home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / books / progem / events.12 < prev    next >
Text File  |  1986-11-01  |  19KB  |  334 lines

  1.       Permission to reprint or excerpt is granted only if the following
  2.       line appears at the top of the article:
  3.  
  4.        ANTIC PUBLISHING INC., COPYRIGHT 1986.  REPRINTED BY PERMISSION.
  5.  
  6.  
  7.  
  8.       PROFESSIONAL GEM  by Tim Oren
  9.       Column #12 - GEM Events and Program Structure
  10.  
  11.  
  12.            So I fibbed a little.  This issue (#12) of ST PRO GEM started
  13.       out to be another discussion of interface issues.  But, as Tolkien
  14.       once said, the tale grew in the telling, and this is now the first
  15.       of  a series of three articles.   This part will discuss AES event
  16.       handling  and  its implications for GEM  program  structure.   The
  17.       following  article will contain a "home brew" dialog handler  with
  18.       some  new  features,  and  the third will,  finally,  take up  the
  19.       discussion  of  interface design,  using the dialog handler as  an
  20.       example.   (There is no download for this article.   The downloads
  21.       will return, with a vengeance, in ST PRO GEM #13.)
  22.  
  23.            ALL FOR ONE,  AND ONE FOR ALL.  A quick inspection of the AES
  24.       documents  shows that there are five routines devoted  to  waiting
  25.       for individual types of events, and one routine, evnt_multi, which
  26.       is  used  when more than one type is desired.   This article  will
  27.       discuss  ONLY evnt_multi for two reasons.   First,  it is the most
  28.       frequently used of the routines.   Second, waiting for one type of
  29.       event is a bad practice.   Any event call turns the system over to
  30.       the AES and suspends the application and its interaction with  the
  31.       user.   In  such  cases,  some  "escape clause",  such as a timer,
  32.       should be inserted to revive the program and prompt the user if no
  33.       event  is  forthcoming.   Otherwise,  the  application may end  up
  34.       apparently  (or  actually)  hung,  with a  resulting  reboot,  and
  35.       probably a very annoyed user.
  36.  
  37.            STARTING  AHEAD.   One  possible type of event is a  message.
  38.       Messages  are usually sent to the application by the AES,  and are
  39.       associated  with  windows or the menu.   Two previous articles  in
  40.       this  series have discussed such messages.   ST PRO GEM number two
  41.       considered   window  messages,   and  number  seven  handled  menu
  42.       messages.  You may want to review these topics before proceeding.
  43.  
  44.            The actual evnt_multi call is a horrendous thing:
  45.  
  46.            ev_which = evnt_multi(ev_flags,
  47.                      btn_clicks, btn_mask, btn_state,
  48.                      r1_flags, r1_x, r1_y, r1_w, r1_h,
  49.                      r2_flags, r2_x, r2_y, r2_w, r2_h,
  50.                      &msg_buff,
  51.                      time_lo, time_hi,
  52.                      &mx, &my, &btn, &kbd, &char, &clicks);
  53.  
  54.       Each  of  the lines in the call relate to a different  event,  and
  55.       they  will be discussed in the order in which they  appear.
  56.  
  57.            Note  that a call with this number of parameters causes  some
  58.       overhead  due  to stacking and retrieval of the values.   In  most
  59.       cases,  this  should be of little concern on a machine as fast  as
  60.       the ST.   However, where throughput is a concern, such as in close
  61.       tracking  of the mouse cursor,  you may want to write a customized
  62.       binding  for evnt_multi which dispenses with the  parameter  list.
  63.       This  can  be accomplished by maintaining the values in  a  static
  64.       array  and moving them as a block into the binding  arrays  int_in
  65.       (for all values but &msg_buff), and addr_in (for &msg_buff).  Note
  66.       that  you  may NOT simply leave the values in  int_in;  other  AES
  67.       bindings reuse this space.
  68.  
  69.            Ev_flags  and ev_which are both 16-bit integers  composed  of
  70.       flag bits.  Bits set in ev_flags determine which event(s) the call
  71.       will  wait  for;  those  set in ev_which  indicate  what  event(s)
  72.       actually occurred.   Both use the following flag bit mnemonics and
  73.       functions:
  74.  
  75.            0x0001 - MU_KEYBD - Keyboard input
  76.            0x0002 - MU_BUTTON - Mouse button(s)
  77.            0x0004 - MU_M1 - Mouse rectangle #1
  78.            0x0008 - MU_M2 - Mouse rectangle #2
  79.            0x0010 - MU_MESAG - AES message
  80.            0x0020 - MU_TIMER - Timer
  81.  
  82.       The  appropriate mnemonics are ORed together to create the  proper
  83.       ev_flags value.
  84.  
  85.            There  is  one  common pitfall here.   Notice  that  multiple
  86.       events  may  be reported from one evnt_multi.   Event  merging  is
  87.       performed  by the AES in order to save space on the  application's
  88.       event queue.   If events have been merged,  more than one bit will
  89.       be  set in the ev_which word.   Your application must check ALL of
  90.       the  bits  before  returning to a new  evnt_multi  call.   If  you
  91.       don't do this, some events may be effectively lost.
  92.  
  93.            The  first event to be considered is the mouse button.   This
  94.       is probably the most difficult event to understand and use, and it
  95.       has one major shortcoming.
  96.  
  97.            The  parameter  btn_clicks tells GEM the  maximum  number  of
  98.       clicks which you are interested in seeing.   This value is usually
  99.       two,  if your program uses the double-click method, or one if only
  100.       single  clicks  are used.   The AES returns the number  of  clicks
  101.       which caused the event through &clicks, which must be a pointer to
  102.       a word.
  103.  
  104.            GEM determines the number of clicks by the following  method.
  105.       When the first button-down is detected, a time delay is begun.  If
  106.       another  complete button-up,  button-down cycle is detected before
  107.       the time expires,  then the result is a double click.   Otherwise,
  108.       the  event is a single click.    Note that the final state of  the
  109.       buttons  is  returned via &btn,  as described below.   By checking
  110.       this  final state,  you may determine whether a single click event
  111.       ended with the button up (a full click),  or with the button still
  112.       down  (which  may  be  interpreted as  the  beginning  of  a  drag
  113.       operation).   Double clicking is meaningless,  and not checked, if
  114.       the evnt_multi is waiting on more than one button (see below).
  115.  
  116.            The double-click detection delay is variable,  and may be set
  117.       by your program using the call
  118.  
  119.            ev_dspeed = ev_dclick(ev_dnew, ev_dfunc);
  120.  
  121.       Ev_dfunc  is a flag which determines the purpose of the call.   If
  122.       it  is  zero,  the  current  double click  speed  is  returned  in
  123.       ev_dspeed.   If ev_dfunc is non-zero, then ev_dnew becomes the new
  124.       double-click   speed.    Both  ev_dspeed  and  ev_dnew  are  words
  125.       containing  a "magic number" between zero and four.   Zero is  the
  126.       slowest  (i.e.,  longest)  double-click,  and four is the fastest.
  127.       (These  correspond  to  the  slow-fast  range  in  the   Desktop's
  128.       Preferences  dialog.)  In general,  you should not reset the click
  129.       speed  unless  specifically requested,  because such a change  can
  130.       throw off the user's timing and destroy the hand/eye  coordination
  131.       involved in using the mouse.
  132.  
  133.            GEM  was  originally designed to work with  a  single  button
  134.       input device.   This allows GEM applications to function well with
  135.       devices such as light pens and digitizing tablets.   However, some
  136.       features are available for dealing with multi-button mice like the
  137.       ST's.
  138.  
  139.            The  evnt_multi parameters btn_mask and btn_state  are  words
  140.       containing  flag bits corresponding to buttons.   The lowest order
  141.       bit corresponds to the left-most button,  and so on.  A bit is set
  142.       in  the  btn_mask parameter if the AES is to  watch  a  particular
  143.       button.   The  corresponding bit in btn_state is set to the  value
  144.       for  which  the program is waiting.   The word returned  via  &btn
  145.       uses  the  same  bit system to show the state of  the  buttons  at
  146.       completion.   It  is  important to notice that all of  the  target
  147.       states in btn_state must occur SIMULTANEOUSLY for the event to  be
  148.       triggered.
  149.  
  150.            Note the limiting nature of this last statement.  It prevents
  151.       a  program from waiting for EITHER the left or right button to  be
  152.       pressed.  Instead, it must wait for BOTH to be pressed, which is a
  153.       difficult  operation  at best.   As a result,  the standard  mouse
  154.       button  procedure is practically useless if you want to take  full
  155.       advantage  of  both buttons on the ST mouse.   In this case,  your
  156.       program  must "poll" the mouse state and  determine  double-clicks
  157.       itself.   (More  on  polling later.)  By the way,  many  designers
  158.       (myself  included) believe that using both buttons  is  inherently
  159.       confusing and should be avoided anyway.
  160.  
  161.            MOUSE RECTANGLES.  One of GEM's nicer features is its ability
  162.       to watch the mouse pointer's position for you, and report an event
  163.       only  when it enters or departs a given screen region.   Since you
  164.       don't  have to track the mouse pixel by pixel,  this eliminates  a
  165.       lot  of application overhead.   The evnt_multi call gives you  the
  166.       ability  to  specify one or two rectangular areas  which  will  be
  167.       watched.   An event can be generated either when the mouse pointer
  168.       enters the rectangle,  or when it leaves the rectangle.  The "r1_"
  169.       series  of  parameters specifies one of the  rectangles,  and  the
  170.       "r2_" series specifies the other, as follows:
  171.  
  172.            r1_flag, r2_flag - zero if waiting to enter rectangle,
  173.                                one if waiting to leave rectangle
  174.            r1_x, r2_x - upper left X raster coordinate of wait rectangle
  175.            r1_y, r2_y - upper left Y raster coordinate of wait rectangle
  176.            r1_w, r2_w - width of wait rectangle in pixels
  177.            r1_h, r2_h - height of wait rectangle in pixels
  178.  
  179.       Each  rectangle  wait will only be active if its  associated  flag
  180.       (MU_M1 or MU_M2) was set in ev_flags.
  181.  
  182.            There  are two common uses of rectangle waits.   The first is
  183.       used when creating mouse-sensitive regions on the screen.   Mouse-
  184.       sensitive regions, also called "hot spots", are objects which show
  185.       a  visual effect,  such as inversion or outlining,  when the mouse
  186.       cursor  moves  over them.   The items in a menu dropdown,  or  the
  187.       inversion  of  Desktop icons during a drag operation,  are  common
  188.       examples.
  189.  
  190.               Hot spots are commonly created by grouping  the  sensitive
  191.       objects  into  one  or  two areas,  and then setting  up  a  mouse
  192.       rectangle  wait  for  entering  the  area.    When  the  event  is
  193.       generated,  the  &mx  and &my returns may be examined to find  the
  194.       true  mouse coordinates,  and objc_find or some other search  will
  195.       determine  the affected object.   The object is then  highlighted,
  196.       and  a new wait for exiting the object rectangle is  posted.   (ST
  197.       PRO  GEM  #13 will show how to create more  complex  effects  with
  198.       rectangle waits.)
  199.  
  200.            The  second common use of rectangle waits is in  animating  a
  201.       drag operation.  In many cases, you can use standard AES animation
  202.       routines such as graf_dragbox or graf_rubberbox.   In other cases,
  203.       you  may  want  a figure other than a simple  box,  or  desire  to
  204.       combine   waits  for  other  conditions  such  as  keystrokes   or
  205.       collision with hotspots.  Then you will need to implement the drag
  206.       operation  yourself,  using  the  mouse rectangles  to  track  the
  207.       cursor.
  208.  
  209.            If you want to track the cursor closely, simply wait for exit
  210.       on a one pixel rectangle at the current position,  and perform the
  211.       animation routine at each event.  If the drag operation only works
  212.       on a grid,  such as character positions,  you can specify a larger
  213.       wait  rectangle and only update the display when a legal  boundary
  214.       is crossed.
  215.  
  216.            MESSAGES.   The  &msg_buff parameter of evnt_multi gives  the
  217.       address  of a 16 byte buffer to receive an AES message.   As noted
  218.       above,  I have discussed standard AES messages elsewhere. The last
  219.       column  also mentioned that messages may be used to  simulate  co-
  220.       routines  within  a single GEM program.
  221.  
  222.            A  further possibility which bears examination is the use  of
  223.       messages  to coordinate the activities of multiple  programs.   In
  224.       single-tasking  GEM,  at least one of these programs would have to
  225.       be  a  desk accessory.   In any such use of the GEM messages,  you
  226.       should pay careful attention to the possibility of overloading the
  227.       queue.   Only  eight  slots are provided per task,  and  messages,
  228.       unlike events, cannot be merged by the AES.
  229.  
  230.            TIMER.   The  timer event gives you a way of pacing action on
  231.       the  screen,  clocking out messages,  or providing a time-out exit
  232.       for   an  operation.    Evnt_multi  has  two  16-bit  timer  input
  233.       parameters,  time_hi  and  time_lo,  which are the top and  bottom
  234.       halves,  respectively,  of  a  32-bit millisecond count.   However,
  235.       this documented time resolution must be taken with a grain of salt
  236.       on the ST, considering that its internal clock frequency is 200Hz!
  237.  
  238.            The  timer  event is also extremely useful  for  polling  the
  239.       event  queue.   A  "poll"  tests the queue  for  completed  events
  240.       without going into a wait state if none are present.  In GEM, this
  241.       is   done  by  generating  a  null  event  which   always   occurs
  242.       immediately.  A timer count of zero will do just that.
  243.  
  244.            Therefore,  you  can poll for any set of events by specifying
  245.       them  in  the evnt_multi parameters.   A zero timer wait  is  then
  246.       added to ensure immediate completion.   Upon return,  if any event
  247.       bit(s) OTHER than MU_TIMER are set,  a significant event was found
  248.       on the queue.  If only MU_TIMER is set, the poll failed to find an
  249.       event.
  250.  
  251.            KEYBOARD.   There  are  no input parameters for the  keyboard
  252.       event.   The  character  which  is read is returned  as  a  16-bit
  253.       quantity through the &char parameter.  For historical reasons, the
  254.       codes  which  are returned are compatible with the IBM  PC's  BIOS
  255.       level scan codes.  You can find this character table in Appendix D
  256.       of  the  GEM VDI manual.   In general,  the high byte need only be
  257.       considered  if  the lower byte is zero.   If the low byte is  non-
  258.       zero, it is a valid ASCII character.
  259.  
  260.            Evnt_multi  also returns the status of several modifier  keys
  261.       through  the &kbd parameter.   This word contains four significant
  262.       bits as follows:
  263.  
  264.            0x0001 - Right hand shift key
  265.            0x0002 - Left hand shift key
  266.            0x0004 - Control key
  267.            0x0008 - ALT key
  268.  
  269.       If  a  bit  is  one,  the key was depressed  when  the  event  was
  270.       generated.   Otherwise,  the key was up.  Since the state of these
  271.       keys  is already taken into account in generating the  &char  scan
  272.       code,  the  &kbd word is most useful when creating enhanced  mouse
  273.       functions, such as shift-click or control-drag.
  274.  
  275.            RANDOM NOTES ON EVENTS.   Although the &mx,  &my,  &btn,  and
  276.       &kbd returns are nominally associated with particular event types,
  277.       they are valid on any return from evnt_multi, and reflect the last
  278.       event  which was merged into that return by the AES.  If you  want
  279.       more  current values,  you may use graf_mkstate to resample  them.
  280.       Whichever method you choose, be consistent within the application,
  281.       since  the point of sampling has an effect on mouse  and  keyboard
  282.       timing.
  283.  
  284.            Although  this and preceding columns have been  presented  in
  285.       terms of a GEM application,  the event system has many interesting
  286.       implications  for desk accessories.   Since the AES scheduler uses
  287.       non-preemptive  dispatching,  accessories  have an event  priority
  288.       effectively  equal  to  the main  application.   Though  "typical"
  289.       accessories  wait  only for AC_OPEN or AC_CLOSE messages  when  in
  290.       their  quiescent state,  this is not a requirement of the  system.
  291.       Timer  and  other events may also be requested  by  an  accessory.
  292.       (Indeed,  there  is  no  absolute requirement  that  an  accessory
  293.       advertise  its presence with a menu_register call.)  The  aspiring
  294.       GEM hacker might consider how these facts could be used to  create
  295.       accessories  similar  to  "BUGS" on the Mac,  or  to  the  "Crabs"
  296.       program  described  in  the September,  1985 issue  of  Scientific
  297.       American.
  298.  
  299.            EVENTS  AND GEM PROGRAM STRUCTURE.   Although the  evnt_multi
  300.       call  might seem to be a small part of the entire GEM system,  its
  301.       usage has deep implications for the structure of any  application.
  302.       It is generally true that each use of evnt_multi corresponds to  a
  303.       mode  in  the  program.   For instance,  form_do contains its  own
  304.       evnt_multi,  and its invocation creates a moded dialog.  While the
  305.       dialog  is in progress,  other features such as windows and  menus
  306.       are unusable.  The graf_dragbox, graf_rubberbox, and graf_slidebox
  307.       routines also contain evnt_multi calls.   They create a mode which
  308.       is sometimes called "spring-loaded",  since the mode vanishes when
  309.       some continuing condition (a depressed mouse button) is removed.
  310.  
  311.            In consequence,  a well-designed,  non-modal GEM program will
  312.       contain only one explicit evnt_multi call.  This call is part of a
  313.       top-level  loop  which  decodes events as they  are  received  and
  314.       dispatches  control  to  the appropriate  handling  routine.   The
  315.       dispatcher  must  always  distinguish  between  event  types.   In
  316.       programs  where  multiple windows are used,  it may also  need  to
  317.       determine which local data structure is associated with the active
  318.       window.
  319.  
  320.            This  construction  is  sometimes  called  a  "push"  program
  321.       structure,  because  it  allows the user to drive the  application
  322.       by generating events in any order.  This contrasts with the "pull"
  323.       structure of traditional command line or menu programs,  where the
  324.       application is in control and demands input at each step before it
  325.       proceeds.    "Push"  structure  promotes  consistent  use  of  the
  326.       user interface and a feeling of control on the part of the user.
  327.  
  328.            The  next ST PRO GEM column will look more closely at  events
  329.       and  program  structure in the context of a large piece  of  code.
  330.       The  code  implements an alternate dialog  handler,  incorporating
  331.       mouse-sensitive objects as part of the standard interface.   Since
  332.       this  code  is  "open",  it may be modified and  merged  with  any
  333.       application's main event loop, resulting in non-modal dialogs.
  334.