[net.micro.atari16] ProGEM part 1 of 6

bammi@cwruecmp.UUCP (Jwahar R. Bammi) (03/22/86)

#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	wind1.prf
#	wind2.prf
#	wind3.prf
# This archive created: Fri Mar 21 22:40:48 1986
# By:	Jwahar R. Bammi ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'wind1.prf'" '(13142 characters)'
if test -f 'wind1.prf'
then
	echo shar: over-writing existing file "'wind1.prf'"
fi
sed 's/^X//' << \SHAR_EOF > 'wind1.prf'
X.!****************************************************************************
X.! 
X.! ANTIC PUBLISHING INC., COPYRIGHT 1985.  REPRINTED BY PERMISSION.
X.!
X.! ** Professional GEM ** by Tim Oren
X.!
X.! Proff File by ST enthusiasts at
X.! Case Western Reserve University
X.! Cleveland, Ohio
X.! uucp : decvax!cwruecmp!bammi
X.! csnet: bammi@case
X.! arpa : bammi%case@csnet-relay
X.! compuserve: 71515,155
X.!
X.!****************************************************************************
X.!
X.!
X.!****************************************************************************
X.!
X.!			Begin Part I
X.!
X.!****************************************************************************
X.!
X.PART I Windows
X.SH IN THE BEGINNING
XIn GEM, creating a window and displaying it are two different functions.  The
Xcreation function is called wind_create, and its calling sequence is:
X.FB wind_create()
Xhandle = wind_create(parts, xfull, yfull, wfull, hfull);
X.FE
XThis function asks GEM to reserve space in its memory for a new window
Xdescription, and to return a code or "handle" which you can use to refer to the
Xwindow in the future.  Valid window handles are positive integers; they are not
Xmemory pointers.
X.PP
XGEM can run out of window handles.  If it does so, the value returned is
Xnegative.  Your code should always check for this  situation and ask the
Xprogram's user to close some windows and retry if  possible. Handle zero is
Xspecial.  It refers to the "desktop", which is predefined as light green (or
Xgray) on the ST.  Window zero is always present and may be used, but never
Xdeleted, by the programmer.
X.PP
XThe xfull, yfull, wfull, and hfull parameters are integers which determine
Xthe maximum size of the window.  Xfull and yfull define the upper left corner of
Xthe window, and wfull and hfull specify its width and height. (Note that all of
Xthe window coordinates which we use are in pixel units.)
X.PP
XGEM saves these values so that the program can get them later when processing
XFULL requests.  Usually the best maximum size for a window is the entire
Xdesktop area, excepting the menu bar.  You can find this by asking wind_get  for
Xthe working area of the desktop (handle zero, remember):
X.FB wind_get()
Xwind_get(0, WF_WXYWH, &xfull, &yfull, &wfull, &hfull);
X.FE
XNote that WF_WXYWH, and all of the other mnemonics used in this article, are
Xdefined in the GEMDEFS.H file in the ST Toolkit.
X.PP
XThe parts parameter of wind_create defines what features will be included in
Xthe window when it is drawn.  It is a word of single bit flags which indicate
Xthe presence/absence of each feature.  To request multiple features, the flags
Xare "or-ed" together. The flags' mnemonics and meanings are:
X.BO
XNAME - A one character high title bar at the top of the window.
X.EO
X.BO
XINFO - A second character line below the NAME.
X.EO
X.BO
XMOVER - This lets the user move the window around by "dragging"  in the NAME
Xarea.  NAME also needs to be defined.
X.EO
X.BO
XCLOSER - A square box at the upper left.  Clicking this control point asks
Xthat the window be removed from the screen.
X.EO
X.BO
XFULLER - A diamond at upper right.  Clicking this control point requests
Xthat the window grow to its maximum size, or  shrink back down if it is already
Xbig.
X.EO
X.BO
XSIZER - An arrow at bottom right.  Dragging the SIZER lets  the user choose
Xa new size for the window.
X.EO
X.BO
XVSLIDE - defines a right-hand scroll box and bar for the window. By dragging
Xthe scroll bar, the user requests that the  window's "viewport" into the
Xinformation be moved.   Clicking on the gray box above the bar requests that
Xthe window be moved up one "page". Clicking below the  bar requests a down page
Xmovement.  You have to define  what constitutes a page or line in the
Xcontext of your application.
X.EO
X.BO
XUPARROW - An arrow above the right scroll bar.  Clicking here requests that
Xthe window be moved up one "line".  Sliders and arrows almost always appear
Xtogether.
X.EO
X.BO
XDNARROW - An arrow below the right scroll bar.  Requests that  window be
Xmoved down a line.
X.EO
X.BO
XHSLIDE - These features are the horizontal equivalent of the RTARROW
Xabove.  They appear at the bottom of the window.  Arrows LFARROW  usually
Xindicate "character" sized movement left and right. "Page" sized
Xmovement has to be defined by each application.
X.EO
X.PP
XIt is important to understand the correspondence between window features and
Xevent messages which are sent to the application by the GEM window manager.  If
Xa feature is not included in a window's creation,  the user cannot perform the
Xcorresponding action, and your application will  never receive the matching
Xmessage type.  For example, a window without a  MOVER may not be dragged by the
Xuser, and your app will never get a WM_MOVED  message for that window.
X.PP
XAnother important principle is that the application itself is responsible for
Ximplementing the user's window action request when a message is received.  This
Xgives the application a chance to accept, modify, or reject the user's request.
X.PP
XAs an example, if a WM_MOVED message is received, it indicates that the user
Xhas dragged the window.  You might want to byte or word align the requested
Xposition before proceeding to move the window. The wind_set calls used to
Xperform the actual movements will be described in the next article.
X.SH OPEN, SESAME!
XThe wind_open call is used to actually make the window appear
Xon the screen.  It animates a "zoom box" on the screen and then draws in the
Xwindow's frame.  The calling sequence is:
X.FB wind_open()
Xwind_open(handle, x, y, w, h);
X.FE
XThe handle is the one returned by wind_create.  Parameters x, y, w, and h
Xdefine the initial location and size of the window.  Note that these
Xmeasurements INCLUDE all of the window frame parts which you have requested. To
Xfind out the size of the area inside the frame, you can use
X.FB wind_get()
Xwind_get(handle, WF_WXYWH, &inner_x, &inner_y, &inner_w, &inner_h);
X.FE
XWhatever size you choose for the window display, it cannot be any larger than
Xthe full size declared in wind_create.
X.PP
XHere is a good place to take note of a useful utility for calculating window
Xsizes.  If you know the "parts list" for a window, and its inner or outer size,
Xyou can find the other size with the wind_calc call:
X.FB wind_calc()
Xwind_calc(parts, kind, input_x, input_y, input_w, input_h, &output_x,
X&output_y, &output_w, &output_h);
X.FE
XKind is set to zero if the input coordinates are the inner area, and you are
Xcalculating the outer size.  Kind is one if the inputs are the outer size and
Xyou want the equivalent inner size.  Parts are just the same as in wind_create.
X.PP
XThere is one common bug in using wind_open.  If the NAME feature  is
Xspecified, then the window title must be initialized BEFORE opening the window:
X.FB wind_set()
Xwind_set(handle, WF_NAME, ADDR(title), 0, 0);
X.FE
XIf you don't do this, you may get gibberish in the NAME area or the system
Xmay crash.   Likewise, if you have specified the INFO feature, you must make a
Xwind_set call for WF_INFO before opening the window.
X.PP
XNote  that ADDR() specifies the 32-bit address of title.  This expression is
Xportable to other (Intel-based) GEM systems.  If you don't care about
Xportability, then &title[0], or just title alone will work fine on the ST.
X.SH CLEANING UP
XWhen you are done with a window, it should be closed and
Xdeleted.  The call
X.FB wind_close()
Xwind_close(handle);
X.FE
Xtakes the window off the screen, redraws the desktop underneath it,
Xand animates a "zoom down" box.  It doesn't delete the window's
Xdefinition, so you can reopen it later.
X.PP
XDeleting the window removes its definition from the system, and makes that
Xhandle available for reuse.  Always close windows before deleting,  or you may
Xleave a "dead" picture on the screen.  Also be sure to delete all  of your
Xwindows before ending the program, or your app may "eat" window  handles.  The
Xsyntax for deleting a window is:
X.FB wind_delete()
Xwind_delete(handle);
X.FE
X.SH THOSE FAT SLIDERS
XOne of ST GEM's unique features is the proportional
Xslider bar.  Unlike other windowing systems, this type of bar gives visual
Xfeedback on the fraction of a document which is being viewed, as well as the
Xposition within the document.  The catch, of course, is that you have two
Xvariables to maintain for each scroll bar: size and position.
X.PP
XBoth bar size and position range from 1 to 1000.  A bar size of 1000 fills
Xthe slide box, and a value of one gets the minimum bar size. To compute the
Xproper size, you can use the formula:
X.br
X.sp 1
X.ce 1
Xsize = min(1000, 1000 * seen_doc / total_doc)
X.br
X.sp 1
XSeen_doc and total_doc are the visible and total size of the document
Xrespectively, in whatever units are appropriate.  As an example, if your window
Xcould show 20 lines of a 100 line text file, you should set a slider size of
X200.  Since the window might be bigger than the total  document at some points,
Xyou need the maximum function.   If the document size is zero, force the slider
Xsize to 1000.  (Note: You will probably  need to do the computation above with
X32-bit arithmetic to avoid overflow  problems).
X.PP
XOnce you have computed the size, use the wind_set function to configure the
Xscroll bar:
X.FB wind_set()
Xwind_set(handle, WF_VSLSIZE, size, 0, 0, 0);
X.FE
XThis call sets the vertical (right hand) scroll bar.  Use WF_HSLSIZE for the
Xhorizontal scroller.  All of these examples are done for the vertical
Xdimension, but the principles are identical in the other direction.
X.PP
XBar positioning is a little tougher.   The most confusing aspect is that the
X1-1000 range does not set an absolute position of the bar within the
Xscroll box.  Instead, it positions the TOP of the bar within its
Xpossible range of variation.
X.PP
XLet's look at our text file example again to make this clearer.  If there are
Xalways 20 lines of a 100 line file visible, then the top of the window must be
Xalways be somewhere between line 1 and line 81. This 80 line range is
Xthe actual freedom of movement of the window. So, if the window were
Xactually positioned with its top at line 61, it would be at the
Xthree-quarter position within  the range, and we should set a scroll
Xbar position of 750.  The actual  formula for computing the position is:
X.sp 1
X.ce 1
Xpos = 1000 * (top_wind - top_doc) / (total_doc - seen_doc)
X.sp 1
XTop_wind and top_doc are the top line in the current window and the whole
Xdocument, respectively.  Obviously, if seen_doc is greater or equal to
Xtotal_doc, you need to force a zero value for pos.  This calculation may seem
Xrather convoluted the first time through, but is easy once you have done it.
XWhen you have computed the position, wind_set configures the scroll bar:
X.FB wind_set()
Xwind_set(handle, WF_VSLIDE, pos, 0, 0, 0);
X.FE
X.sp 1
X.ce 1
XWF_HSLIDE is the equivalent for horizontal scrolling.
X.sp 1
XIt is a good practice to avoid setting the slider size or position if they
Xare already at the value which you need.  This avoids an annoying redraw flash
Xon the screen when it is not necessary.  You can check on the current
Xvalue of a slider parameter with wind_get:
X.FB wind_get()
Xwind_get(handle, WF_VSLIDE, &curr_value, &foo, &foo, &foo);
X.FE
XFoo is a dummy variable which needs to be there, but is not used. Substitute
XWF_VSLIDE with whatever parameter you are checking.
X.PP
XOne philosophical note on the use of sliders:  It is probably best to avoid
Xthe use of both sliders at once unless it is clearly appropriate to the type of
Xdata which is being viewed.
X.PP
XSince Write and Paint programs make use of the sheet-of-paper metaphor,
Xmoving the window around in both dimensions is reasonable. However, if the data
Xis more randomly organized, such as a tableau of icons, then it is probably
Xbetter to only scroll in  the vertical dimension and "reshuffle" if
Xthe window's width is changed. Then the user only needs to manipulate
Xone control to find information which is off-screen.  Anyone who has
Xhad trouble finding a file or folder within a Desktop window will
Xrecognize this problem. 
X.SH COMING UP NEXT
XIn my next column in Antic Online, we'll conclude the tour of the ST's
Xwindowing system.  I'll discuss the correct way to redraw a window's contents,
Xand how to handle the various messages which an application receives from the
Xwindow manager.  Finally, we'll look at a way to redesign the desktop
Xbackground to your own specifications.
X.SH FEEDBACK
XOne of the beauties of an on-line column is that you can make your comments
Xknown immediately.  To register your opinions, select ST FEEDBACK, enter your
Xmessage, leave your name, and enter a blank line to exit.
X.PP
XI am interested in hearing proposals for topics, feedback on the technical
Xlevel of the column, and reports on bugs and other "features" in both
Xthe column and the ST itself.  Your comments will be read by the ANTIC
Xstaff and myself and, though we might not answer individual questions,
Xthey will be used to steer the course of future columns.
X.!
X.!
X.!*****************************************************************************
X.!*									      *
X.!*				End Part 1				      *
X.!*									      *
X.!*****************************************************************************
SHAR_EOF
if test 13142 -ne "`wc -c 'wind1.prf'`"
then
	echo shar: error transmitting "'wind1.prf'" '(should have been 13142 characters)'
