[comp.sys.atari.st] ProGem...more Part 02 of 02

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