Events
******

Epoch provides the ability to handle X Window System events in Elisp.

Event Basics
============

Events are the mechanism the X Window System uses to communicate with client programs such as Epoch.

Certain types of X events, listed below, are stored into a queue, the event-queue.  Whenever such an event is received by Epoch, it is stored in the event-queue, and an event-key is inserted into the keyboard buffer.  Whenever the keyboard is checked for keys, these event keys are read and processed until there are none left or an actual key is encountered.  For each of these events, the variable epoch::event is bound to the value of the event, and the event handler epoch::event-handler is called.  (see Basic Event Handling to learn more about that subject.)

Each event is returned as a vector of four elements.  The first is the event type, the second is data associated with the event, the third is the screen on which the event occured, and the fourth is the time-stamp indicating the time the event occured (this will be nil for focus, map, resize, and client-message events).

Epoch currently captures the events described in the following table:

Event
     Data

focus
     t for focus-in, nil for focus-out

property-change
     If epoch::lazy-events is nil, then a cons pair.  Car is name of property (a string), cdr is new value of property.  Otherwise, the value is just the X-atom resource of the property. (see Property Change Events)

selection-clear
     ATOM corresponding to selection name (see Selection Events).

map
     t for map, nil for unmap.

move
     Cons pair:  x-position, y-position in pixels.

resize
     List of three elements: new width, new height, outer borderwidth.

client-message
     A triple of the form (TYPE FROM . DATA).  See description of epoch::send-client-message below for an explanation.  (see Client Message Events).

button
     A 5-tuple of form (PRESS/RELEASE X-COORD Y-COORD BUTTON MOD-STATE).  (see Mouse Events)

motion
     A triplet of the form (X-COORD Y-COORD MOD-STATE). (see Motion Events).

To support asynchronous communication through events, Epoch provides primitives to set and read X Properties (see X Properties), and a property event handler.  Primitives are also provided to send client messages.

Client messages are sent through the epoch::send-client-message function and received through events of type client-message.

 -- Variable: epoch::lazy-events
     If this variable is non-nil, then the internal event code will do as little work as possible. Primarily, property events will only report the atom of the property changed, and leave it up to other code to acquire the value if desired.  (see Property Change Events)

 -- Variable: epoch::mouse-events
     If this variable is non-nil, then mouse events are placed into the Epoch event queue instead of generating fake key strokes.

Basic Event Handling
====================

Events are handled by binding the variable epoch::event-handler to a function of no arguments.  Whenever an event is dispatched as described above, if epoch::event-handler is non-nil, the value in it is called as a no argument function. This function should then examine the value of epoch::event and take appropriate action.

If any error occurs while the event handler is being executed, then the behavior depends on the value of the variable epoch::event-handler-abort.  If this is t, then the event-handler is aborted by resetting the variable to nil. This action prevents runaway errors on every following event.  If the variable epoch::event-handler-abort is nil then this action is not taken.

In order to make event handling easier, a standard set of event handling functions are provided.  These provide a (somewhat) widget-like interface to events.  Selected parts of the interface can be replaced without change to the underlying internals.  Event handling is organized hierarchially -- the top level handler invokes other handlers to dispatch the final handling routines.  The following description is from the top down.

The basic event handler maintains an internal alist to associate event types with event handlers.  An event type is the symbolic name corresponding to a class of X events.  An event handler is an Elisp function that may be called when an event occurs.

For each event type, a stack of event handlers is kept, and when an event of that type occurs, the function at the top of the stack is called with arguments showed below.  This allows you to change the event handler behavior in a restorable way.  Each basic event type must be installed before any events will be dispatched for it; this allows events to be globally disabled and reenabled.  Currently the Epoch Elisp files (see Packages) install all supported events.

When the basic handler runs, epoch::event-handler-abort is initially set to t.  It then watches for errors during the dispatch of an event, which are detected by checking epoch::event-handler after returning from the dispatch.  If epoch::event-handler has been set to nil, an error is presumed to have occured, and ignore-event is called on that event.  This provides improvements over the built-in system, in that only a particular type of event is ignored (others continue to dispatch), and service can be restored with a simple (resume-event EVENT), independent of the actual names of the handlers.  This also means that handlers can be anonymous, i.e. push-event can be passed a lambda expression instead of the symbol name of a function.

