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