home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / contrib / menu / evmux.icn < prev    next >
Text File  |  1992-05-18  |  5KB  |  176 lines

  1. ############################################################################
  2. #
  3. #    Name:        evmux.icn
  4. #
  5. #    Title:        Callback-based event multiplexor for X-windows
  6. #
  7. #    Author:        Gregg Townsend
  8. #
  9. #    Date:        December, 1990; October, 1991
  10. #
  11. ############################################################################
  12. #
  13. #   These procedures help organize event-driven X-windows programs.
  14. #   They are configured by registering *sensors*, which respond to
  15. #   X events that occur when the mouse cursor is within a particular
  16. #   region.  When a sensor fires, it calls a user procedure that was
  17. #   registerd when the sensor was created.
  18. #
  19. #   These routines interpret window events and respond by calling user code:
  20. #    sensor() registers the events of interest
  21. #    evhandle() reads and responds to the next event
  22. #    evmux() loops forever, handling events
  23. #
  24. #   Two other little routines help build event-driven programs:
  25. #    quitsensor() registers a standardized response to ^C, DEL, etc.
  26. #    argless() responds by calling any proc with no arguments, e.g. exit().
  27. #
  28. #
  29. #   sensor(win,ev,proc,arg,x,y,w,h) -- register an event responder.
  30. #
  31. #    registers *proc* as the procedure to be called when the event[s]
  32. #    *ev* occur within the given bounds inside window *win*.  The default
  33. #    bounds encompass the entire window.
  34. #
  35. #    The event set *ev* can be either:
  36. #        -- a cset or string specifying particular keypresses of interest
  37. #        -- one of the event keywords (&lpress, &rdrag, &resize, etc.)
  38. #
  39. #    When a matching event occurs, proc(win,arg,x,y,e) is called.  proc,
  40. #    win, and arg are as recorded from the sensor call.  x and y give the
  41. #    current mouse position and e the event; for a keypress, this is the
  42. #    character.
  43. #
  44. #    No event generates more than one procedure call.
  45. #    In the case of conflicting entries, the later registrant wins.
  46. #
  47. #
  48. #   evmux(win) -- loop forever, calling event handlers as appropriate.
  49. #   evhandle(win) -- wait for the next event, and handle it.
  50. #
  51. #    evmux(win) is an infinite loop that calls user routines in response
  52. #    to window events.  It is for programs that don't need to do other
  53. #    work while waiting for window input.
  54. #
  55. #    evhandle(win) processes one event and then returns to its caller,
  56. #    allowing external loop control.  evhandle returns the outcome of
  57. #    the handler proc, or fails if there is no handler for the event.
  58. #
  59. #   quitsensor(win,wait) -- standardized "quit" sensor
  60. #
  61. #    quitsensor() registers a sensor that calls exit() when any of these
  62. #    characters are typed in the window:  Q, q, ^C, ^D, ^? (DEL).
  63. #
  64. #    If wait is non-null, quitsensor does not return but just waits for
  65. #    the signal (useful in non-interactive display programs).
  66. #
  67. #
  68. #   argless(win,proc) -- call proc with no arguments.
  69. #
  70. #    Useful for registering argless procedures as in quitsensor() above.
  71. #
  72. ############################################################################
  73.  
  74.  
  75. record evrec (ev, proc, arg, x, y, w, h)
  76. global ewtab
  77.  
  78.  
  79. ## sensor(win,ev,proc,arg,x,y,w,h) -- register an event responder.
  80.  
  81. procedure sensor (win, ev, proc, arg, x, y, w, h)
  82.    local evlist, r, e
  83.  
  84.    /ewtab := table()
  85.    /ewtab[win] := list()
  86.    evlist := ewtab[win]
  87.    /x := 0
  88.    /y := 0
  89.    /w := XAttrib (win, "width") - x
  90.    /h := XAttrib (win, "height") - y
  91.  
  92.    if type(ev) == ("cset" | "string") then 
  93.       ev := cset(ev)
  94.    else
  95.       ev := cset(evchar(ev)) | stop ("invalid event specification: ", image(ev))
  96.    push (evlist, r := evrec (ev, proc, arg, x, y, w, h))
  97.    return r
  98.    end
  99.  
  100.  
  101. ##   evchar (e) -- map mouse event to character code.
  102. #  
  103. #  Internally, *all* events are single-character strings, and mouse & resizing
  104. #  events are mapped into characters that are never returned as keypress events.
  105.  
  106. procedure evchar (s)
  107.    return case s of {
  108.       &lpress:    "\237"    # mouse button 1 down
  109.       &mpress:    "\236"    # mouse button 2 down
  110.       &rpress:    "\235"    # mouse button 3 down
  111.       &lrelease:  "\234"    # mouse button 1 up
  112.       &mrelease:  "\233"    # mouse button 2 up
  113.       &rrelease:  "\232"    # mouse button 3 up
  114.       &ldrag:     "\231"    # mouse button 1 is dragging
  115.       &mdrag:     "\230"    # mouse button 2 is dragging
  116.       &rdrag:     "\227"    # mouse button 3 is dragging
  117.       &resize:    "\226"    # window has resized
  118.    }
  119.    fail
  120. end
  121.  
  122.  
  123. ## evmux(win) -- loop forever, calling event handlers as appropriate.
  124. ## evhandle(win) -- wait for the next event, and handle it.
  125. #            produce result of the handler proc; fail if nobody handles.
  126.  
  127. procedure evmux (win)
  128.    repeat
  129.       evhandle (win)
  130. end
  131.     
  132. procedure evhandle (win)
  133.    local x, y, ev, e, r, t
  134.  
  135.    t := (\ewtab)[win] | stop ("no events registered for window")
  136.    ev := XEvent (win)
  137.  
  138.    # convert event code to single character
  139.    if type(ev) == "integer" then
  140.       e := evchar(ev) | ""
  141.    else
  142.       e := ev
  143.  
  144.    # find and call the first (most recent) matching handler
  145.    # (just a simple serial search)
  146.    every r := !t do
  147.       if any (r.ev, e) & ontarget (r, &x, &y) then
  148.      return r.proc (win, r.arg, &x, &y, ev)
  149.    fail
  150. end
  151.  
  152.  
  153. ## ontarget (r, x, y) -- check if an event is within bounds
  154. #
  155. #  checks that (x, y) are within the bounds of (r.x, r.y, r.w, r.h).
  156.  
  157. procedure ontarget (r, x, y)
  158.    return (x -:= r.x) >= 0 & x < r.w & (y -:= r.y) >= 0 & y < r.h
  159.    end
  160.  
  161.  
  162. ## quitsensor(win,wait) -- standardized "quit" sensor
  163.  
  164. procedure quitsensor (win, wait)
  165.    sensor (win, '\^c\^d\dqQ', argless, exit)
  166.    if \wait then evmux (win)
  167.    return
  168.    end
  169.  
  170.  
  171. ## argless(win,proc) -- call proc with no arguments.
  172.  
  173. procedure argless (win, proc)
  174.    return proc ()
  175.    end
  176.