Event handler functions should be defined as follows:

     (defun my-event-handler (EVENT-TYPE VALUE SCREEN)
       "EVENT-TYPE is the type of the event.  VALUE is the value of
     the event, and SCREEN is the screen that received the event.
     Handlers can call the event handling interface routines, so that a
     one-shot handler (which pops itself) can be set up."
       )

The following functions and variables form the interface to the event handling system.

 -- Variable: epoch::event-handler
     Variable that contains nil or a function to be called when there are pending property change events.  The handler should use the variable epoch::event to retrieve the current event.  If epoch::event-handler has been set to nil after an event has been dispatched, an error is presumed to have occured (see above).

 -- Variable: epoch::event
     Just before the event handler in epoch::event-handler is called, this variable is bound to the value of the event that caused the handler call.  It is a vector of size four, consisting of the event type, the event value, the screen where the event occurred, and the event's timestamp (if available).

 -- Variable: epoch::event-handler-abort
     If this variable is non-nil, then if an error occurs while the event handler is running, epoch::event-handler is set to nil.  This prevents an error in some part of the event handler code from causing Epoch to lock up with excessive errors.

 -- Function: epoch::get-event
     All events are stored in an internal event queue. This primitive returns the oldest event in the event queue as an Elisp vector of size three. The zeroth element is the type of the event, the first element is the value of the event, the second element is the screen on which the event occurred, and the third element is the event's timestamp (if available).

 -- Function: install-event event
     This puts EVENT into the handler alist.  EVENT can be anything, but unless it is eq to an event type, it will never be dispatched; instead it will be ignored.

 -- Function: remove-event event
     Removes EVENT from the handler alist.  All handlers associated with it are lost.

 -- Function: push-event event handler
     Installs HANDLER for EVENT.  Handlers are installed in a stack, and the handler at the top of the stack is dispatched for the event.

 -- Function: pop-event event
     Removes and returns the top level handler for EVENT.

 -- Function: ignore-event event
     Pushes a marker onto the handler stack for EVENT so that the event is not dispatched.

 -- Function: resume-event event
     Pops the ignore marker from the top of the handler stack for EVENT.  Note that these two functions are different from remove-event and install-event in that these allow temporary, transparent inhibition of events in a local area, while the latter have global effects.

 -- Function: display-event-status
     Print the current event handler status into a buffer and display it in a window on the current screen.  Normally bound to C-z e.  The status keys are H for being handled, I for ignored, and U for uninstalled.  If a number follows the letter, that is the depth of the handlers or ignore markers.

Advanced Event Handling
=======================

In addition to the standard event handling facilities just described, it is occasionally necessary to specially handle certain event types.

 -- Function: epoch::wait-for-event event-type handler
     This primitive will wait for an EVENT-TYPE type to occur, and then call handler if non NIL.  handler should be a function defined similarly to other event handler functions see Basic Event Handling.  Any other events which are received during the wait are stored and dispatched in the order of arrival after the desired event has occured.  The function will return after this has occured. Note: This function could cause deadlock if the selected event type does not occur.

Property Change Events
======================

The Epoch Elisp files set up a handler for the property-change event which then dispatches based on the property, in a manner analagous to the basic event handling.  This property event handler uses lazy events (see epoch::lazy-events in see Basic Event Handling.) This means that a property change event has a value of just the X-atom resource corresponding to the property that changed.

     Implementation note: Property events are passed as lazy events to save the expense of unneeded round-trip server requests.  With non-lazy events, all property events would involve two round-trip requests, one for the atom and another for the value.  However, most property events are not handled, and so such information is simply thrown away.  With this system, only those property events that are actually dispatched invoke this expense, and in many cases the name of the property is unnecessary.  (If the handler function is attached to only one property, then it implicitly knows the property name value.)  The primitive equal has been extended to provide comparisons for X Resources (see X Resources).

