TweetFollow Us on Twitter

Managers for Sys 6
Volume Number:4
Issue Number:10
Column Tag:Forth Forum

The Manager

By Jörg Langowski, MacTutor Editorial Staff

Notification Manager, List Manager and UserItems

System updates are almost too frequent to keep track of. It has been only a couple of months since I installed release 6.0; already there are a couple of bug fixes out. I couldn’t get them as of this writing, but System 6.0 has behaved stable so far, examples of ill-behaved applications are only very rare.

The scene keeps moving. As I write this, System 6.0.1 is almost released and 7.0 is being talked about; true to the old wisdom “if one version of the operating system finally behaves, go install a new one”. Anyway, the example I am giving today explores a new service added in System 6.0 under MultiFinder; the notification manager.

This is one of the little things - one might say - added on the way to ‘Real Inter-Process Communication’, and it is responsible for the little printer icon you see flashing with the Apple symbol in the menu bar when your background printer has a problem, or the clock icon when your alarm clock goes off.

Actually, this month’s program deals with many different things, the notification manager being only one of them. I wanted to create some useful utility that can keep track of appointments and remind me if something’s coming up, just like the Reminder DA in one of my recent columns. However, this time I wanted to be able to enter date and time in a well-readable format, and also keep a file with the appointments that is automatically read in on startup and updated on exit. It turned out that doing these things in a nice way required some use of the list manager and a user item in a modeless dialog; so the example will show you some of those things as well.

The Plan

The program consists of a modeless dialog window which displays a list of appointments with their dates and corresponding messages. Selection, updating and scrolling of the list is handled by the list manager. The dialog allows the user to edit a list item, add and delete appointments, and exit the program.

As long as the dialog window is up, a background task (easily created under Mach2) keeps doing the following things:

- Each time the list is changed (by adding/editing/ deleting things), it gets the time and message of the next upcoming appointment from the list.

- When the system time exceeds the time of the upcoming appointment, a Notification Manager (NM) request is set up. The NM then displays an alert message with the appointment message. After the message, the program gets the next appointment from the list.

- When the main dialog window is closed, the background task writes the appointment list back to the file and terminates the program.

Figure 1. Main dialog window of this month’s example

Implementation

First of all, we need to create a modeless dialog window that contains a list. Since that is not a standard dialog item, it has to be implemented as a user item. Just as a reminder: a user item is anything in a dialog that has to be drawn using our own procedure when the dialog is updated. A pointer to the drawing procedure is passed to the dialog manager by calling SetDItem, as described in TN34:

First call:

GetDItem  (DialogPtr, itemNo, type, item, box);

check if necessary whether type is really the type of a userItem, and then call

SetDItem  (DialogPtr, itemNo, type, @drawProc, box);

where @drawProc is a pointer to the user-supplied draw procedure. Note that it is really a pointer that is passed here, not a handle like in the case of other dialog items. DialogPtr, of course, is the pointer to the dialog window, where the item itemNo has been defined as a userItem, and box is the rectangle where the item will be drawn.

We can install a user item procedure from Mach2, but, if we just passed any Mach2 routine’s pointer to the SetDItem trap, the machine would crash gloriously when trying to draw the item, because the procedure is not called from the Mach2 context, but through the dialog manager. This means, glue code has to be written-something you should be used to by now.

In the example, the routine gUser provides this service, setting up space on the stack for the local Forth and DO...LOOP stacks, saving all the registers, and moving the dialog pointer and item numbers on the Forth stack. It then calls the UserDraw procedure and cleans up after it has returned.

List Manager

