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 >
Wrap
Text File
|
1992-05-18
|
5KB
|
176 lines
############################################################################
#
# Name: evmux.icn
#
# Title: Callback-based event multiplexor for X-windows
#
# Author: Gregg Townsend
#
# Date: December, 1990; October, 1991
#
############################################################################
#
# These procedures help organize event-driven X-windows programs.
# They are configured by registering *sensors*, which respond to
# X events that occur when the mouse cursor is within a particular
# region. When a sensor fires, it calls a user procedure that was
# registerd when the sensor was created.
#
# These routines interpret window events and respond by calling user code:
# sensor() registers the events of interest
# evhandle() reads and responds to the next event
# evmux() loops forever, handling events
#
# Two other little routines help build event-driven programs:
# quitsensor() registers a standardized response to ^C, DEL, etc.
# argless() responds by calling any proc with no arguments, e.g. exit().
#
#
# sensor(win,ev,proc,arg,x,y,w,h) -- register an event responder.
#
# registers *proc* as the procedure to be called when the event[s]
# *ev* occur within the given bounds inside window *win*. The default
# bounds encompass the entire window.
#
# The event set *ev* can be either:
# -- a cset or string specifying particular keypresses of interest
# -- one of the event keywords (&lpress, &rdrag, &resize, etc.)
#
# When a matching event occurs, proc(win,arg,x,y,e) is called. proc,
# win, and arg are as recorded from the sensor call. x and y give the
# current mouse position and e the event; for a keypress, this is the
# character.
#
# No event generates more than one procedure call.
# In the case of conflicting entries, the later registrant wins.
#
#
# evmux(win) -- loop forever, calling event handlers as appropriate.
# evhandle(win) -- wait for the next event, and handle it.
#
# evmux(win) is an infinite loop that calls user routines in response
# to window events. It is for programs that don't need to do other
# work while waiting for window input.
#
# evhandle(win) processes one event and then returns to its caller,
# allowing external loop control. evhandle returns the outcome of
# the handler proc, or fails if there is no handler for the event.
#
# quitsensor(win,wait) -- standardized "quit" sensor
#
# quitsensor() registers a sensor that calls exit() when any of these
# characters are typed in the window: Q, q, ^C, ^D, ^? (DEL).
#
# If wait is non-null, quitsensor does not return but just waits for
# the signal (useful in non-interactive display programs).
#
#
# argless(win,proc) -- call proc with no arguments.
#
# Useful for registering argless procedures as in quitsensor() above.
#
############################################################################
record evrec (ev, proc, arg, x, y, w, h)
global ewtab
## sensor(win,ev,proc,arg,x,y,w,h) -- register an event responder.
procedure sensor (win, ev, proc, arg, x, y, w, h)
local evlist, r, e
/ewtab := table()
/ewtab[win] := list()
evlist := ewtab[win]
/x := 0
/y := 0
/w := XAttrib (win, "width") - x
/h := XAttrib (win, "height") - y
if type(ev) == ("cset" | "string") then
ev := cset(ev)
else
ev := cset(evchar(ev)) | stop ("invalid event specification: ", image(ev))
push (evlist, r := evrec (ev, proc, arg, x, y, w, h))
return r
end
## evchar (e) -- map mouse event to character code.
#
# Internally, *all* events are single-character strings, and mouse & resizing
# events are mapped into characters that are never returned as keypress events.
procedure evchar (s)
return case s of {
&lpress: "\237" # mouse button 1 down
&mpress: "\236" # mouse button 2 down
&rpress: "\235" # mouse button 3 down
&lrelease: "\234" # mouse button 1 up
&mrelease: "\233" # mouse button 2 up
&rrelease: "\232" # mouse button 3 up
&ldrag: "\231" # mouse button 1 is dragging
&mdrag: "\230" # mouse button 2 is dragging
&rdrag: "\227" # mouse button 3 is dragging
&resize: "\226" # window has resized
}
fail
end
## evmux(win) -- loop forever, calling event handlers as appropriate.
## evhandle(win) -- wait for the next event, and handle it.
# produce result of the handler proc; fail if nobody handles.
procedure evmux (win)
repeat
evhandle (win)
end
procedure evhandle (win)
local x, y, ev, e, r, t
t := (\ewtab)[win] | stop ("no events registered for window")
ev := XEvent (win)
# convert event code to single character
if type(ev) == "integer" then
e := evchar(ev) | ""
else
e := ev
# find and call the first (most recent) matching handler
# (just a simple serial search)
every r := !t do
if any (r.ev, e) & ontarget (r, &x, &y) then
return r.proc (win, r.arg, &x, &y, ev)
fail
end
## ontarget (r, x, y) -- check if an event is within bounds
#
# checks that (x, y) are within the bounds of (r.x, r.y, r.w, r.h).
procedure ontarget (r, x, y)
return (x -:= r.x) >= 0 & x < r.w & (y -:= r.y) >= 0 & y < r.h
end
## quitsensor(win,wait) -- standardized "quit" sensor
procedure quitsensor (win, wait)
sensor (win, '\^c\^d\dqQ', argless, exit)
if \wait then evmux (win)
return
end
## argless(win,proc) -- call proc with no arguments.
procedure argless (win, proc)
return proc ()
end