Each installed property is stored as the X-atom resource and a stack of handlers.  If the top entry is a function, then it is called with the same parameters as for basic event handling.  (The event type will always be property-change, but this allows a consistent handler interface for all handler functions.)  If the property is not in the alist, or the top entry is not a function, the property change is ignored.

In contrast to basic event handling, if the property is not installed, pushing the property handler will install it.  The inhibition of handling for certain properties is not as useful as for events.  Since the number of possible property events is far larger than the number of possible event types, the extra hassle of having to seperately install properties was judged to be too much.  The install-property and remove-property should be used seldom, if at all, and are provided primarily for conformity with basic event handling.

Property change handler functions should be of the same form as the general event handlers.  Note that the value of the property change is passed as an X-atom.  If the value of the property is desired, the function get-property can be used.  If the name of the property is needed, use unintern-atom.

One way that property change events can be used is to send messages to and receive messages from the window manager.  We use this facility extensively to display menus to the user, change window names and decorations, etc.  X properties are manipulated and accessed through the epoch::set-property and epoch::get-property functions (see X Properties).

Epoch maintains two properties on the screens automatically.  These are EPOCH_SCREEN_ID, which is an integer that is the screen ID, and EPOCH_CURRENT, which is a string, either ``yes'' if that screen is the current edit screen, ``no'' if it is not, or ``minibuf'' if it is the minibuffer.

The following functions are the interface to the property event handling system.

 -- Function: install-property property
     This puts PROPERTY into the handler alist.  PROPERTY should be the name of an X Property (i.e. a string or X Atom).

 -- Function: remove-property property
     Removes PROPERTY from the handler alist.  All handlers associated with it are lost.

 -- Function: push-property property handler
     Installs HANDLER for PROPERTY.  Handlers are installed in a stack, and the handler at the top of the stack is dispatched for the property.  If the property is not already in the handler list, it is added.

 -- Function: pop-property property
     Removes and returns the top level handler for PROPERTY.

 -- Function: ignore-property property
     Pushes a marker onto the handler stack for PROPERTY so that the property is not dispatched.

 -- Function: resume-property property
     Pops the ignore marker from the top of the handler stack for PROPERTY.

Selection Events
================

There are three types of events associated with X11 selections, two of which may be handled in Elisp (see X Selections). selection-clear events are handled based on selection name with a handler similar to other events.  selection-request events are handled internally unless the requested target atom is non-standard.

 -- Variable: epoch::convert-selection-hook convert-to-target
     The function named by this hook will be called for any selection-requests with non-standard target atoms.

 -- Function: add-selection-target target function
     Adds TARGET to list of user-defined target atoms.  FUNCTION will be called for conversion requests of this type.

 -- Function: convert-to-target target
     Called by epoch::convert-selection-hook to call appropriate conversion function based on TARGET.  If no function exists, return nil.

 -- Function: install-selection selection
     Puts SELECTION on handler alist.  SELECTION should be the name of an X Selection (i.e. a string or X Atom).

 -- Function: remove-selection selection
     Removes SELECTION from handler alist.  All handlers associated with it are lost.

 -- Function: push-selection selection handler
     Installs HANDLER for SELECTION.  Handlers are installed in a stack, with the handler at the top of the stack is dispatched for the selection.  If the selection is not already on the handler list, it is added.

 -- Function: pop-selection selection
     Removes and returns the top level handler for SELECTION.

 -- Function: ignore-selection selection
     Pushes a marker onto the handler stack for SELECTION so that the selection is not dispatched.

 -- Function: resume-selection selection
     Pops the ignore marker from the top of the handler stack for SELECTION.

Note: If no handler is installed for a given selection, then selection-clear events received will be handled generically, with any data for that selection being deleted from epoch::selection-alist.  If a handler has been installed for a selection, it is the responsibility of that handler to remove data from epoch::selection-alist if this behavior is desired.

Client Message Events
=====================

The Epoch Elisp files set up a handler for the client-message event which then dispatches based on the message type.  Each installed property is stored as the X-atom resource and a stack of handlers.  If the top entry is a function, then it is called, with the same parameters as for basic event handling.  If the message type is not in the alist, or the top entry is not a function, the message is ignored.