fi
echo shar: extracting "'wind2.prf'" '(20216 characters)'
if test -f 'wind2.prf'
then
	echo shar: over-writing existing file "'wind2.prf'"
fi
sed 's/^X//' << \SHAR_EOF > 'wind2.prf'
X.!****************************************************************************
X.! 
X.! ANTIC PUBLISHING INC., COPYRIGHT 1985.  REPRINTED BY PERMISSION.
X.!
X.! ** Professional GEM ** by Tim Oren
X.!
X.! Proff File by ST enthusiasts at
X.! Case Western Reserve University
X.! Cleveland, Ohio
X.! uucp : decvax!cwruecmp!bammi
X.! csnet: bammi@case
X.! arpa : bammi%case@csnet-relay
X.! compuserve: 71515,155
X.!
X.!****************************************************************************
X.!
X.!
X.!****************************************************************************
X.!
X.!			Begin Part 2
X.!
X.!****************************************************************************
X.!
X.PART II Windows
X.SH EXCELSIOR
XIn this installment, we continue the exploration of GEM's window manager by
Xfinding out how to process the messages received by an application
Xwhen it has a window defined on the screen.
X.PP
XAlso, beginning with this column, sample C code demonstrating the techniques
Xdiscussed will be available on SIG*ATARI in DL5.  This will allow you to
Xdownload the code without interference by the CIS text-formatter used by ANTIC
XONLINE output.
X.PP
XThe file for this column is GEMCL2.XMO.  All references  to non-GEM routines in
Xthis column refer to this file.  Please note that  these files will not contain
Xentire programs.  Instead, they consist of small pieces of utility code which
Xyou may copy and modify in your own  programs.
X.SH REDRAWING WINDOWS
XOne of the most misunderstood parts of GEM is the correct method for drawing
Xwithin a window.  Most requests for redrawing are generated by the GEM system,
Xand arrive as messages (read with evnt_multi) which contain the handle of the
Xwindow, and the screen rectangle which is  "dirty" and needs to be redrawn.
X.PP
XScreen areas may become dirty as a result of windows being closed, sized down,
Xor moved, thus "exposing" an area underneath.  The completion of  a dialog, or
Xclosing of a desk accessory may also free up a screen area which needs to be
Xredrawn.  When GEM detects the presence of a dirty rectangle,  it checks its
Xlist of open windows, and sends the application a redraw message  for each of
Xits windows which intersects the dirty area.
X.SH CAVEAT EMPTOR
XGEM does not "clip" the rectangle which it sends to  the application; that is,
Xthe rectangle may not lie entirely within the  portion of the window which is
Xexposed on the screen.  It is the job of the application to determine in what
Xportion of the rectangle it may safely draw.   This is done by examining the
X"rectangle list" associated with the window.
X.PP
XA rectangle list is maintained by GEM for each active window.  It contains the
Xportions of the window's interior which are exposed, i.e., topmost, on the
Xscreen and within which the app may draw.
X.PP
XLet's consider an example to make this clear.  Suppose an app has opened two
Xwindows, and there are no desk accessory windows open. The window which is
Xtopmost will  always have only one rectangle in its list.  If the two are
Xseparate on the  screen, then the second window will also have one rectangle.
XIf they overlap,  then the top window will "break" the rectangle of the bottom
Xone.  If the  overlap is at a corner, two rectangles will be generated for the
Xbottom window.  If the overlap is on a side only, then three rectangles are
Xrequired to cover  the exposed portion of the bottom window.  Finally, if the
Xfirst window is  entirely within the second, it requires four rectangles in the
Xlist to tile the second window.
X.PP
XTry working out a few rectangle examples with pencil and paper to get the feel
Xof it.  You will see that the possible combinations with more  than two windows
Xare enormous.  This, by the way, is the reason that GEM does  not send one
Xmessage for each rectangle on the list: With multiple windows,  the number of
Xmessages generated would quickly fill up the application's message queue.
X.PP
XFinally, note that every app MUST use this method, even if it only
Xuses a single window, because there may be desk accessories with their
Xown  windows in the system at the same time.  If you do not use the
Xrectangle lists, you may overwrite an accessory's window.
X.SH INTO THE BITS
XFirst, we should note that the message type for a  redraw request is WM_REDRAW,
Xwhich is stored in msg[0], the first location of the message returned by
Xevnt_multi.  The window handle is stored in msg[3].  These locations are the
Xsame for all of the message types being discuss.  The rectangle which needs to
Xbe redrawn is stored in msg[4] through msg[7].
X.PP
XNow let's examine the sample redraw code in more detail. The redraw loop is
Xbracketed with mouse off and mouse on calls.  If you forget to do  this, the
Xmouse pointer will be over-written if it is within the window and  the next
Xmovement of the mouse will leave a rectangular blotch on the screen  as a piece
Xof the "old" screen is incorrectly restored.
X.PP
XThe other necessary step is to set the window update flag.  This prevents the
Xmenu manager from dropping a menu on top of the screen portion being redrawn.
XYou must release this flag at the end of the redraw, or the you will be unable
Xto use any menus afterwards.
X.PP
XThe window rectangles are retrieved using a get-first, get-next scheme which
Xwill be familiar if you have used the GEM DOS or PC-DOS wildcard file calls.
XThe end of the rectangle list has been reached when both the width and height
Xreturned are zero.  Since some part of a  window might be off-screen
X(unless you have clamped its position - see below), the retrieved
Xrectangle is intersected with the desktop's area,  and then with the
Xscreen area for which a redraw was requested.
X.PP
XNow you have the particular area of the screen in which it is  legal to draw.
XUnless there is only one window in your application, you will have to test the
Xhandle in the redraw request to figure out what to  put in the rectangle.
X.PP
XDepending on the app, you may be drawing an AES  object tree, or executing VDI
Xcalls, or some combination of the two.  In  the AES case, the computed
Xrectangle is used to specify the bounds of the objc_draw.  For VDI
Xwork, the rectangle is used to set the clipping area before executing
Xthe VDI calls.
X.SH A SMALL CONFESSION
XAt the beginning of this discussion, I  deliberately omitted one class of
Xredraws: those initiated by the application  itself.
XIn some cases a part of the screen must be redrawn immediately to give feedback
Xto the user following a keystroke, button, or mouse action.   In these cases,
Xthe application could call do_redraw directly, without  waiting for a message.
X.PP
XThe only time you can bypass do_redraw, and draw  without walking the rectangle
Xlist, is when you can be sure that the target  window is on top, and that the
Xfigure being drawn is entirely contained  within it.
X.PP
XIn many cases, however, an application initiated redraw happens because of a
Xcomputed change, for instance, a spreadsheet update, and its timing is not
Xcrucial.  In this instance, you may wish to have the  app send ITSELF a redraw
Xrequest.
X.PP
XThe main advantage of this approach  is that the AES is smart enough to see if
Xthere is already a redraw request for the same window in the queue, and, if so,
Xto merge the requests by  doing a union of their rectangles.  In this fashion,
Xthe "blinky" appearance of multiple redraws is avoided, without the need to
Xinclude logic for merging redraws within the program.
XA utility routine for sending the "self-redraw" is included in the
Xdown-load for this article.
X.SH WINDOW CONTROL REQUESTS
XAn application is notified by the AES, via the message system, when the user
Xmanipulates one of the window control points.  Remember that you must have
Xspecified each control point when the window was created, or will not receive
Xthe associated control message.
X.PP
XThe most important thing to understand about window control is that the change
Xwhich the user requested does not take place until the application forwards it
Xto the AES.  While this makes for a little extra work,  it gives the program a
Xchance to intervene and validate or modify the request to suit.
X.PP
XA second thing to keep in mind is that not all window updates cause a redraw
Xrequest to be generated for the window, because the AES attempts to save time
Xwith raster moves on the screen.
XNow let's look at each window control request in detail.  The message
Xcode for a window move is WM_MOVED.  If you are willing to accept  any
Xsuch request, just do:
X.FB wind_set()
Xwind_set(wh, WF_CXYWH, msg[4], msg[5], msg[6], msg[7]);
X.FE
X.sp 1
X.ce 1
X(Remember that wh, the window handle, is always in msg[3]).
X.sp 1
XThe AES will not request a redraw of the window following this call, unless the
Xwindow is being moved from a location which is partially "off-screen". Instead,
Xit will do a "blit" (raster copy) of the window and its contents to the new
Xlocation without intervention by the app.
X.PP
XThere are two constraints which you may often wish to apply to  the user's move
Xrequest.  The first is to force the new location to lie entirely within the
Xdesktop, rather than partially off-screen.  You can do this with the
Xrc_constrain utility by executing:
X.FB rc_constrain()
Xrc_constrain(&full, &msg[4]);
X.FE
Xbefore making the wind_set call.  (Full is assumed to contain the desktop
Xdimensions.)
X.PP
XThe second common constraint is to "snap" the x-dimension location of the new
Xlocation to a word boundary.  This operation will speed up GEM's "blit" because
Xno shifting or masking will need to be done when moving the window.  To perform
Xthis operation, use align() before the  wind_set call:
X.FB align()
Xmsg[4] = align(msg[4], 16);
X.FE
XThe message code for a window size request is WM_SIZED.  Again, if you are
Xwilling to accept any request, you can just "turn it around" with the same
Xwind_set call as given for WM_MOVED.
X.PP
XActually, GEM enforces a couple of constraints on sizing.  First, the
Xwindow may not be sized off screen.  Second, there is a minimum window
Xsize which is dependent on the window components specified when it was
Xcreated.  This prevents features like scroll arrows from being
Xsqueezed into oblivion. The most common application constraint on
Xsizing is to snap the size to horizontal words (as above) and/or
Xvertical character lines.  In the latter case, the vertical dimension
Xof the output font is used with align(). 
X.PP
XAlso,  be aware that the size message which you receive specifies the
XEXTERNAL dimensions of the window.  To assure an "even" size for the
XINTERNAL dimensions, you must make a wind_calc call to compute them,
Xuse align() on the computed values, back out the corresponding
Xexternal dimensions with the reverse wind_calc, and then make the
Xwind_set call with this set of values. 
X.PP
XA window resize will only cause a redraw request for the window if the size is
Xbeing increased in at least one dimension.  This is satisfactory for most
Xapplications, but if you must "reshuffle" the window after a  size-down, you
Xshould send yourself a redraw (as described above) after you make the wind_set
Xcall.  This will guarantee that the display is updated correctly.  Also note
Xthat the sizing or movement of one window may cause redraw requests to be
Xgenerated for other windows which are uncovered by the change.
X.PP
XThe window full request, with code WM_FULLED, is actually a toggle. If the
Xwindow is already at its full size (as specified in the wind_create), then this
Xis a request to shrink to its previous size. If the window is currently small,
Xthen the request is to grow to full size.
X.PP
XSince the AES records the current, previous, and maximum window size,
Xyou can use wind_get calls to determine which situation pertains. The
Xhndl_full utility in the down-load (modified from Doodle), shows how
Xto do this. 
X.PP
XThe "zoom box" effects when changing size are optional, and can be removed  to
Xspeed things up.  Again, if the window's size is decreasing, no redraw is
Xgenerated, so you must send yourself one if necessary.  You should not have  to
Xperform any constraint or "snap" operations here, since (presumably) the  full
Xand previous sizes have had these checks applied to them already.
X.PP
XThe WM_CLOSED message is received when the close box is clicked. What
Xaction you perform depends on the application.  If you want to remove
Xthe window, use wind_close as described in the last column.  In many
Xapplications, however, the close message may indicate that a file is
Xto be saved, or a directory or editing level is to be closed.  In
Xthese cases, the message is used to trigger this action before or
Xinstead of the wind_close.  (Folders on the Desktop are an example of
Xthis situation.) 
X.PP
XThe WM_TOPPED message indicates that the AES wants to bring the
Xindicated window to the "top" and make it active.  This happens if the
Xuser clicks within a window which is not on top, or if the currently
Xtopped window is closed by its application or desk accessory.
XNormally, the application should respond to this message with:
X.FB wind_set()
Xwind_set(wh, WF_TOP, 0, 0);
X.FE
Xand allow the process to complete.
X.PP
XIn a few instances, a window may be used in an output only mode, such as a
Xstatus display, with at least one other window present for input.  In
Xthis case, a WM_TOPPED message for the status window may be ignored.
XIn all other cases, you must handle the WM_TOPPED message even if your
Xapplication has only one window: Invocation of a desk accessory could
Xalways place another window on top.  If you fail to do so, subsequent
Xredraws for your window may not be processed correctly.
X.SH WINDOW SLIDER MESSAGES
XIf you specify all of the slider bar parts for your window, you may receive up
Xto five different message types for each of the two sets of sliders.  To
Xsimplify things a little, I will discuss everything in terms of the vertical
X(right hand side) sliders.  If you are also using the horizontal sliders, the
Xsame techniques will work, just use the alternate mnemonics.
X.PP
XThe WM_VSLID message indicates that the user has dragged the slider bar within
Xits box, indicating a new relative position within the document.
XAlong with the window handle, this message includes the relative
Xposition between 1 and 1000 in msg[4].
X.PP
XRecall from last column's discussion that this interval corresponds to the
X"freedom of movement" of the slider. If you want to accept the user's request,
Xjust make the call:
X.FB wind_set
Xwind_set(wh, WF_VSLIDE, msg[4], 0, 0, 0);
X.FE
X.sp 1
X.ce 1
X(Corresponding horizontal mnemonics are WM_HSLID and WF_HSLIDE).
X.sp 1
XNote that this wind_set call will not cause a redraw message to be sent.  You
Xmust update the display to reflect the new scrolled position, either by
Xexecuting a redraw directly, or by sending yourself a message.
X.PP
XIf the document within the window has some structure, you may not wish
Xto accept all slider positions.  Instead you may want to force the
Xscroll position to the nearest text line (for instance).  Using terms
Xdefined in the last column, you may convert the slider position to
X"document units" with: 
X.sp 1
X.ce 1
Xtop_wind = msg[4] * (total_doc - seen_doc) / 1000 + top_doc
X.sp 1
X.ce 1
X(This will probably require 32-bit arithmetic).
X.sp 1
XAfter rounding off or otherwise modifying the request, convert it back
Xto slider units and make the WF_VSLIDE request.
X.PP
XThe other four slider requests all share one message code: WM_ARROWED.
XThey are distinguished by sub-codes stored in msg[4]: WA_UPPAGE,
XWA_DNPAGE, WA_UPLINE, and WA_DNLINE.  These are produced by clicking
Xabove and below the slider, and on the up and down arrows,
Xrespectively.  (I have no idea why sub-codes were used in this one
Xinstance.)  The corresponding horizontal slider codes are: 
XWA_LFPAGE, WA_RTPAGE, WA_LFLINE, and WA_RTLINE.
X.PP
XWhat interpretation you give to these requests will depend on  the application.
XIn the most common instance, text documents, the customary method is to change
Xthe top of window position (top_wind) by  one line for a WA_UPLINE or
XWA_DNLINE, and by seen_doc (the number of lines in the window) for a
XWA_UPPAGE or WA_DNPAGE.
X.PP
XAfter making the change, compute a new slider position, and make the wind_set
Xcall as given above.  If the document's length is not an even multiple of
X"lines" or "pages" you will have to be careful that incrementing or
Xdecrementing top_wind does not exceed its range of freedom: top_doc to (top_doc
X+ total_doc - seen_doc).
X.PP
XIf you have such an odd size document, you will also have to make a decision on
Xwhether to violate the line positioning rule so that the slider may be put at
Xits bottom-most position, or to follow the rule but make it impossible to get
Xthe slider to the extreme of its range.
X.SH A COMMON BUG
XIt is easy to forget that user clicks are not the only things that
Xaffect slider position.  If the window size changes as a result of a
XWM_SIZED or WM_FULLED message, the app must also  update its sliders
X(if they are present).  This is a good reason to keep the top of
Xwindow information in "document units". 
X.PP
XYou can just redo the position calculation with the new "seen_doc" value, and
Xcall  wind_set.  Also remember that changing the size of the
Xunderlying document  (adding or deleting a bottom line, for instance)
Xmust also cause the sliders to be adjusted.
X.SH DEPT. OF DIRTY TRICKS
XThere are two remaining window calls which are useful to advanced programmers.
XThey require techniques which I have not yet discussed, so you may need to file
Xthem for future reference.
X.PP
XThe AES maintains a quarter-screen sized buffer which is used to save the area
Xunder alerts and menu drop-downs.  It is occasionally useful for the
Xapplication to gain access to this buffer for its own use in saving
Xscreen areas with raster copies.  To do so, use:
X.FB wind_get()
Xwind_get(0, WF_SCREEN, &loaddr, &hiaddr, &lolen, &hilen);
X.FE
XHiaddr and loaddr are the top and bottom 16-bits (respectively) of the  32-bit
Xaddress of the buffer.  Hilen and lolen are the two halves of  its length.
X.PP
XDue to a preculiarity of the binding you have to reassemble  these
Xpieces before using them.  (The actual value of WF_SCREEN is 17; this
Xdoes not appear in some versions of the GEMDEFS.H file.)
X.PP
XIf you use this buffer, you MUST prevent menus from dropping down by using
Xeither the BEG_UPDATE or BEG_MCTRL wind_update calls.  Failure to do so will
Xresult in your data being destroyed.  Remember to use the matching wind_update:
XEND_UPDATE or END_MCTRL, when you are done.
X.PP
XThe other useful call enables you to replace the system's desktop definition
Xwith a resource of your choosing.  The call:
X.FB wind_set()
Xwind_set(0, WF_NEWDESK, tree, 0, 0);
X.FE
Xwhere tree is the 32-bit address of the object tree, will cause the AES to draw
Xyour definition instead of the usual gray or green background. Not
Xonly that, it will continue to redraw this tree with no intervention
Xon your part. 
X.PP
XObviously, the new definition must be carefully built to fit the desktop area
Xexactly or garbage will be left around the edges.  For the truly sophisticated,
Xa user-defined object could be used in this tree, with the result that your
Xapplication's code would be entered from the AES whenever the desktop was
Xredrawn.  This would allow you to put VDI pictures or complex images onto the
Xdesktop background.
X.SH A SIN OF OMISSION
XIn the last column, I neglected to mention that strings whose addresses are
Xpassed in the WF_NAME and WF_INFO  wind_set calls must be allocated in a static
Xdata area.  Since the AES remembers the addresses (not the characters), a
Xdisaster may result if the storage has been reused when the window manager next
Xattempts to draw the window title area.
X.SH COMING SOON
XThis concludes our tour of GEM's basic window management techniques. There have
Xbeen some unavoidable glimpses of paths not yet taken (forward references), but
Xwe will return in time.
X.PP
XOn our next excursion, we will take a look at techniques for handling simple
Xdialog boxes, and start exploring the mysteries of resources and object trees.
X.!
X.!
X.!*****************************************************************************
X.!*									      *
X.!*				End Part 2				      *
X.!*									      *
X.!*****************************************************************************
SHAR_EOF
if test 20216 -ne "`wc -c 'wind2.prf'`"
then
	echo shar: error transmitting "'wind2.prf'" '(should have been 20216 characters)'