Our user item will contain a list. How do we handle it? IM Vol.IV describes the List Manager routines, and using those the job becomes pretty easy. I am not going to review the List Manager in detail; IM gives a pretty good description, and we also had an article last year describing the list manager (V3#4).

For the drawing procedure, all we need is a call to LUpdate, which redraws the list. This is implemented in UserDraw (see Listing). However, here we assume the list has already been setup. This is done at the start of the program, calling installUserDraw which calls MakeList. The latter routine (taken from Palo Alto Shipping’s ListManager example) creates a list in a given rectangle and window with vertical and horizontal cell size given in pixels. Looking at the example you will also notice that our list has a vertical scroll bar; the list manager handles scrolling automatically. Note that the list rectangle was inset by one pixel with respect to the user item rectangle, except for the right side where the scroll bar appears, where it had to be inset by 16 pixels (the scroll bar is drawn outside the list). After the list is created, its handle is stored in a variable for further use.

We now need a handler for mouse down events in the user item; and also routines that will allow us to edit, add and delete list items when the appropriate buttons in the modeless dialog are pushed. The words userList-handler, userEdit, userAdd, and userDelete are provided for this purpose.

Mouse down events in the user item are handled by userList-handler. It calls LClick with the local mouse position, the modifiers word of the event record and the list handle. (Note that event-record is a Mach2 system variable which points to the latest event record). LClick handles selection of list elements, highlighting, scrolling, and double clicks. If a list item is double-clicked, the userEdit procedure is called; otherwise, the routine just returns, with the list selection changed.

userEdit and userAdd set up a modal dialog which allow a date and text to be entered into a message field. While userAdd adds a new field at the end of the list, userEdit takes the current selection, puts the date and message into the modal dialog, and lets the user edit it. getMsg is the routine that parses the message string into its date and message fields and displays the edit dialog. update-cell writes the current date/message string into the selected cell. userDelete simply deletes the currently selected cell.

A number of things could be improved here: mainly, I did not implement automatic sorting by date when a list item is added or edited. This is straightforward and would require one or two more pages of code; since it is not really essential for the operation, I’m leaving it as an exercise for you.

The list is initially filled from a file called ‘dates’ which has to be in the same folder as the application. If it doesn’t exists, it will be created. dates contains the date/message strings, separated by carriage returns, and can be edited like any text file. fill-list opens - or creates - the file, reads the strings and adds rows to the list. At the end of the program, write-list writes the list back to the file. This way, by making the program one of your Multifinder startup applications, you will be automatically reminded of any upcoming appointment that was entered into the list.

Modeless Dialog Handling in Mach2

What has to be done to handle modeless dialogs correctly in a multitasking environment like Mach2? Since events are handled for us by the I-O task, we need not - and should not - call WaitNextEvent, IsDialogEvent, or DialogSelect from our program. This has already been done for us. All we need to do to connect a modeless dialog window with one particular task is install the task pointer in the dialog window’s refCon field. The I-O task will look at the front window’s refCon and pass the event information to the owning task. In the case of a dialog event it will put the dialog pointer and the item number into the user variables DialogHandle and DialogData (offsets 140 and 136). When data is stored there, the owning task will run the modeless dialog handling routine whose pointer is stored in the user variable modelessVector (offset 132). This routine gets passed the item number and the dialog pointer. Our program uses the word dialog-handler to call the handlers for the individual dialog items. The pointer to this routine is installed on starting up the task; likewise we install a pointer to a menu handling routine, which allows to handle desk accessories, a simple file menu which can only quit the program, and an Edit menu which allows for editing in desk accessories (in case you ever want to run this program from the finder, which is not very likely). Setting up the menus and menu handlers should be self-explanatory from the listing.

The Main Program

The main program window is hidden behind the menu bar, its coordinates being (1,1,16,16). This is because Mach2 can only assign a menu bar to a terminal task, therefore we need a main window. I have not tried whether - since we also have the dialog window associated with the task - the main window can be simply made invisible by calling HideWindow, so I simply used the ‘tiny-window-behind-menu-bar’ method that one would use in Mach2 for having menus without a window.

The main task loop does two things:

- checks whether an appointment has ‘matured’ and must be displayed using the Notification Manager (check_next_date);

- checks whether the dialog window is still visible. If it is not, the user has closed it and the program should write the list back to the file and exit (check_dialog_up).

A flag, nmChanged, is kept to indicate whether check_next_date should search the list for the next appointment due or simply compare the time of the last appointment read with the system time. The flag is set by the list editing routines, and by check_next_date itself when it has displayed an appointment. It is reset by the routine that gets the next appointment from the list. check_next_date calls say_it when the system time has exceeded the time of the appointment. say_it (finally!) calls the Notification Manager.

Notifying the User

The actual notification routine, as it turns out, is the smallest part of the program and of my column. say_it first checks the flag, nmPresent, which has been set at startup time to indicate whether the NM traps are present. If not, we’re running under an older system version, and say_it simply beeps. Otherwise, it calls notify-request, our glue routine to the NMInstall trap. The NM traps are explained in TN184, and I’ll repeat some of the information here.

notify-request takes the following parameters from the stack:

mark, contains 1 if the application should be marked in the Apple menu, 0 if not, or the reference number of a desk accessory to mark that desk accessory.

SIcon, contains a handle (non-purgeable) to a SICN resource if a small icon should flash with the Apple icon in the menu bar, 0 otherwise.

sound, contains a handle to a sound record to be played with SndPlay if a special sound is to be played on the notification; 0 if no sound should be made and -1 for the system beep.

str, a pointer to a string to appear in the NM alert box, or 0 if no alert.

resp, a pointer to a response procedure. This is explained in more detail in TN184; we simply use -1 to indicate the standard system response procedure which simply removes the NM request from the queue. If 0 is passed, no response procedure is called, and the program itself would be responsible for removing the NM request using NMRemove.

refCon, a constant available for general use, TN184 suggest to store A5 of the calling program here to allow access to the application globals.

myNMRec will contain the NM record in the format given in TN184, and NMInstall is called passing its address in A0.

That’s it; the alert will come up when an appointment is due if you let the ‘appts’ application (provided on the source code disk) turn in the background. Try to experiment with the other NM options, the small icons and sounds.

One last remark: in some cases it might happen that not the actual appointment is displayed in the alert box, but the next one on the list. This happens when it takes the NM longer than one second to get the resources and display the alert. In that case, the background task will already have continued and put the next message string in the msgTxt global variable! This can be remedied by increasing the wait period (presently, 60 ticks) after calling say_it in check_next_date.

The necessary resources which have to be added to the MACH.RSRC file for running the program are given in Listing 2, in Rez format. Don’t forget to add a SIZE -1 resource as well, with the canBackground bit set, and a size of approx. 120K. Good luck.

Mach 2.14 (beta)

The latest news is a beta version 2.14 of Mach2, which I received recently; as you read this, 2.14 might be released, and I’ll give you a list of the main changes in one of the next columns. Here just a very brief summary:

- compiler optimization has been improved.

- local variable handling has been greatly improved, with the possibility to reserve blocks of local variable space (i.e. for parameter blocks), and customizing the local variable compiler.

- some words have been added, among them SHIFT which takes the function of SCALE that I previously defined.

- more trap words have been added to the system. The NM traps, which I defined here, are included.

- the disassembler has been enhanced, with listing of references to USER and global variables.

That’s it; till next month.

{1}
Listing 1: Notification Manager example
\ notification manager example System Ver 6.0 needed
\ JL 15.8.88

only forth definitions
also assembler also mac also i/o
decimal 

\ structure of a NM record

0CONSTANT qLink  \ pointer
4CONSTANT qType  \ integer
6CONSTANT nmFlags\ integer
8CONSTANT nmPrivate\ longint
12 CONSTANT nmReserved  \ integer
14 CONSTANT nmMark \ integer
16 CONSTANT nmSIcon\ handle
20 CONSTANT nmSound\ handle
24 CONSTANT nmStr\ StringPtr
28 CONSTANT nmResp \ ProcPtr
32 CONSTANT nmRefCon \ longint

8CONSTANT nmType
 
.TRAP _NMInstall $A05E
.TRAP _NMRemove  $A05F

CODE  NMInstall  ( NMRec -- result )
 MOVE.L (A6)+,A0
 _NMInstall
 MOVE.L D0,-(A6)
 RTS
END-CODE MACH

CODE  NMRemove ( NMRec -- result )
 MOVE.L (A6)+,A0
 _NMRemove
 MOVE.L D0,-(A6)
 RTS
END-CODE MACH

$5E CONSTANT nmTrap#
$9F CONSTANT unkTrap#

variable myNMRec 32 vallot
variable nmPresent 
 \ for checking whether the NM is implemented
variable nmChanged 
 \ flag for telling supervisor task
 \ that something has changed
variable nmSecs  
 \ time in seconds for next notify alert

: notify-request
 { mark SIcon sound str resp refCon | -- 
 nmPtr result }

 nmType mynmRec qType + w!
 mark   mynmRec nmMark + w!
 SIcon  mynmRec nmSIcon + !
 sound  mynmRec nmSound + !
 str    mynmRec nmStr + !
 resp   mynmRec nmResp + !
 refCon mynmRec nmRefCon + !

 mynmRec dup NMInstall
;

300 CONSTANT AppleID
301 CONSTANT FileID
302 CONSTANT EditID

2000 CONSTANT updID
2001 CONSTANT msgID

110 CONSTANT wVisible \ offset into window record

132 USER modelessVector
 60 USER fID

CREATE APPLESTRING  $01 C,  $14 C, 

NEW.WINDOW nmWindow

“ NM” nmWindow TITLE
1 1 16 16 nmWindow BOUNDS
Plain Visible NoCloseBox NoGrowBox nmWindow ITEMS

600 4000 TERMINAL nmTask

NEW.MBAR nmBar 

NEW.MENU AppleMenu
APPLESTRING AppleMenu TITLE
0 APPLEID AppleMenu BOUNDS
“ About Appointments ...;(-” AppleMenu ITEMS

NEW.MENU FileMenu
“ File” FileMenu TITLE
0 FileID FileMenu BOUNDS
“ Close;Quit”  FileMenu ITEMS

NEW.MENU EditMenu
“ Edit” EditMenu TITLE
0 EditID EditMenu BOUNDS
“ (Undo/Z;(-;Cut/K;Copy/C;Paste/V;Clear” EditMenu ITEMS

VARIABLE DAName 60 VALLOT
VARIABLE updStore 160 VALLOT 
 \ for ‘update appointments’ dialog
VARIABLE updPtr
VARIABLE msgPtr  \ for storing the dialog pointers
VARIABLE updRect 4 vallot
VARIABLE hUpdList\ stores list handle
VARIABLE listRows\ total # of rows in list 
VARIABLE datim 10 VALLOT 
 \ 14 bytes for date-time record
VARIABLE msgTxt 252 VALLOT 
 \ 256 bytes for item text

\ ***** list manager support

\ List Manager select flags.
128CONSTANT OnlyOne
 64CONSTANT ExtendDrag
 32CONSTANT NoDisjoint
 16CONSTANT NoExtend
  8CONSTANT NoRect
  4CONSTANT UseSense
  2CONSTANT NoNilHilite
  
\ Offsets into the List record
 12CONSTANT IndentOffset
 36CONSTANT SelFlags
 80CONSTANT LDataHandle

CREATE ArrayDim  \ Initially we will have an empty array.
 \ We’ll add rows and columns later.
 0 W,   \ Row-o.
 0 W,   \ Column-o.
 0 W,   \ Row-i.
 1 W,   \ Column-i.

: NewVList ( rview databounds size wPtr - lhandle )
 0 \ LDEF proc id
 swap \ window pointer
 0 \ DrawIt flag
 0 \ HasGrow flag
 0 \ scrollHoriz flag
 -1\ scrollVert flag
 (CALL) LNew
;

: MakeList { rect vcell hcell wPtr | 
 lhandle cellpt rectbr recttl -- lhandle }
 rect  @ $10001 + -> recttl
 rect 4 + @ $10010 - -> rectbr
 ^ recttl \ Pass rectangle.
 ArrayDim \ Pass bounds.
 vCell ^ cellpt W!
 hCell ^ cellpt 2+ W!
 cellpt \ Pass cell size.
 wPtr
 NewVList -> lhandle
 
 OnlyOne NoNilHilite +    
 \ Select only one cell at a time.
 lhandle @ SelFlags + C!  
 \ Don’t hilite empty cells.
 lhandle
;

: read1line { ^pfile string | pStr char -- flag }
 string -> pStr
 BEGIN
 ^pfile @ virtual c@ -> char
 1 ^pfile +!
 char 0= char 13 = OR 0= WHILE
 1 +> pStr 
 char pStr c!
 REPEAT
 pStr string - string c!
 char
;
 
: open-dates-file
 “ Dates” $open dup 0< 
 IF drop “ Dates” dup 
 $create drop 
 $open 
 THEN
 fID w!
;

: fill-list { | pfile theCell -- }
 0 listRows !
 open-dates-file
 0 -> pfile
 BEGIN
 ^ pfile msgTxt read1line WHILE
 1 listRows @ hupdList @ call LAddRow drop
 0 -> theCell
 listRows @ ^ theCell w!
 1 listRows +!
 msgtxt count theCell hupdList @ call LSetCell
 REPEAT
 fID w@ closefile
 -1 hUpdList @ call LDoDraw 
 hupdList @ call LAutoScroll
;

: write-list { | len theCell offset -- }
 open-dates-file
 0 -> offset
 listRows @ 0 DO
 0 -> theCell  i ^ theCell w!
 0 -> len  255 ^ len w!
 msgTxt ^ len theCell hUpdList @
 call LGetCell
 ^ len w@ -> len
 13 msgTxt len + c!
 1 +> len
 offset len msgTxt fID w@ write
 len +> offset
 LOOP
 0 msgtxt c!
 offset 1 msgTxt fID w@ write
 offset 1+ fID w@ setEOF
 fID w@ closefile
;

\ UserDraw procedure
\ must use (call) instead of call and use glue code
\ for saving registers and setting up Forth stack

: UserDraw { theDlg theItem | iType iHdl rectbr recttl -- }
 
 theDlg theItem ^ iType ^ iHdl ^ recttl
 (call) GetDItem
 ^ recttl (call) FrameRect
 theDlg 24 + @   \ visRgn of dialog window
 hUpdList @ \ list handle
 (call) LUpdate
;

\ UserDraw procedure glue code
\ sets up local stack etc.

CODE gUser
 LINK A6,#-512   ( 512 bytes of local Forth stack )
 MOVEM.L A0-A5/D0-D7,-(A7)( save registers )
 MOVE.L A6,A3    ( setup local loop return stack )
 SUBA.L #256,A3  ( in the low 256 local stack bytes )
 CLR.L  D1
 MOVE.W 8(A6),D1 ( theItem )
 MOVE.L 10(A6),D0( theDialog )
 MOVE.L D0,-(A6)
 MOVE.L D1,-(A6)

 UserDraw

 MOVEM.L (A7)+,A0-A5/D0-D7( restore registers )
 UNLK A6
 MOVE.L (A7)+,A0 ( return address )
 ADD.W  #6,A7    ( pop off 6 bytes of parameters )
 JMP    (A0)
 RTS
END-CODE MACH

: update-cell { string | theCell -- }
 0 -> theCell
 -1 ^ theCell hupdList @ call LGetSelect
 IF
 string count theCell hupdList @ 
 call LSetCell
 THEN
;

: getText { dlgPtr item# string | iType iHdl iBox -- string }
 dlgPtr item# ^ iType ^ iHdl ^ iBox
 call GetDItem
 iHdl string call GetIText
 string
;
 
: setText { dlgPtr item# string | iType iHdl iBox -- }
 dlgPtr item# ^ iType ^ iHdl ^ iBox
 call GetDItem
 iHdl string call SetIText
;

: setup-msg { editDlg string | -- string }
 editDlg  8 string getText ( year )
 editDlg  9 string 3 + getText ( month )
 editDlg 10 string 6 + getText ( day )
 editDlg 11 string 9 + getText ( hour )
 editDlg 12 string 12 + getText ( min )
 editDlg 13 string 15 + getText ( sec )

 editDlg 3 string 18 + getText ( message )
 c@ 18 + string c!

 ascii / dup string 3 + c! string 6 + c!
 32 string 9 + c! 32 string 18 + c!
 ascii : dup string 12 + c! string 15 + c!
 string
;

: parse-msg { string | sPtr -- }
 string c@ 18 - string 18 + c!
 6 0 do 
 string i 3 * + -> sPtr
 2 sPtr c!
 sPtr call stringtonum
 datim i 2* + w!  
 loop
 datim w@ 1900 + datim w!
;

: set-dlg { editDlg string | -- }
 editDlg  8 string setText ( year )
 editDlg  9 string 3 + setText ( month )
 editDlg 10 string 6 + setText ( day )
 editDlg 11 string 9 + setText ( hour )
 editDlg 12 string 12 + setText ( min )
 editDlg 13 string 15 + setText ( sec )
 editDlg 3 string 18 + setText ( message )   
;

: getMsg { text | editDlg itemHit iTyp iHdl iBox
 -- string_or_zero }
 msgID 0 -1 call GetNewDialog -> editDlg
 text parse-msg
 editDlg text set-dlg
 0 ^ itemHit call ModalDialog
 ^ itemHit w@ CASE
 1 OF editDlg msgTxt setup-msgENDOF
 2 OF ( Cancel ) 0 ENDOF
 ENDCASE
 editDlg call DisposDialog
;

: userEdit { | theCell len -- }
 0 -> theCell
 -1 ^ theCell hupdList @ call LGetSelect
 IF
 255 ^ len w!
 msgTxt 1+ ^ len theCell hupdList @ call LGetCell
 ^ len w@ msgtxt c!
 msgtxt getMsg ?dup IF
 update-cell 
 THEN
 THEN
 nmChanged on
;

: userAdd  { | theCell -- }
 “ yy/mm/dd hh:mm:ss Your message - “ 
 dup c@ 1+ msgtxt swap cmove
 msgtxt getMsg IF 
 0 -> theCell
 -1 ^ theCell hupdList @ call LGetSelect
 IF 0 theCell hUpdList @ call LSetSelect THEN            
 1 listRows @ hupdList @ call LAddRow
 0 -> theCell
 listRows @ ^ theCell w!
 1 listRows +!
 msgtxt count theCell hupdList @ call LSetCell
 -1 theCell hUpdList @ call LSetSelect
 hupdList @ call LAutoScroll
 THEN
 nmChanged on
;

: userDelete { | theCell -- }
 0 -> theCell
 -1 ^ theCell hupdList @ call LGetSelect
 IF
 1 ^ theCell w@ hupdList @ call LDelRow
 -1 listRows +!
 THEN
 nmChanged on
;

: userList-handler { | thePt thePort -- }
 ^ thePort call getPort
 call frontwindow call setport 
 ^ thePt call getMouse    
 thePt event-record modifiers + w@ 
 hUpdList @
 call LClick
 IF ( double click ) userEdit THEN
 thePort call setPort
;

: CloseMe
 updPtr @ call CloseDialog
;

: QuitMe CloseMe ;

: dialog-handler 
 { itemHit dlgPtr | -- }

 itemHit CASE 
 1 OF CloseMe  ENDOF
 2 OF userEdit   ENDOF
 3 OF userAdd  ENDOF
 4 OF userDelete ENDOF

 5 OF userList-handler  ENDOF
 ENDCASE
;

: installupdPtr
 updPtr @ ?dup IF
 nmTask @ 2+ call SetWRefCon
 ELSE
 cr .” Couldn’t create dialog”
 ABORT
 THEN
;

: installuserDraw { pUser | iType iHdl rectbr recttl -- }
 updPtr @ 5 ^ iType ^ iHdl ^ recttl
 call GetDItem 
 updPtr @ 5 ^ iType w@  pUser ^ recttl
 call SetDItem 
 ^ recttl 16 280 updPtr @ MakeList 
 hUpdList !
;

: UndoMe ;
: CutMe ;
: CopyMe ;
: PasteMe ;
: ClearMe ;

: do-about
 128 0 CALL Alert DROP
;

: do-apple   { item# }
 \ item# = 1 (About...)?
 item# 1 =  
 IFdo-about
 ELSE
 Applemenu @ item# DAName CALL GetItem
 DAName CALL OpenDeskAcc DROP
 THEN ;

: DO-FILE ( item# -  )  
 ( handles selections from the file menu )
 CASE
 1 OF   CloseMe  ENDOF
 2 OF    QuitMe  ENDOF
 ENDCASE  
;

: DO-EDIT ( item# - )
 ( handles selections from the edit menu )
 dup 1- call SysEdit ( item# flag )
 0= IF
 CASE
 1 OF UndoMeENDOF
 3 OF CutMe ENDOF
 4 OF CopyMeENDOF
 5 OF PasteMe    ENDOF
 6 OF ClearMe    ENDOF
 ENDCASE  
 THEN
;
 
: nmBAR-handler  ( item# menuID -  ) 
 CASE   
 APPLEID OF DO-APPLE    ENDOF
 FILEID  OF DO-FILE  ENDOF
 EDITID OF DO-EDIT ENDOF
 ENDCASE  
 0 CALL HILITEMENU  
;

\ setup notify request with text in (msgTxt + 18)

: say_it 
 nmPresent @ IF
 1 ( mark )
 0 ( no Icon )
 -1 ( system beep )
 msgTxt 18 + ( string to display )
 -1 ( remove request )
 0 ( no refCon )
 notify-request
 2drop
 ELSE 
 5 call sysbeep 
 THEN
;

: get_time { | time -- secs }
 ^ time call readdatetime drop @
;

: get_next_date { | len theCell secs -- }
 listRows @ 0 DO
 0 -> theCell i ^ theCell w!
 255 ^ len w!
 msgTxt 1+ ^ len theCell hupdList @ call LGetCell
 ^ len w@ msgtxt c!
 msgtxt parse-msg
 datim call date2secs -> secs
 get_time secs u< IF leave THEN
 -1 -> secs \ in case no date matches
 LOOP
 secs nmSecs !
 nmChanged off
;

: wait { ticks | time -- }
 call tickcount ticks + -> time
 begin
 pause
 call tickcount time > 
 until
;

: check_next_date 
 nmChanged @ IF get_next_date THEN
 nmSecs @ get_time
 u< IF 
 say_it
 60 wait 
 nmChanged on 
 THEN 
;

: check_dialog_up
 updPtr @ wVisible + c@
 0= IF write-list bye
 THEN
;

: go.nm 
 ACTIVATE
 fill-list
 [‘] dialog-handler modelessVector !
 [‘] nmBar-handler menu-vector !
 nmWindow dup call showWindow
 call selectWindow
 updPtr @ dup call showWindow
 call selectWindow
 call DrawMenuBar
 begin  
 PAUSE 
 check_next_date
 check_dialog_up
 again
;

: nmPresent?
 NMTrap# CALL GetTrapAddress
 UnkTrap# CALL GetTrapAddress
 = IF 0 ELSE 1 THEN
 nmPresent !
;

: start 
 nmPresent?
 nmWindow ADD
 nmWindow nmTask BUILD

 nmBar ADD
 nmBar AppleMenu ADD
 AppleMenu @ ascii DRVR CALL AddResMenu
 nmBar FileMenu ADD
 nmBar EditMenu ADD
 nmBar nmTask mbar>task

 updID updStore -1 call GetNewDialog
 updPtr !

 installupdPtr
 [‘] gUser installUserDraw

 nmChanged on
 nmTask go.nm 
;
{2}
Listing 2: Resources for example (MPW Rez format)
resource ‘DITL’ (2000, “date list”) {
 { /* array DITLarray: 5 elements */
 /* [1] */
 {272, 328, 296, 392},
 Button {
 enabled,
 “Exit”
 },
 /* [2] */
 {168, 328, 192, 392},
 Button {
 enabled,
 “Edit”
 },
 /* [3] */
 {200, 328, 224, 392},
 Button {
 enabled,
 “Add...”
 },
 /* [4] */
 {232, 328, 256, 392},
 Button {
 enabled,
 “Delete”
 },
 /* [5] */
 {8, 8, 312, 312},
 UserItem {
 enabled
 }
 }
};

resource ‘DITL’ (2001, “appt text”) {
 { /* array DITLarray: 15 elements */
 /* [1] */
 {160, 256, 184, 320},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {160, 336, 184, 408},
 Button {
 enabled,
 “Cancel”
 },
 /* [3] */
 {49, 10, 145, 410},
 EditText {
 disabled,
 “”
 },
 /* [4] */
 {15, 275, 33, 295},
 StaticText {
 disabled,
 “:”
 },
 /* [5] */
 {15, 235, 33, 255},
 StaticText {
 disabled,
 “:”
 },
 /* [6] */
 {15, 129, 33, 149},
 StaticText {
 disabled,
 “/”
 },
 /* [7] */
 {15, 89, 33, 109},
 StaticText {
 disabled,
 “/”
 },
 /* [8] */
 {16, 58, 32, 86},
 EditText {
 disabled,
 “”
 },
 /* [9] */
 {16, 101, 32, 127},
 EditText {
 disabled,
 “”
 },
 /* [10] */
 {16, 140, 32, 167},
 EditText {
 disabled,
 “”
 },
 /* [11] */
 {16, 205, 32, 231},
 EditText {
 disabled,
 “”
 },
 /* [12] */
 {16, 244, 32, 271},
 EditText {
 disabled,
 “”
 },
 /* [13] */
 {16, 284, 32, 312},
 EditText {
 disabled,
 “”
 },
 /* [14] */
 {16, 8, 32, 50},
 StaticText {
 disabled,
 “Date:”
 },
 /* [15] */
 {16, 176, 32, 196},
 StaticText {
 disabled,
 “at”
 }
 }
};

resource ‘DITL’ (128, “About Appts”) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {159, 82, 188, 151},
 Button {
 enabled,
 “Okay <0>”
 },
 /* [2] */
 {35, 28, 128, 192},
 StaticText {
 disabled,
 “Appointment reminder - \nNotification Man”
 “ager example\n© 1988 J. Langowski / MacTu”
 “tor”
 }
 }
};

resource ‘DLOG’ (2000, “date list”) {
 {54, 38, 380, 446},
 noGrowDocProc,
 invisible,
 goAway,
 0x0,
 2000,
 “Appointments”
};

resource ‘DLOG’ (2001, “appt text”) {
 {48, 16, 248, 440},
 dBoxProc,
 visible,
 noGoAway,
 0x0,
 2001,
 “Edit Appointment”
};

resource ‘ALRT’ (128, “About Appts”) {
 {40, 40, 240, 280},
 128,
 { /* array: 4 elements */
 /* [1] */
 Cancel, visible, silent,
 /* [2] */
 Cancel, visible, silent,
 /* [3] */
 Cancel, visible, silent,
 /* [4] */
 Cancel, visible, silent
 }
};
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Capto 1.2.9 - $29.99
Capto (was Voila) is an easy-to-use app that takes capturing, recording, video and image editing to the next level. With an intelligent file manager and quick sharing options, Capto is perfect for... Read more
Opera 51.0.2830.40 - High-performance We...
Opera is a fast and secure browser trusted by millions of users. With the intuitive interface, Speed Dial and visual bookmarks for organizing favorite sites, news feature with fresh, relevant content... Read more
GarageSale 7.0.13 - Create outstanding e...
GarageSale is a slick, full-featured client application for the eBay online auction system. Create and manage your auctions with ease. With GarageSale, you can create, edit, track, and manage... Read more
1Password 6.8.7 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
Evernote 7.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
MacUpdate Desktop 6.2.0 - $20.00
MacUpdate Desktop brings seamless 1-click app installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on... Read more
HoudahSpot 4.3.5 - Advanced file-search...
HoudahSpot is a versatile desktop search tool. Use HoudahSpot to locate hard-to-find files and keep frequently used files within reach. HoudahSpot will immediately feel familiar. It works just the... Read more
EtreCheck 4.0.4 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
WhatsApp 0.2.8361 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
iClock 4.2 - Customize your menubar cloc...
iClock is a menu-bar replacement for Apple's default clock but with 100x features. Have your Apple or Google calendar in the menubar. Have the day, date, and time in different fonts and colors in the... Read more

Latest Forum Discussions

See All

Alto's Odyssey Guide - How to Tackl...
Alto’s Odyssey is a completely stunning and serene runner, but it can also be a bit tricky. Check out these to try and keep your cool while playing this endless runner: Don’t focus too much on tasks [Read more] | Read more »
Here's everything you need to know...
Alto's Odyssey is a really, really good game. If you don't believe me, you should definitely check out our review by clicking this link right here. It takes the ideas from the original Alto's Adventure, then subtly builds on them, creating... | Read more »
Alto's Odyssey (Games)
Alto's Odyssey 1.0.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.1 (iTunes) Description: Just beyond the horizon sits a majestic desert, vast and unexplored. Join Alto and his friends and set off on an endless... | Read more »
Vainglory 5v5: Everything you need to kn...
Vainglory just got bigger. [Read more] | Read more »
Check out these 5 games that are a lot l...
So you're in love with Minecraft, but you're looking for something else to play as well? You've come to the right place then, because this list is all about games that are a bit like Minecraft. Some of them, more than others. [Read more] | Read more »
Our top 5 characters from casual RPG Cre...
Creature Quest definitely lives up to its name with a host of collectible creatures based on fantasy tales and world mythologies. To celebrate Creature Quest’s first birthday, we’re going to lay out what we think are the five best characters in the... | Read more »
Around the Empire: What have you missed...
Did you know that Steel Media has a whole swathe of other sites dedicated to all aspects of mobile gaming? Sure you'll get the very best iPhone news, reviews, and opinions right here at 148Apps, but we don't want you missing out on a single piece... | Read more »
All the best games on sale for iPhone an...
Oh hi there, and welcome to our round-up of the best games that are currently on sale for iPhone and iPad. You thought I didn't see you there, did you, skulking behind the bushes? Trust me though, the bushes aren't where the best deals are. The... | Read more »
The Battle of Polytopia Guide - How to H...
A new update just released for The Battle of Polytopia (formerly Super Tribes), which introduces online multiplayer. For all the fans of Midjiwan’s lite take on Civilization, this is certainly welcome news, but playing online isn’t as easy and... | Read more »
The best games that came out for iPhone...
Another week, another bunch of new releases on the App Store, another update to our big list of new games. It's not a classic lineup this week, but there are some really good ones in the mix all the same. [Read more] | Read more »

Price Scanner via MacPrices.net

Amazon restocks MacBook Pros with models avai...
Amazon has restocked 15″ and 13″ Apple MacBook Pros with models on sale for up to $251 off MSRP. Shipping is free. Note that stock of some Macs may come and go (and some sell out quickly), so check... Read more
Lowest price of the year: 15″ 2.8GHz Apple Ma...
Amazon has the 2017 Space Gray 15″ 2.8GHz MacBook Pro on sale today for $251 off MSRP. Shipping is free: – 15″ 2.8GHz Touch Bar MacBook Pro Space Gray (MPTR2LL/A): $2148, $251 off MSRP Their price is... Read more
Apple restocks full line of Certified Refurbi...
Apple has restocked a full line of Apple Certified Refurbished 2017 13″ MacBook Pros for $200-$300 off MSRP. A standard Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
Lowest sale price available for 13″ 1.8GHz Ma...
Focus Camera has the 2017 13″ 1.8GHz/128GB Apple MacBook Air on sale today for $829 including free shipping. Their price is $170 off MSRP, and it’s the lowest price available for a current 13″... Read more
21-inch 2.3GHz iMac on sale for $999, $100 of...
B&H Photo has the 2017 21″ 2.3GHz iMac (MMQA2LL/A) in stock and on sale for $999 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. Read more
Apple refurbished Mac minis in stock again st...
Apple has restocked Certified Refurbished Mac minis starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: – 1.4GHz Mac mini: $419 $80 off MSRP – 2.6GHz Mac... Read more
Tuesday MacBook Deals: $250 off 15″ 2.9GHz Ma...
Adorama has the Silver 15″ 2.9GHz Apple MacBook Pro on sale today for $250 off MSRP. Shipping is free, and Adorama charges sales tax for residents in NY & NJ only: – 15″ 2.9GHz Silver MacBook Pro... Read more
Save up to $350 with these Apple Certified Re...
Apple has a full line of Certified Refurbished iMacs available for up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: – 27... Read more
B&H offers $200 discount on Silver 15″ Ma...
B&H Photo has Silver 15″ Apple MacBook Pros on sale for $200 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 15″ 2.8GHz Touch Bar MacBook Pro Silver (... Read more
12″ Apple iPad Pro Sale of the Year! Models u...
B&H Photo has 12″ #iPad Pros on sale for up to $150 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 12″ 64GB WiFi iPad Pro: $719 $80 off MSRP – 12″ 256GB WiFi... Read more

Jobs Board

*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
Sr. Experience Designer, Today at *Apple* -...
# Sr. Experience Designer, Today at Apple Job Number: 56495251 Santa Clara Valley, California, United States Posted: 18-Jan-2018 Weekly Hours: 40.00 **Job Summary** Read more
*Apple* Technical Specialist - Apple, Inc. (...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of 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
Strategist, *Apple* Media Products, Content...
# Strategist, Apple Media Products, Content and Marketing Job Number: 113399632 Santa Clara Valley, California, United States Posted: 20-Feb-2018 Weekly Hours: 40.00 Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.