The value of a client message is a list of ( TYPE SOURCE . DATA ) where TYPE is the message type X-atom resource, SOURCE is an X-window resource specifying the source window, and DATA is the data field of the message converted to Elisp data in the same manner as X property values (see X Properties).  To send client mesages, see Client Messages.

If the message type is not installed, pushing a handler will install it. install-message and remove-message should be used seldom, if at all, and are provided primarily for conformity with basic event handling.

The following functions are the interface to the client message event handling system.

 -- Function: install-message message
     This puts MESSAGE into the handler alist.  MESSAGE should be either a string or X Atom.

 -- Function: remove-message message
     Removes MESSAGE from the handler alist.  All handlers associated with it are lost.

 -- Function: push-message message handler
     Installs HANDLER for MESSAGE.  Handlers are installed in a stack, and the handler at the top of the stack is dispatched for the message.  If the message is not already in the handler list, it is added.

 -- Function: pop-message message
     Removes and returns the top level handler for MESSAGE.

 -- Function: ignore-message message
     Pushes an ignore marker onto the handler stack for MESSAGE so that the message is not dispatched.

 -- Function: resume-message message
     Pops the ignore marker from the top of the handler stack for MESSAGE.

Mouse Events
============

Mouse events go into the event queue with event type button and event value the 5-tuple (PRESS/RELEASE X-COORD Y-COORD BUTTON MOD-STATE).  PRESS/RELEASE indicates if the event was a button press or release; the coordinates are character coordinates within the screen; BUTTON indicates which button; and the MOD-STATE is a bitmask indicating the state of the button modifiers.

Note: Mouse events are only received on the keyboard queue when epoch::mouse-events is nil.  This is the default value, but the Epoch Elisp files set it to t.

The Epoch Elisp files install a handler for the button events, which in turn dispatches functions for each different mouse event.