fi
echo shar: extracting "'wind3.prf'" '(16916 characters)'
if test -f 'wind3.prf'
then
	echo shar: over-writing existing file "'wind3.prf'"
fi
sed 's/^X//' << \SHAR_EOF > 'wind3.prf'
X.!****************************************************************************
X.! 
X.! ANTIC PUBLISHING INC., COPYRIGHT 1985.  REPRINTED BY PERMISSION.
X.!
X.! ** Professional GEM ** by Tim Oren
X.!
X.! Proff File by ST enthusiasts at
X.! Case Western Reserve University
X.! Cleveland, Ohio
X.! uucp : decvax!cwruecmp!bammi
X.! csnet: bammi@case
X.! arpa : bammi%case@csnet-relay
X.! compuserve: 71515,155
X.!
X.!****************************************************************************
X.!
X.!
X.!****************************************************************************
X.!
X.!			Begin Part 3
X.!
X.!****************************************************************************
X.!
X.PART III THE DIALOG HANDLER
X.SH A MEANINGFUL DIALOG
XThis issue of ST PRO GEM begins an exploration of ST GEM's dialog handler.  I
Xwill discuss basic system calls for presenting the dialog, and then continue
Xwith techniques for initializing and reading on/off button and "radio" button
Xobjects.  We  will also take some short side-trips into the operation
Xof the GEM Resource Construction Set to assist you in building these dialogs.
X.PP
XThere are a number of short C routines which accompany this column. These are
Xstored as file GEMCL3.XMO in DL 5 on SIG*ATARI. Before reading this column, you
Xshould visit SIG*ATARI (go pcs-132) and download this file.
X.PP
X.SH DEFINING TERMS
XA dialog box is an "interactive form" in which the user may enter text and
Xindicate selections by pointing with the mouse. Dialogs in GEM are
X"modal", that is, when a dialog is activated other screen functions
Xsuch as menus and  window controls are suspended until the dialog is completed.
X.PP
XIn most cases, the visual structure of a GEM dialog is specified within your
Xapplication's resource file.  The GEM Resource Construction Set (RCS)
Xis used to build a picture of the dialog.
X.PP
XWhen the RCS writes out a resource, it converts that picture into a tree of
XGEM drawing objects and stores this data structure within the resource.  Before
Xyour application can  display the dialog, it must load this resource file and
Xfind the  address of the tree which defines the dialog.
X.PP
XTo load a resource, the AES checks its size and allocates memory for the
Xload.  It then reads in the resource, adjusting internal pointers to
Xreflect the load address.  Finally, the object sizes stored in the
Xresource are converted from characters to pixels using the system font size.
X.PP
XA note for those with Macintosh experience:  Although Mac and GEM resources
Xshare a name, there are fundamental differences which can be misleading.  A Mac
Xresource is a fork within a file; a GEM resource is a TOS file by itself.  Mac
Xresources may be paged in and out of memory; GEM resources are monolithic.  GEM
Xresources are internally tree structured; Mac resources are not.  Finally, Mac
Xresources include font information, while ST GEM does this with font loading at
Xthe VDI level.
X.PP
XThe resource load is done with the GEM AES call:
X.FB rsrc_load()
Xok = rsrc_load(ADDR("MYAPP.RSC"));
X.FE
X"MYAPP" should be replaced with the name of your program. Resources
Xconventionally have the same primary name as their application, with the RSC
Xextent name instead of PRG.  The ok flag returned by rsrc_load will be FALSE is
Xanything went wrong during the load.
X.PP
XThe most common causes of failure are the resource not being in the
Xapplication's subdirectory, or lack of sufficient memory for GEM to allocate
Xspace for the resource.  If this happens, you must terminate the program
Ximmediately.
X.PP
XOnce you have loaded the resource, you find the address of a dialog's object
Xtree with:
X.FB rsrc_gaddr()
Xrsrc_gaddr(R_TREE, MYDIALOG, &tree);
X.FE
XTree is a 32-bit variable which will receive the address of the root
Xnode of the tree.
X.PP
XThe mnemonic MYDIALOG should be replaced with the name you gave your dialog
Xwhen defining it in the RCS.  At the same time that it writes the resource, RCS
Xgenerates a corresponding .H file containing tree and object names.
XIn order to use these mnemonics within your program, you must include
Xthe name file in your compile:  #include "MYAPP.H"
X.SH BUG ALERT!
XWhen using the DRI/Alcyon C compiler, .H files must be in the compiler's home
Xdirectory or they will not be found.  This is especially annoying using a two
Xfloppy drive ST development system. The only way around this is to explicitly
Xreference an alternate disk in the #include, for instance:  "B:MYAPP.H".
X[Ed. Note: Use the -i flag with the C pre-processor to name the include
Xdirectories].
X.PP
XNow that the address of the dialog tree has been found, you are ready to
Xdisplay it.  The standard (and minimal) sequence for doing so is given in
Xroutine hndl_dial() in the download.  We will now walk through each
Xstep in this procedure.
X.PP
XThe form_center call establishes the location of the dialog on the screen.
XDialog trees generated by the RCS have an undefined origin (upper-left corner).
X.PP
XForm_center computes the upper-left location necessary to center the dialog
Xon the screen, and inserts it into the OB_X and OB_Y fields of the ROOT object
Xof the tree.  It also computes the screen rectangle which the dialog
Xwill occupy on screen and writes its pixel coordinates into variables
Xxdial, ydial, wdial, and hdial.
X.PP
XThere is one peculiarity of form_center which occasionally causes trouble.
XNormally the rectangle returned in xdial, etc., is exactly the same size as the
Xbasic dialog box.
X.PP
XHowever, when the OUTLINED enhancement has been specified for the box,
Xform_center adds a three pixel margin to the rectangle returned. This
Xcauses the screen area under the outline to be correctly redrawn later
X(see below).  Note that OUTLINED is part of the standard dialog box in
Xthe RCS.  Other enhancements, such as SHADOWED or "outside" borders
Xare NOT handled in this fashion, and you must compensate  for them in
Xyour code. 
X.PP
XThe next part of the sequence is a form_dial call with a zero parameter.
XThis reserves the screen for the dialog action about to occur. Note that the C
Xbinding given for form_dial in the DRI documents is in error: there are nine
Xparameters, not five.  The first set of xywh arguments is actually used with
Xform_dial calls 1 and 2 only, but place holders must be supplied in all cases.
X.PP
XThe succeeding form_dial call (parameter one) animates a "zoom box" on the
Xscreen which moves and grows from the first screen rectangle given to
Xthe second rectangle, where the dialog will be displayed.
X.PP
XThe use of this call is entirely optional.  In choosing whether to use it or
Xnot, you should consider whether the origin of the "zoom" is relevant to the
Xoperation.  For instance, a zoom from the menu bar is relatively meaningless,
Xwhile a zoom from an object about to be edited in the dialog provides visual
Xfeedback to the user, showing whether the correct object was chosen.
X.PP
XIf the origin is not relevant, then the zoom is just a time-waster. If  you
Xdecide to include these effects, consider a "preferences" option in  your app
Xwhich will allow the experienced and jaded user to turn them off in the
Xinterests of speed.
X.PP
XThe objc_draw call actually displays the dialog on the screen. Note that the
Xaddress of the tree, the beginning drawing object, and the drawing depth are
Xpassed as arguments, as well as the rectangle allotted for the dialog.
X.PP
XIn general, dialogs (and parts of dialogs) are  ALWAYS drawn beginning at the
XROOT (object zero).  When you want to draw  only a portion of the
Xdialog, adjust the clipping rectangle, but not the object number.
XThis ensures that the background of the dialog is always  drawn correctly.
X.PP
XThe objc_xywh() utility in the download can be used to find the clipping
Xrectangle for any object within a dialog, though you may have to allow an extra
Xmargin is you have used shadows, outlines, or outside borders with the object.
X.PP
XCalling form_do transfers control to the AES, which animates the dialog for
Xuser interaction.  The address of the dialog tree is passed as a
Xparameter.  The second paramter is the number of the editable object
Xat which the text cursor will first be positioned. If you have no text
Xfields, pass a zero.  Note that again the DRI documents are in error:
Xpassing a -1 default may crash the system. Also be careful that the
Xdefault which you specify is actually a text field; no error checking
Xis performed. 
X.PP
XThe form_do call returns the number of the object on which the clicked to
Xterminate the dialog.  Usually this is a button type object with the EXIT and
XSELECTABLE attributes set.  Setting the DEFAULT attribute as well will cause an
Xexit on that object is a carriage return is struck while in the dialog.
X.PP
XIf the top bit of the return is set, it indicates that  the exit object had
Xthe TOUCHEXIT attribute and was selected with a double-click.  Since very few
Xdialogs use this combination, the sample code simply masks off the top bit.
X.PP
XThe next form_dial call reverses the "zoom box", moving it from the dialog's
Xlocation back to the given x,y,w,h.  The same cautions apply here as above.
X.PP
XThe final form_dial call tells GEM that the dialog is complete, and that the
Xscreen area occupied by the dialog is now considered "dirty" and needs to be
Xredrawn.  Using the methods described in our last column, GEM then
Xsends redraws to all windows which were overlaid, and does any
Xnecessary redrawing of the menu or desktop itself.
X.PP
XThere is one notable "feature" of form_dial(3):  It always redraws an area
Xwhich is two pixels wider and higher than your request!  This was probably
Xincluded to make sure that drop-shadows were cleaned up, and is usually
Xinnocuous.
X.SH A HANDY TRICK
XUse of the form_dial(3) call is not limited to dialogs.  You can use
Xit to force the system to redraw any part of the screen.  The
Xadvantage of this method is that the redraw area need not lie entirely
Xwithin a window, as was necessary with the send_redraw method detailed
Xin the last column.  A disadvantage is that this method is  somewhat
Xslower, since the AES has to decide who gets the redraws.
X.SH CLEAN UP
XAs a last step, you need to clear the SELECTED flag in the object which was
Xclicked.  If you do not do this, the object will  be drawn inverted the next
Xtime you call the dialog.  You could clear the flag with the GEM objc_change
Xcall, but it is inefficient since you do not need to redraw the object.
X.PP
XInstead, use the desel_obj() code in the  download, which modifies the
Xobject's OB_STATE field directly.  Assuming  that ret_obj contains the exit
Xobject returned by hndl_dial, the call:
X.FB desel_obj()
Xdesel_obj(tree, ret_obj);
X.FE
Xwill do the trick.
X.SH RECAP
XThe basic dialog handling method I have described contains three steps:
Xinitialization (rsrc_gaddr), dialog presentation (hndl_dial), and cleanup
X(desel_obj).
X.PP
XAs we build more advanced dialogs, these same basic steps will be performed,
Xbut they will grow more complex. The initialization will include setting up
Xproper object text and states, and the cleanup phase will also interrogate the
Xfinal states of objects to find out what the user did.
X.SH BUTTON, BUTTON
XThe simple dialogs described above contain only exit buttons as active objects.
XAs such, they are little more than glorified alert boxes.
X.PP
XWe will now increase the complexity a little by considering non-exit buttons.
XThese are constructed by setting the SELECTABLE attribute on a button object.
XAt run-time, such an object will toggle its state between selected
X(highlighted) and non-selected  whenever the user clicks on it.  (You
Xcan set the SELECTABLE attribute  of other types of objects and use
Xthem instead of actual buttons, but  be sure that the user will be
Xable to figure out what you intend!) 
X.PP
XHaving non-exit buttons forces us to consider the problem of initializing
Xthem before the dialog, and interrogating and resetting them afterward.
X.PP
XSince a button is a toggle, it is usually associated with a flag variable in
Xthe program.  As part of the initialization, you should test the flag variable,
Xand if true call:
X.FB sel_obj()
Xsel_obj(tree, BTNOBJ);
X.FE
Xwhich will cause the button to appear highlighted when the dialog is first
Xdrawn.  Sel_obj() is in the download.  BTNOBJ is replaced with the  name you
Xgave your button when you defined it in the RCS.  Since the button starts out
Xdeselected, you don't have to do anything if your flag variable is false.
X.PP
XAfter the dialog has completed, you need to check the object's state. The
Xselectp() utility does so by masking the OB_STATE field.  You can simply assign
Xthe result of this test to your flag variable, but be sure that the dialog was
Xexited with an OK button, not with a CANCEL! Again, remember to clean up the
Xbutton with desel_obj(). (It's often easiest to deselect all buttons
Xjust before you leave the dialog routine, regardless of the final
Xdialog state.) 
X.SH WHO'S GOT THE BUTTON?
XAnother common use of buttons in a  dialog is to select one of a set
Xof possible options.  In GEM, such objects are called radio buttons.
XThis term recalls automobile radio tuners where pushing in one button
Xpops out any others.  In like fashion, selecting any one of a set of
Xradio buttons automatically deselects all of the others.
X.PP
XTo use the radio button feature, you must do some careful work with the
XResource Construction Set.
X.PP
XFirst, each member of a set of  radio buttons must be children of the same
Xparent object within the  object tree. To create this structure, put a hollow
Xbox type object in the  dialog, make it big enough to hold all of the buttons,
Xand then put the buttons into the box one at a time.
X.PP
XBy nesting the buttons within the  box object, you force them to be its
Xchildren.  Each of the buttons must have both the SELECTABLE and RADIO BUTTON
Xattributes set.  When you are done, you may make the containing box
Xinvisible by setting its border to zero, but do not FLATTEN it!
X.PP
XSince each radio button represents a different option, you must usually
Xassign a name to each object.  When initializing the dialog, you must check
Xwhich option is currently set, and turn on the corresponding button only.  A
Xchain of if-then-else structures assures that only one button will be selected.
X.PP
XAt the conclusion of the dialog, you must check each button with selectp()
Xand make the appropriate adjustments to internal variables. Again, an
Xif-then-else chain is appropriate since only one button may be
Xselected.  Either deselect the chosen button within this chain or do
Xthem all at the end. 
X.PP
XThere is one common use of radio buttons in which you may short-cut this
Xprocedure.  If the buttons each represent one possible value of a numeric
Xvariable, for instance, a set of selector buttons representing  colors
Xfrom zero to seven, then you can compute the initial object directly.
X.PP
XIn order for this technique to work, you must use a special capability of the
XRCS.  Insert the object corresponding to a zero value at the top (or left) of
Xyour array of buttons, then put the "one" button below (or right) of it, and so
Xon.
X.PP
XWhen the buttons are complete,  the SORT operation is used to guarantee that
Xthe top/left object is in fact the first child of the parent box with
Xthe others following in order.  Due to the details of object tree
Xstructure (to be discussed in the next column), this will guarantee
Xthat these objects are contiguous in the resource.
X.PP
XIf you assign a name (say BUTTON1) to the first button,  then you can
Xinitialize the correct button with the call:
X.FB sel_obj()
Xsel_obj(tree, BUTTON1 + field);
X.FE
Xwhere field is the variable of interest.
X.PP
XWhen the dialog is complete, you can scan the radio buttons to compute the
Xnew value for the underlying variable.  The encode() procedure in the download
Xwill do this.  As always, remember to deselect the buttons at the end.
X.PP
XYou can use offsets or multipliers if your variable's values don't start with
Xzero or increment by one.  If the values are irregular you may be able to use a
Xlookup table, at the cost of additional code.
X.SH COMING UP NEXT
XIn the next column, I will discuss the internal structure of object
Xtrees.  Then we'll use that knowledge to build a piece of code which
Xwill "walk" an entire tree and apply a function to each object. We'll
Xapply this code to do all of the button deselects  with a single call!
XI'll also look at handling editable text fields and discuss some ways
Xto alter a dialog's appearance at run-time. 
X.SH DISPELL GREMLINS
XAn editing error caused an omission in the first installment of ST PRO
XGEM.  The window components RTARROW and DNARROW should have been
Xlisted along with HSLIDE as the horizontal equivalents of the vertical
Xslider components which were discussed.
X.!
X.!
X.!*****************************************************************************
X.!*									      *
X.!*				End Part 3				      *
X.!*									      *
X.!*****************************************************************************
SHAR_EOF
if test 16916 -ne "`wc -c 'wind3.prf'`"
then
	echo shar: error transmitting "'wind3.prf'" '(should have been 16916 characters)'
fi
#	End of shell archive
exit 0

-- 
					Jwahar R. Bammi
			       Usenet:  .....!decvax!cwruecmp!bammi
			        CSnet:  bammi@case
				 Arpa:  bammi%case@csnet-relay
			   CompuServe:  71515,155