exodus@uop.UUCP (Freddy Kreuger) (10/10/87)
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 2 (of 2)."
# Contents: gem11.asc
# Wrapped by exodus@uop on Thu Oct 8 16:49:38 1987
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f gem11.asc -a "${1}" != "-c" ; then
echo shar: Will not over-write existing file \"gem11.asc\"
else
echo shar: Extracting \"gem11.asc\" \(20829 characters\)
sed "s/^X//" >gem11.asc <<'END_OF_gem11.asc'
X *PROFESSIONAL GEM*
X by Tim Oren
X Column #11 - GEM Hooks and Hacks
X An Insider's AES Tricks
X
X Welcome to the eleventh episode of ST PRO GEM, which is
Xdevoted to exploring some of the little documented, but powerful,
Xfeatures of GEM. Like the authors of most complex systems, the
XGEM programmers left behind a set of "hooks", powerful features
Xwhich would aid them in enhancing the system later. I am going to
Xlay out a number of these methods which have served me well in
Xmaking creative use of the AES. You will find that most of them
Xconcern the object and form libraries, since I was most involved
Xin those parts of GEM. There are probably many more useful tricks
Xwaiting to be found in other parts of GEM, so if you happen onto
Xone, please let me know in the Feedback! Before you begin,be sure
Xto pick up the download for this column: GMCL11.C in DL3 of PCS-
X57.
X
X POWERFUL OBJECTS
X
X The first four tricks all involve augmenting standard AES
Xobjects. This is a powerful technique for two reasons. First,
Xyou can take advantage of the regular AES object and form
Xlibraries to draw and handle most of your objects, so that your
Xprogram need only process the exceptions. Second, you can use the
XRCS to copy the special objects into multiple dialogs or
Xresources. These four tricks are Extended Object Types, User-
Xdefined Objects, TOUCHEXIT, and INDIRECT. Let's look at each of
Xthem in turn.
X
X EXTENDED OBJECT TYPES
X
X If you look at the AES Object Library documentation, you will
Xnotice that the values for the OB_TYPE field in an object are all
X32 or less. This means that a number of bits are unused in this
Xfield. In fact, the AES completely ignores the top byte of the
XOB_TYPE field. In addition, the RCS ignores the top byte, but it
Xalso preserves its value when an object is read, written, or
Xcopied.
X
X This gives you one byte per object to use as you see fit.
XSince the processing of an object or dialog is (so far) in the
Xhands of the AES, the best uses of Extended Types are in flagging
Xmethods for initializing an object or handling its value when the
Xdialog completes.
X
X For example, you might have several dialogs containing
Xeditable numeric fields. The Extended Type of each numeric field
Xcould be set to the index of the corresponding value in an array.
XThen your application's dialog initialization code could scan the
Xobject tree for such objects, pick up the appropriate value
Xfrom the array and convert it to ASCII, storing the result in the
Xresource's string area. When the dialog was finished, another
Xpass could be made to reconvert the ASCII to binary and store away
Xthe results in the array. (Note that the map_tree() utility from
Xcolumn #5 will scan an entire resource tree.)
X
X Another application is to assign uniform codes to exit
Xbuttons in dialogs. If you give every "OK" button an Extended
XType of one, and every "Cancel" button an Extended Type of two,
Xthen you needn't worry about naming every exit object. Just
Xexamine the Extended Type of the object returned by form_do, and
Xproceed accordingly.
X
X The catch, of course, is that you have to find a way to enter
Xthe Extended Type code in the first place. Version 1.0 of the
XRCS, as shipped with the Atari developer's kit, makes no provision
Xfor this. So you have your choice of two methods for creating the
Xfirst object with each Extended Type code.
X
X First, you can dump out a C source of a resource, insert the
Xnew type code by hand, and regenerate the resource with STCREATE.
XAlternately, you could carefully modify the binary resource using
XSID. You will probably want to reread the AES object manual, ST
XPRO GEM #4 and #5, and use the C source as a guide when doing so.
XIn both cases, you should make things easy on yourself by creating
Xa one dialog resource with only a single object other than the
Xroot. Version 2.0 of the RCS will let you directly enter an
XExtended Type, but it has not yet been released for the ST by DRI.
X
X Once you have created a prototype extended object by either
Xmethod, you can use the RCS to propogate it. The safest way is to
Xuse the MERGE option to add the modified tree to the resource you
Xare building. Then copy the prototype object via the clipboard to
Xyour dialog(s), deleting the extra tree when you are done. If you
Xare using several different extended objects, you can use MERGE
Xand clipboard copies to get them all into one tree which will then
Xbecome your own object library.
X
X The second way of using RCS is easier, but more dangerous.
XIf you want to try the following technique, BACK UP YOUR RCS DISK
XFIRST! Put simply, the RCS does not care what is in its dialog
Xpartbox. It will make copies of anything that it finds there! This
Xgives you the option of using the RCS on ITS OWN RESOURCE in order
Xto add your customized objects to the partbox.
X
X To do this, open RCS.RSC from the RCS. Since there is no DEF
Xfile, you will get a collection of question mark icons. Use the
XNAME option to make TREE5 into a DIALOG. Open it, and you will
Xsee the dialog partbox.
X
X Now you can use the MERGE technique described above to insert
Xyour customized objects. Then SAVE the modified resource, and
Xrerun the RCS. Your new objects should now appear in the partbox.
XIf you added several, you may have to stretch the partbox to see
Xthem all. You can now make copies of the new objects just like
Xany other part. (Note: DO NOT modify the alert or menu partboxes,
Xyou will probably crash the RCS.)
X
X USER-DEFINED OBJECTS
X
X The one type of object which was not discussed in the earlier
Xarticles on AES objects was G_USERDEF, the programmer defined
Xobject. This is the hook for creating objects with other
Xappearances beyond those provided by the standard AES. By the
Xway, you should note that the G_PROGDEF and APPLBLK mnemonics used
Xin the AES documents are incorrect; the actual names as used
Xdefined OBDEFS.H are G_USERDEF and USERBLK.
X
X The RCS does not support the creation of G_USERDEF objects,
Xsince it has no idea how they will be drawn by your program.
XInstead, you must insert a dummy object into your resource where
Xyou want the G_USERDEF to appear, and patch it after your
Xapplication performs its resource load.
X
X You must replace the object's existing OB_TYPE with
XG_USERDEF, though you may still use the upper byte as an Extended
XType. You must also change the OB_SPEC field to be a 32-bit
Xpointer to a USERBLK structure. An USERBLK is simply two LONG
X(32-bit) fields. The first is the address of the drawing code
Xassociated with the user defined object. The second is an
Xarbitrary 32-bit value assigned to the object by your application.
X
X You can designate objects for conversion to G_USERDEFs in the
Xnormal fashion by assigning them names which are referenced one by
Xone in your initialization code. You can also combine two tricks
Xby using the Extended Type field as a designator for objects to be
Xconverted to G_USERDEF. Each tree can then be scanned for objects
Xto be converted. There is a short code segment in the download
Xwhich demonstrates this technique.
X
X My usual convention is to define new drawing objects as
Xvariants of existing objects, using the Extended Type field to
Xdesignate the particular variation. Thus an Extended Type of one
Xmight designate a G_BUTTON with rounded corners, while a value of
Xtwo could flag a G_STRING of boldface text. When using this
Xtechnique, the RCS can be used to build a rough facsimile of the
Xdialog by inserting the basic object type as placeholders. The
Xexisting OB_SPEC information can then be copied to the second
Xposition in the USERBLK when the object is initialized.
X
X One final note before moving on: There is no reason that the
XUSERBLK cannot be extended beyond two fields. You might want to
Xadd extra words to store more information related to drawing the
Xobject, such as its original type.
X
X The AES will call your drawing code whenever the G_USERDEF
Xneeds to be drawn. This occurs when you make an objc_draw call
Xfor its tree, or when an objc_change occurs for that object. If
Xyour user-defined object is in a menu drop-drop, then your drawing
Xcode will be called any time the user exposes that menu.
X
X Before getting into the details of the AES to application
Xcalling sequence, some warnings are in order. First, remember
Xthat your drawing code will execute in the AES' context, using its
Xstack. Therefore, be careful not to overuse the stack with deep
Xrecursion, long parameter lists, or large dynamic arrays. Second,
Xthe AES is NOT re-entrant, so you may not make ANY calls to it
Xfrom within a G_USERDEF procedure. You may, of course, call the
XVDI. Finally, realize that drawing code associated with a menu
Xobject may be called by the AES at any time. Exercise great care
Xin sharing data space between such code and the rest of the
Xapplication!
X
X When your drawing code is called by the AES, the stack is set
Xup as if a normal procedure call had occured. There will be one
Xparameter on the stack: a 32-bit pointer to a PARMBLK structure.
XThis structure lies in the AES' data space, so do not write beyond
Xits end!
X
X The PARMBLK contains 15 words. The first two are the long
Xaddress of the object tree being drawn, and the third word is the
Xnumber of the G_USERDEF object. You may need these values if the
Xsame drawing code is used for more than one object at a time.
XWords four and five contain the previous and current OB_STATE
Xvalues of the object. If these values are different, your drawing
Xcode is being called in response to an objc_change request.
XOtherwise, the active AES call is an objc_draw.
X
X Words six through nine contain the object's rectangle on the
Xscreen. Remember that you cannot call objc_offset within the
Xdrawing code, so you will need these values! The next four words
Xcontain the clipping rectangle specified in the active objc_change
Xor objc_draw call. You should set the VDI clip rectangle to this
Xvalue before doing any output to the screen.
X
X The last two words in the PARMBLK contain a copy of the extra
X32-bit parameter from the object's USERBLK. If you have followed
Xthe method of copying an OB_SPEC into this location, these words
Xwill be your pointer to a string, or BITBLK, or whatever.
X
X When your drawing routine is done, it should return a zero
Xvalue to the AES. This is a "magic" value; anything else will
Xstop the drawing operation.
X
X The download contains a sample drawing routine which defines
Xone extended drawing object, a rounded rectangle button. You can
Xuse this procedure as a starting point for your own User Defined
Xobjects.
X
X PUT ANYTHING YOU WANT ON THE DESKTOP!
X
X In ST PRO GEM #2, I described the use of the WF_NEWDESK
Xwind_set call to substitute your own object tree for the normal
Xgreen desktop background. If the tree you supply contains User
XDefined objects, you can draw whatever you want on the desktop!
XSome of the things you might try are free hand drawings imported
Xin metafile format from EasyDraw, or whole screen bit images
Xgenerated by Degas. If you do the latter, you will have to store
Xthe entire image off screen and blit parts of it to the display as
Xrequested.
X
X In any case, remember that your desktop drawing code can be
Xcalled any time that a window is moved, so exercise the same care
Xas with a menu drawer. Also, be aware that making the WF_NEWDESK
Xcall does not force an immediate redraw of the desktop. To do
Xthat, do a form_dial(3) call for the entire desktop rectangle.
X
X THE TOUCHEXIT FLAG
X
X The TOUCHEXIT attribute is an alternative to the more usual
XEXIT. When the TOUCHEXIT bit is set in an object's OB_FLAG word,
Xthe form_do routine will exit immediately when the mouse button is
Xpressed with the cursor over the object. Your code can
Ximmediately take control of the mouse and display, without waiting
Xfor the release of the button. This method is used for generating
Xeffects such as slider bars within otherwise normal dialogs.
X
X The easiest way to code a TOUCHEXIT handler is to place a
Xloop around the form_do call. If the object number returned is
XTOUCHEXIT, then the animation procedure is called, followed by a
Xresumption of the form_do (WITHOUT recalling form_dial or
Xobjc_draw!). If the object returned is a normal EXIT, the dialog
Xis complete and control flows to the cleanup code.
X
X There is one idiosyncrasy of TOUCHEXIT which should be noted.
XWhen the AES "notices" that the mouse button has been pressed over
Xa TOUCHEXIT, it immediately retests the button state. If it has
Xalready been released, it waits to see if a double click is
Xperformed. If so, the object number returned by form_do will have
Xits high bit set. If you don't care about double clicks, your
Xcode should mask off this flag. However, you may want to use the
Xdouble click to denote some enhanced action. For example, the GEM
Xfile selector uses a double click on one of the file name objects
Xto indicate a selection plus immediate exit.
X
X THE INDIRECT FLAG
X
X If the INDIRECT bit is set in an object's OB_STATE word, the
XAES interprets the 32-bit OB_SPEC field as a pointer to the memory
Xlocation in which the ACTUAL OB_SPEC is to be found. Like User
XDefined objects, this capability is not supported by the RCS, so
Xyou have to set up the INDIRECT bit and alter the OB_SPEC at run
Xtime.
X
X The value of INDIRECT is that you can use it to associate an
XAES object with other data or code. The general technique is to
Xset up a table with a spare 32-bit location at its beginning.
XThen, when initializing the application's resource, you move the
Xtrue OB_SPEC into this location, set the INDIRECT flag, and
Xreplace the OB_SPEC field with a pointer to the table. The object
Xbehaves normally during drawing and form handling. However, if you
Xreceive its number from form_do or objc_find, you have an
Ximmediate pointer to the associated table, without having to go
Xthrough a lookup procedure.
X
X This technique works well in programs like the GEM Desktop.
XEach G_ICON object is set up with INDIRECT. Its OB_SPEC goes to
Xthe beginning of a data area defining the associated file. The
Xblank location at the beginning of file table is filled up with
Xthe former OB_SPEC, which points to a ICONBLK.
X
X You can also combine INDIRECT with TOUCHEXIT when creating
Xobjects that must change when they are clicked by a user. For
Xinstance, a color selection box might be linked to a table
Xcontaining the various OB_SPEC values through which the program
Xwill cycle. Each time the user clicked on the box, the TOUCHEXIT
Xroutine would advance the table pointer, copy the next value into
Xthe dummy OB_SPEC location at the front of the table, and redraw
Xthe object in its new appearance.
X
X A programmer who wanted to follow a truly object-oriented
X"Smalltalkish" approach could use the INDIRECT method to bind AES
Xdrawing object to tables of associated procedures or "methods".
XFor instance, one procedure could be flagged for use when the user
Xclicked on the object, one when the object was dragged, one for
Xdouble-click, and so on. If the table structure was capable of
Xindicating that the true method was stored in another table, a
Xrudimentary form of class inheritance could be obtained.
X
X INSTANT CO-ROUTINES
X
X We turn to the AES event and message system for this trick.
XWhile some languages like Modula 2 provide a method for
Ximplementing co-routines, there is no such capability in C.
XHowever, we can effectively fake it by using the AES event
Xlibrary.
X
X As already seen in an earlier column, an application can
Xwrite a message to its own event queue using the appl_write call.
XUsually, this is a redraw message, but there is nothing to prevent
Xyou from using this facility to send messages from one routine in
Xyour program to another. To set up co-routines using this method,
Xthey would be coded as separate procedures called from the
Xapplication's main event loop.
X
X When one of the co-routines wanted to call the other, it
Xwould post a message containing the request and any associated
Xparameters into the application's queue and then return. The main
Xloop would find the message and make the appropriate call to the
Xsecond co-routine. It it was necessary to then re-enter the first
Xco-routine at the calling point, the original message could
Xcontain an imbedded reply message to be sent back when the request
Xwas complete. A simple switch structure could then be used to
Xresume at the appropriate point.
X
X There are two potential problems in using this method. The
Xfirst is the limited capacity of the application event queue. The
Xqueue contains eight entries. While the AES economizes this
Xspace by merging redraws and multiple events, it cannot merge
Xmessages. Because of this limit, you must be extremely careful
Xwhen one message received has the potential to generate two or
Xmore messages sent. Unless this situation is carefully managed,
Xyou can get a sort of "cancer" which will overflow the queue and
Xprobably crash your application.
X
X The second danger involves race conditions. Message sent by
Xthe application are posted to the end of the queue. If other
Xevents have occurred, such as mouse clicks or keyboard presses,
Xthey will be seen and processed ahead of the application generated
Xmessage. This implies that you cannot use this method if the
Xprogram must complete its action before a new user generated event
Xcan be processed.
X
X THAT'S ALL FOR NOW
X
X Hopefully these hints will keep you profitably occupied for a
Xwhile. ST PRO GEM number twelve will return to the topic of user
Xinterfaces. Reaction to the first article on this subject was
Xmostly positive, but a lot of folks wanted to see real code as
Xwell. In response to your feedback, there will also be code for
Ximplemented your own "mouse sensitive" objects which highlight
Xwhen the cursor touches them. This will be presented as part of
Xan alternate form manager.
X
X UPDATE: ATARI ST
X
X I have recently gotten more information on some topics
Xmentioned in earlier articles. These notes will bring you up to
Xdate:
X
X A number of developers reported that they were unable to get
Xthe self-redraw technique described in ST PRO GEM #2 to work.
XThis is usually due to a bug in the appl_init binding in Alcyon C.
XThe value returned from the function, which would normally be
Xassigned to gl_apid, is coming back as garbage. To work around
Xthe problem, declare EXTERN WORD gl_apid; in your program and DO
XNOT assign the value from appl_init. The binding WILL make the
Xassignment. A tip of the hat to Russ Wetmore for this report.
X
X The last column mentioned that turning off the clip
Xrectangle while drawing graphics text will speed things up. It
Xturns out that the VDI will also run at the non-clipped speed if
Xthe ENTIRE string to be written is within the current clip
Xrectangle. To compound the problem, there is a one-off bug in the
Xdetection algorithm for the right edge. That is, the clip
Xrectangle has to be one pixel BEYOND the right edge of the text
Xfor the fast write to work.
X
X The Feedback in ST PRO GEM #10 mentioned that there are known
Xbugs in the Alcyon C floating point library. In fact, this
Xlibrary has been replaced with a new, debugged version in recent
Xshipments of the Toolkit. If you need to use floating point and
Xhave run into this bug, you should be able to get an update from
XAtari. Also, check the Atari Developer's SIG (PCS-57) for a
Xpossible download.
X
X In addition, it turns out there is an undocumented feature in
XAlcyon C which allows you to imbed assembly code in-line. Try
Xusing:
X
X asm(".....");
X
Xwhere the dots are replaced with an assembly instruction. You get
Xone instruction per asm(), one asm() per line. Thanks to Leonard
XTramiel for both of the above tidbits.
END_OF_gem11.asc
if test 20829 -ne `wc -c <gem11.asc`; then
echo shar: \"gem11.asc\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked both archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0