Mouse event dispatching uses two tables, one global and the other local to each buffer.  When a mouse event is dispatched, the local table is checked first.  If the table is missing or the entry is nil, then the global table is used.  If a function is found, then it is dispatched.  The mouse event handler should be defined as follows:

     (defun my-mouse-handler (MOUSE-DATA)
       "MOUSE-DATA is a list of ( POINT BUFFER WINDOW SCREEN ).
     These all refer to the character location at which the button on the
     mouse was pressed or released.  Note that at the time the handler is
     called, no change to point, current buffer, current window or
     current screen has been made.  It is entirely up to the handler how much
     to change such information.")

When specifying a particular mouse event, both the mouse button and keyboard modifier states must be specified, e.g., the middle button with Control.  Note that separate mouse button codes exist for button presses in the window, mode line, and minibuffer.  These values are specified as numbers, but for ease of programming, constants are defined for them, listed below.

These are the predefined constants for specifying the mouse button:  Note that these match codes in mouse::event-data.

Name
     Value

mouse-left
     1

mouse-middle
     2

mouse-right
     3

mouse-mode-left
     4

mouse-mode-middle
     5

mouse-mode-right
     6

mouse-minibuf-left
     7

mouse-minibuf-middle
     8

mouse-minibuf-right
     9

These are the predefined constants for specifying the keyboard modifier state. Names without a trailing -up signify the down button event.

Name
     Value

mouse-down
     0

mouse-up
     1

mouse-shift
     2

mouse-shift-up
     3

mouse-control
     4

mouse-control-up
     5

mouse-control-shift
     6

mouse-control-shift-up
     7

mouse-meta
     8

mouse-meta-up
     9

mouse-meta-shift
     10

mouse-meta-shift-up
     11

mouse-meta-control
     12

mouse-meta-control-up
     13

mouse-meta-control-shift
     14

mouse-meta-control-shift-up
     15

Note: In that version, the passed argument was a list of the form (X Y SCREEN) of the mouse event.  This data was not particularly useful, and had to be converted into more useful data by actually setting point with the x-mouse-set-point call.  A look through the mouse handling code indicated that, in fact, every function went ahead and did this in order to calculate the point.

The following functions are modeled after keymaps.

 -- Function: create-mouse-map &optional source-map
     Creates a mouse map for use in dispatching.  If SOURCE-MAP is non-nil, then the contents of that map are copied into the new map.

 -- Function: copy-mouse-map source-map dest-map
     Copies a mouse map from SOURCE-MAP to DEST-MAP.

 -- Function: use-local-mouse-map mouse-map &optional buffer
     Sets MOUSE-MAP to be the local mouse map in BUFFER.

 -- Function: kill-local-mouse-map &optional buffer
     Removes the local mouse map from BUFFER.

 -- Function: define-mouse mouse-map button modifier function
     Sets the entry in MOUSE-MAP for the mouse BUTTON with MODIFIER to be FUNCTION.  BUTTON should be one of the mouse button constants, and MODIFIER should be one of the button modifiers.

 -- Function: local-set-mouse button modifier function
     Sets the entry in the local mouse map for BUTTON and MODIFIER to FUNCTION.

 -- Function: global-set-mouse button modifier function
     Sets the entry in the global mouse map for BUTTON and MODIFIER to FUNCTION.

 -- Function: mouse::set-point mouse-data
     Sets the point to the value specified in MOUSE-DATA, which should be the same form as the list passed to mouse handler functions, (point buffer window screen)

 -- Function: coordinates-in-window-p position window
     Returns t if position described by POSITION is in WINDOW.  POSITION is a list of the form (screen-x screen-y).

 -- Function: epoch::coords-to-point x y screen
     Converts a pixel (X, Y) location on a given SCREEN into a list of the form (point buffer window screen) or nil if the location is not on the SCREEN.  POINT is returned as nil if location is in window's modeline.

Data pertaining to the most recent button press event is available in the following variables.  Note that this enables the detection of multiple mouse clicks.

 -- Variable: mouse::interval 200
     The number of milliseconds allowed between multiple mouse clicks. Interval is clocked between down-click and the previous up-click.

 -- Variable: mouse::x
     X screen position of last mouse button press, in pixels.

 -- Variable: mouse::y
     Y screen position of last mouse button press, in pixels.

 -- Variable: mouse::last-spot
     Mouse data of the last event (point buffer window screen).

 -- Variable: mouse::time-stamp
     Millisecond time of the last up-click.

 -- Variable: mouse::clicks
     The number of times mouse button was pressed and released.

Motion Events
=============

Epoch allows the user to receive motion events, which occur when the mouse moves.  By default this feature is turned off.  It can be enabled in a number of ways:

  * By using command line option -motion: makes motion events appear for all screens.

  * By using *motion in resources: makes motion events appear for all screens.

  * By using motion in the property alist; t turns on motion events at screen creation time, nil disables them.

  * By using primitive epoch::set-motion-hints: turns motion events on or off by screen.

Note that motion events go into the event-queue but must be specifically solicited by functions rather than being automatically provided.  Each time you execute a function affecting the mouse (for example, epoch::query-pointer), the next motion event (if any) is sent to the primitive.  This prevents motion events from coming so fast that Epoch would thrash to death.

The relevant primitives are:

 -- Function: epoch::motion-hints-p &optional screen
     Returns t or nil for SCREEN (default: current screen) depending if motion events are enabled or disabled for that screen.

 -- Function: epoch::set-motion-hints flag &optional screen
     Flag must be t or nil; enables or disables motion hints for SCREEN (default: current screen).

On Event Handling
=================

As part of the standard event handling, a facility to install one-shot handlers for events on particular screens is provided.  After the action function has been called for the particular event, it is removed.

 -- Function: on-map-do screen action
     On the next map event for SCREEN, call ACTION with a single argument that is the screen of the event.

 -- Function: on-unmap-do screen action
     On the next unmap event for SCREEN, call ACTION with a single argument that is the screen of the event.

 -- Function: on-move-do screen action
     On the next move event for SCREEN, call ACTION with two arguments, the screen and the move event value.

 -- Function: on-resize-do screen action
     On the next resize event for SCREEN, call ACTION with two arguments, the screen and the resize event value.