[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36. Events and the Event Loop

36.1 Introduction to Events  
36.2 Main Loop  
36.3 Specifics of the Event Gathering Mechanism  
36.4 Specifics About the Emacs Event  
36.5 Event Queues  
36.6 Event Stream Callback Routines  
36.7 Other Event Loop Functions  
36.8 Stream Pairs  
36.9 Converting Events  
36.10 Dispatching Events; The Command Builder  
36.11 Focus Handling  
36.12 Editor-Level Control Flow Modules  


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.1 Introduction to Events

An event is an object that encapsulates information about an interesting occurrence in the operating system. Events are generated either by user action, direct (e.g. typing on the keyboard or moving the mouse) or indirect (moving another window, thereby generating an expose event on an Emacs frame), or as a result of some other typically asynchronous action happening, such as output from a subprocess being ready or a timer expiring. Events come into the system in an asynchronous fashion (typically through a callback being called) and are converted into a synchronous event queue (first-in, first-out) in a process that we will call collection.

Note that each application has its own event queue. (It is immaterial whether the collection process directly puts the events in the proper application's queue, or puts them into a single system queue, which is later split up.)

The most basic level of event collection is done by the operating system or window system. Typically, XEmacs does its own event collection as well. Often there are multiple layers of collection in XEmacs, with events from various sources being collected into a queue, which is then combined with other sources to go into another queue (i.e. a second level of collection), with perhaps another level on top of this, etc.

XEmacs has its own types of events (called Emacs events), which provides an abstract layer on top of the system-dependent nature of the most basic events that are received. Part of the complex nature of the XEmacs event collection process involves converting from the operating-system events into the proper Emacs events--there may not be a one-to-one correspondence.

Emacs events are documented in `events.h'; I'll discuss them later.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.2 Main Loop

The command loop is the top-level loop that the editor is always running. It loops endlessly, calling next-event to retrieve an event and dispatch-event to execute it. dispatch-event does the appropriate thing with non-user events (process, timeout, magic, eval, mouse motion); this involves calling a Lisp handler function, redrawing a newly-exposed part of a frame, reading subprocess output, etc. For user events, dispatch-event looks up the event in relevant keymaps or menubars; when a full key sequence or menubar selection is reached, the appropriate function is executed. dispatch-event may have to keep state across calls; this is done in the "command-builder" structure associated with each console (remember, there's usually only one console), and the engine that looks up keystrokes and constructs full key sequences is called the command builder. This is documented elsewhere.

The guts of the command loop are in command_loop_1(). This function doesn't catch errors, though--that's the job of command_loop_2(), which is a condition-case (i.e. error-trapping) wrapper around command_loop_1(). command_loop_1() never returns, but may get thrown out of.

When an error occurs, cmd_error() is called, which usually invokes the Lisp error handler in command-error; however, a default error handler is provided if command-error is nil (e.g. during startup). The purpose of the error handler is simply to display the error message and do associated cleanup; it does not need to throw anywhere. When the error handler finishes, the condition-case in command_loop_2() will finish and command_loop_2() will reinvoke command_loop_1().

command_loop_2() is invoked from three places: from initial_command_loop() (called from main() at the end of internal initialization), from the Lisp function recursive-edit, and from call_command_loop().

call_command_loop() is called when a macro is started and when the minibuffer is entered; normal termination of the macro or minibuffer causes a throw out of the recursive command loop. (To execute-kbd-macro for macros and exit for minibuffers. Note also that the low-level minibuffer-entering function, read-minibuffer-internal, provides its own error handling and does not need command_loop_2()'s error encapsulation; so it tells call_command_loop() to invoke command_loop_1() directly.)

Note that both read-minibuffer-internal and recursive-edit set up a catch for exit; this is why abort-recursive-edit, which throws to this catch, exits out of either one.

initial_command_loop(), called from main(), sets up a catch for top-level when invoking command_loop_2(), allowing functions to throw all the way to the top level if they really need to. Before invoking command_loop_2(), initial_command_loop() calls top_level_1(), which handles all of the startup stuff (creating the initial frame, handling the command-line options, loading the user's `.emacs' file, etc.). The function that actually does this is in Lisp and is pointed to by the variable top-level; normally this function is normal-top-level. top_level_1() is just an error-handling wrapper similar to command_loop_2(). Note also that initial_command_loop() sets up a catch for top-level when invoking top_level_1(), just like when it invokes command_loop_2().


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.3 Specifics of the Event Gathering Mechanism

Here is an approximate diagram of the collection processes at work in XEmacs, under TTY's (TTY's are simpler than X so we'll look at this first):

 
 asynch.      asynch.    asynch.   asynch.             [Collectors in
kbd events  kbd events   process   process                the OS]
      |         |         output    output
      |         |           |         |
      |         |           |         |      SIGINT,   [signal handlers
      |         |           |         |      SIGQUIT,     in XEmacs]
      V         V           V         V      SIGWINCH,
     file      file        file      file    SIGALRM
     desc.     desc.       desc.     desc.     |
     (TTY)     (TTY)       (pipe)    (pipe)    |
      |          |          |         |      fake    timeouts
      |          |          |         |      file        |
      |          |          |         |      desc.       |
      |          |          |         |      (pipe)      |
      |          |          |         |        |         |
      |          |          |         |        |         |
      |          |          |         |        |         |
      V          V          V         V        V         V
      ------>-----------<----------------<----------------
                  |
                  |
                  | [collected using select() in emacs_tty_next_event()
                  |  and converted to the appropriate Emacs event]
                  |
                  |
                  V          (above this line is TTY-specific)
                Emacs -----------------------------------------------
                event (below this line is the generic event mechanism)
                  |
                  |
was there     if not, call
a SIGINT?  emacs_tty_next_event()
    |             |
    |             |
    |             |
    V             V
    --->------<----
           |
           |     [collected in event_stream_next_event();
           |      SIGINT is converted using maybe_read_quit_event()]
           V
         Emacs
         event
           |
           \---->------>----- maybe_kbd_translate() ---->---\
                                                            |
                                                            |
                                                            |
     command event queue                                    |
                                               if not from command
  (contains events that were                   event queue, call
  read earlier but not processed,              event_stream_next_event()
  typically when waiting in a                               |
  sit-for, sleep-for, etc. for                              |
 a particular event to be received)                         |
               |                                            |
               |                                            |
               V                                            V
               ---->------------------------------------<----
                                               |
                                               | [collected in
                                               |  next_event_internal()]
                                               |
 unread-     unread-       event from          |
 command-    command-       keyboard       else, call
 events      event           macro      next_event_internal()
   |           |               |               |
   |           |               |               |
   |           |               |               |
   V           V               V               V
   --------->----------------------<------------
                     |
                     |      [collected in next-event, which may loop
                     |       more than once if the event it gets is on
                     |       a dead frame, device, etc.]
                     |
                     |
                     V
            feed into top-level event loop,
            which repeatedly calls next-event
            and then dispatches the event
            using dispatch-event

Notice the separation between TTY-specific and generic event mechanism. When using the Xt-based event loop, the TTY-specific stuff is replaced but the rest stays the same.

It's also important to realize that only one different kind of system-specific event loop can be operating at a time, and must be able to receive all kinds of events simultaneously. For the two existing event loops (implemented in `event-tty.c' and `event-Xt.c', respectively), the TTY event loop only handles TTY consoles, while the Xt event loop handles both TTY and X consoles. This situation is different from all of the output handlers, where you simply have one per console type.

Here's the Xt Event Loop Diagram (notice that below a certain point, it's the same as the above diagram):

 
asynch. asynch. asynch. asynch.                 [Collectors in
 kbd     kbd    process process                    the OS]
events  events  output  output
  |       |       |       |
  |       |       |       |     asynch. asynch. [Collectors in the
  |       |       |       |       X        X     OS and X Window System]
  |       |       |       |     events  events
  |       |       |       |       |        |
  |       |       |       |       |        |
  |       |       |       |       |        |    SIGINT, [signal handlers
  |       |       |       |       |        |    SIGQUIT,   in XEmacs]
  |       |       |       |       |        |    SIGWINCH,
  |       |       |       |       |        |    SIGALRM
  |       |       |       |       |        |       |
  |       |       |       |       |        |       |
  |       |       |       |       |        |       |      timeouts
  |       |       |       |       |        |       |          |
  |       |       |       |       |        |       |          |
  |       |       |       |       |        |       V          |
  V       V       V       V       V        V      fake        |
 file    file    file    file    file     file    file        |
 desc.   desc.   desc.   desc.   desc.    desc.   desc.       |
 (TTY)   (TTY)   (pipe)  (pipe) (socket) (socket) (pipe)      |
  |       |       |       |       |        |       |          |
  |       |       |       |       |        |       |          |
  |       |       |       |       |        |       |          |
  V       V       V       V       V        V       V          V
  --->----------------------------------------<---------<------
       |              |               |
       |              |               |[collected using select() in
       |              |               | _XtWaitForSomething(), called
       |              |               | from XtAppProcessEvent(), called
       |              |               | in emacs_Xt_next_event();
       |              |               | dispatched to various callbacks]
       |              |               |
       |              |               |
  emacs_Xt_        p_s_callback(),    | [popup_selection_callback]
  event_handler()  x_u_v_s_callback(),| [x_update_vertical_scrollbar_
       |           x_u_h_s_callback(),|  callback]
       |           search_callback()  | [x_update_horizontal_scrollbar_
       |              |               |  callback]
       |              |               |
       |              |               |
  enqueue_Xt_       signal_special_   |
  dispatch_event()  Xt_user_event()   |
  [maybe multiple     |               |
   times, maybe 0     |               |
   times]             |               |
       |            enqueue_Xt_       |
       |            dispatch_event()  |
       |              |               |
       |              |               |
       V              V               |
       -->----------<--               |
              |                       |
              |                       |
           dispatch             Xt_what_callback()
           event                  sets flags
           queue                      |
              |                       |
              |                       |
              |                       |
              |                       |
              ---->-----------<--------
                   |
                   |
                   |     [collected and converted as appropriate in
                   |            emacs_Xt_next_event()]
                   |
                   |
                   V          (above this line is Xt-specific)
                 Emacs ------------------------------------------------
                 event (below this line is the generic event mechanism)
                   |
                   |
was there      if not, call
a SIGINT?   emacs_Xt_next_event()
    |              |
    |              |
    |              |
    V              V
    --->-------<----
           |
           |        [collected in event_stream_next_event();
           |         SIGINT is converted using maybe_read_quit_event()]
           V
         Emacs
         event
           |
           \---->------>----- maybe_kbd_translate() -->-----\
                                                            |
                                                            |
                                                            |
     command event queue                                    |
                                              if not from command
  (contains events that were                  event queue, call
  read earlier but not processed,             event_stream_next_event()
  typically when waiting in a                               |
  sit-for, sleep-for, etc. for                              |
 a particular event to be received)                         |
               |                                            |
               |                                            |
               V                                            V
               ---->----------------------------------<------
                                               |
                                               | [collected in
                                               |  next_event_internal()]
                                               |
 unread-     unread-       event from          |
 command-    command-       keyboard       else, call
 events      event           macro      next_event_internal()
   |           |               |               |
   |           |               |               |
   |           |               |               |
   V           V               V               V
   --------->----------------------<------------
                     |
                     |      [collected in next-event, which may loop
                     |       more than once if the event it gets is on
                     |       a dead frame, device, etc.]
                     |
                     |
                     V
            feed into top-level event loop,
            which repeatedly calls next-event
            and then dispatches the event
            using dispatch-event


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.4 Specifics About the Emacs Event


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.5 Event Queues

There are two event queues here -- the command event queue (#### which should be called "deferred event queue" and is in my glyph ws) and the dispatch event queue. (MS Windows actually has an extra dispatch queue for non-user events and uses the generic one only for user events. This is because user and non-user events in Windows come through the same place -- the window procedure -- but under X, it's possible to selectively process events such that we take all the user events before the non-user ones. #### In fact, given the way we now drain the queue, we might need two separate queues, like under Windows. Need to think carefully exactly how this works, and should certainly generalize the two different queues.

The dispatch queue (which used to occur duplicated inside of each event implementation) is used for events that have been read from the window-system event queue(s) and not yet process by next_event_internal(). It exists for two reasons: (1) because in many implementations, events often come from the window system by way of callbacks, and need to push the event to be returned onto a queue; (2) in order to handle QUIT in a guaranteed correct fashion without resorting to weird implementation-specific hacks that may or may not work well, we need to drain the window-system event queues and then look through to see if there's an event matching quit-char (usually ^G). the drained events need to go onto a queue. (There are other, similar cases where we need to drain the pending events so we can look ahead -- for example, checking for pending expose events under X to avoid excessive server activity.)

The command event queue is used AFTER an event has been read from next_event_internal(), when it needs to be pushed back. This includes, for example, accept-process-output, sleep-for and wait_delaying_user_input(). Eval events and the like, generated by enqueue-eval-event, enqueue_magic_eval_event(), etc. are also pushed onto this queue. Some events generated by callbacks are also pushed onto this queue, #### although maybe shouldn't be.

The command queue takes precedence over the dispatch queue.

#### It is worth investigating to see whether both queues are really needed, and how exactly they should be used. enqueue-eval-event, for example, could certainly push onto the dispatch queue, and all callbacks maybe should. wait_delaying_user_input() seems to need both queues, since it can take events from the dispatch queue and push them onto the command queue; but it perhaps could be rewritten to avoid this. #### In general we need to review the handling of these two queues, figure out exactly what ought to be happening, and document it.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.6 Event Stream Callback Routines

There is one object called an event_stream. This object contains callback functions for doing the window-system-dependent operations that XEmacs requires.

If XEmacs is compiled with support for X11 and the X Toolkit, then this event_stream structure will contain functions that can cope with input on XEmacs windows on multiple displays, as well as input from dumb tty frames.

If it is desired to have XEmacs able to open frames on the displays of multiple heterogeneous machines, X11 and SunView, or X11 and NeXT, for example, then it will be necessary to construct an event_stream structure that can cope with the given types. Currently, the only implemented event_streams are for dumb-ttys, and for X11 plus dumb-ttys, and for mswindows.

To implement this for one window system is relatively simple. To implement this for multiple window systems is trickier and may not be possible in all situations, but it's been done for X and TTY.

Note that these callbacks are NOT console methods; that's because the routines are not specific to a particular console type but must be able to simultaneously cope with all allowable console types.

The slots of the event_stream structure:

next_event_cb
A function which fills in an XEmacs_event structure with the next event available. If there is no event available, then this should block.

IMPORTANT: timer events and especially process events *must not* be returned if there are events of other types available; otherwise you can end up with an infinite loop in Fdiscard_input().

event_pending_cb
A function which says whether there are events to be read. If called with an argument of 0, then this should say whether calling the next_event_cb will block. If called with a non-zero argument, then this should say whether there are that many user-generated events pending (that is, keypresses, mouse-clicks, dialog-box selection events, etc.). (This is used for redisplay optimization, among other things.) The difference is that the former includes process events and timer events, but the latter doesn't.

If this function is not sure whether there are events to be read, it must return 0. Otherwise various undesirable effects will occur, such as redisplay not occurring until the next event occurs.

handle_magic_event_cb
XEmacs calls this with an event structure which contains window-system dependent information that XEmacs doesn't need to know about, but which must happen in order. If the next_event_cb never returns an event of type "magic", this will never be used.

format_magic_event_cb
Called with a magic event; print a representation of the innards of the event to PSTREAM.

compare_magic_event_cb
Called with two magic events; return non-zero if the innards of the two are equal, zero otherwise.

hash_magic_event_cb
Called with a magic event; return a hash of the innards of the event.

add_timeout_cb
Called with an EMACS_TIME, the absolute time at which a wakeup event should be generated; and a void *, which is an arbitrary value that will be returned in the timeout event. The timeouts generated by this function should be one-shots: they fire once and then disappear. This callback should return an int id-number which uniquely identifies this wakeup. If an implementation doesn't have microseconds or millisecond granularity, it should round up to the closest value it can deal with.

remove_timeout_cb
Called with an int, the id number of a wakeup to discard. This id number must have been returned by the add_timeout_cb. If the given wakeup has already expired, this should do nothing.

select_process_cb
unselect_process_cb
These callbacks tell the underlying implementation to add or remove a file descriptor from the list of fds which are polled for inferior-process input. When input becomes available on the given process connection, an event of type "process" should be generated.

select_console_cb
unselect_console_cb
These callbacks tell the underlying implementation to add or remove a console from the list of consoles which are polled for user-input.

select_device_cb
unselect_device_cb
These callbacks are used by Unixoid event loops (those that use select() and file descriptors and have a separate input fd per device).

create_io_streams_cb
delete_io_streams_cb
These callbacks are called by process code to create the input and output lstreams which are used for subprocess I/O.

quitp_cb
A handler function called from the QUIT macro which should check whether the quit character has been typed. On systems with SIGIO, this will not be called unless the sigio_happened flag is true (it is set from the SIGIO handler).

XEmacs has its own event structures, which are distinct from the event structures used by X or any other window system. It is the job of the event_stream layer to translate to this format.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.7 Other Event Loop Functions

detect_input_pending() and input-pending-p look for input by calling event_stream->event_pending_p and looking in [V]unread-command-event and the command_event_queue (they do not check for an executing keyboard macro, though).

discard-input cancels any command events pending (and any keyboard macros currently executing), and puts the others onto the command_event_queue. There is a comment about a "race condition", which is not a good sign.

next-command-event and read-char are higher-level interfaces to next-event. next-command-event gets the next command event (i.e. keypress, mouse event, menu selection, or scrollbar action), calling dispatch-event on any others. read-char calls next-command-event and uses event_to_character() to return the character equivalent. With the right kind of input method support, it is possible for (read-char) to return a Kanji character.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.8 Stream Pairs

Since there are many possible processes/event loop combinations, the event code is responsible for creating an appropriate lstream type. The process implementation does not care about that implementation.

The Create stream pair function is passed two void* values, which identify process-dependent 'handles'. The process implementation uses these handles to communicate with child processes. The function must be prepared to receive handle types of any process implementation. Since only one process implementation exists in a particular XEmacs configuration, preprocessing is a means of compiling in the support for the code which deals with particular handle types.

For example, a unixoid type loop, which relies on file descriptors, may be asked to create a pair of streams by a unix-style process implementation. In this case, the handles passed are unix file descriptors, and the code may deal with these directly. Although, the same code may be used on Win32 system with X-Windows. In this case, Win32 process implementation passes handles of type HANDLE, and the create_io_streams function must call appropriate function to get file descriptors given HANDLEs, so that these descriptors may be passed to XtAddInput.

The handle given may have special denying value, in which case the corresponding lstream should not be created.

The return value of the function is a unique stream identifier. It is used by processes implementation, in its platform-independent part. There is the get_process_from_usid function, which returns process object given its USID. The event stream is responsible for converting its internal handle type into USID.

Example is the TTY event stream. When a file descriptor signals input, the event loop must determine process to which the input is destined. Thus, the implementation uses process input stream file descriptor as USID, by simply casting the fd value to USID type.

There are two special USID values. One, USID_ERROR, indicates that the stream pair cannot be created. The second, USID_DONTHASH, indicates that streams are created, but the event stream does not wish to be able to find the process by its USID. Specifically, if an event stream implementation never calls get_process_from_usid, this value should always be returned, to prevent accumulating useless information on USID to process relationship.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.9 Converting Events

character_to_event(), event_to_character(), event-to-character, and character-to-event convert between characters and keypress events corresponding to the characters. If the event was not a keypress, event_to_character() returns -1 and event-to-character returns nil. These functions convert between character representation and the split-up event representation (keysym plus mod keys).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.10 Dispatching Events; The Command Builder

Not yet documented.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.11 Focus Handling

Ben's capsule lecture on focus:

In GNU Emacs select-frame never changes the window-manager frame focus. All it does is change the "selected frame". This is similar to what happens when we call select-device or select-console. Whenever an event comes in (including a keyboard event), its frame is selected; therefore, evaluating select-frame in `*scratch*' won't cause any effects because the next received event (in the same frame) will cause a switch back to the frame displaying `*scratch*'.

Whenever a focus-change event is received from the window manager, it generates a switch-frame event, which causes the Lisp function handle-switch-frame to get run. This basically just runs select-frame (see below, however).

In GNU Emacs, if you want to have an operation run when a frame is selected, you supply an event binding for switch-frame (and then maybe call handle-switch-frame, or something ...).

In XEmacs, we do change the window-manager frame focus as a result of select-frame, but not until the next time an event is received, so that a function that momentarily changes the selected frame won't cause WM focus flashing. (#### There's something not quite right here; this is causing the wrong-cursor-focus problems that you occasionally see. But the general idea is correct.) This approach is winning for people who use the explicit-focus model, but is trickier to implement.

We also don't make the switch-frame event visible but instead have select-frame-hook, which is a better approach.

There is the problem of surrogate minibuffers, where when we enter the minibuffer, you essentially want to temporarily switch the WM focus to the frame with the minibuffer, and switch it back when you exit the minibuffer.

GNU Emacs solves this with the crockish redirect-frame-focus, which says "for keyboard events received from FRAME, act like they're coming from FOCUS-FRAME". I think what this means is that, when a keyboard event comes in and the event manager is about to select the event's frame, if that frame has its focus redirected, the redirected-to frame is selected instead. That way, if you're in a minibufferless frame and enter the minibuffer, then all Lisp functions that run see the selected frame as the minibuffer's frame rather than the minibufferless frame you came from, so that (e.g.) your typing actually appears in the minibuffer's frame and things behave sanely.

There's also some weird logic that switches the redirected frame focus from one frame to another if Lisp code explicitly calls select-frame (but not if handle-switch-frame is called), and saves and restores the frame focus in window configurations, etc. etc. All of this logic is heavily #if 0'd, with lots of comments saying "No, this approach doesn't seem to work, so I'm trying this ... is it reasonable? Well, I'm not sure ..." that are a red flag indicating crockishness.

Because of our way of doing things, we can avoid all this crock. Keyboard events never cause a select-frame (who cares what frame they're associated with? They come from a console, only). We change the actual WM focus to a surrogate minibuffer frame, so we don't have to do any internal redirection. In order to get the focus back, I took the approach in `minibuf.el' of just checking to see if the frame we moved to is still the selected frame, and move back to the old one if so. Conceivably we might have to do the weird "tracking" that GNU Emacs does when select-frame is called, but I don't think so. If the selected frame moved from the minibuffer frame, then we just leave it there, figuring that someone knows what they're doing. Because we don't have any redirection recorded anywhere, it's safe to do this, and we don't end up with unwanted redirection.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

36.12 Editor-Level Control Flow Modules

 
`event-Xt.c'
`event-msw.c'
`event-stream.c'
`event-tty.c'
`events-mod.h'
`gpmevent.c'
`gpmevent.h'
`events.c'
`events.h'

These implement the handling of events (user input and other system notifications).

`events.c' and `events.h' define the event Lisp object type and primitives for manipulating it.

`event-stream.c' implements the basic functions for working with event queues, dispatching an event by looking it up in relevant keymaps and such, and handling timeouts; this includes the primitives next-event and dispatch-event, as well as related primitives such as sit-for, sleep-for, and accept-process-output. (`event-stream.c' is one of the hairiest and trickiest modules in XEmacs. Beware! You can easily mess things up here.)

`event-Xt.c' and `event-tty.c' implement the low-level interfaces onto retrieving events from Xt (the X toolkit) and from TTY's (using read() and select()), respectively. The event interface enforces a clean separation between the specific code for interfacing with the operating system and the generic code for working with events, by defining an API of basic, low-level event methods; `event-Xt.c' and `event-tty.c' are two different implementations of this API. To add support for a new operating system (e.g. NeXTstep), one merely needs to provide another implementation of those API functions.

Note that the choice of whether to use `event-Xt.c' or `event-tty.c' is made at compile time! Or at the very latest, it is made at startup time. `event-Xt.c' handles events for both X and TTY frames; `event-tty.c' is only used when X support is not compiled into XEmacs. The reason for this is that there is only one event loop in XEmacs: thus, it needs to be able to receive events from all different kinds of frames.

 
`keymap.c'
`keymap.h'

`keymap.c' and `keymap.h' define the keymap Lisp object type and associated methods and primitives. (Remember that keymaps are objects that associate event descriptions with functions to be called to "execute" those events; dispatch-event looks up events in the relevant keymaps.)

 
`cmdloop.c'

`cmdloop.c' contains functions that implement the actual editor command loop--i.e. the event loop that cyclically retrieves and dispatches events. This code is also rather tricky, just like `event-stream.c'.

 
`macros.c'
`macros.h'

These two modules contain the basic code for defining keyboard macros. These functions don't actually do much; most of the code that handles keyboard macros is mixed in with the event-handling code in `event-stream.c'.

 
`minibuf.c'

This contains some miscellaneous code related to the minibuffer (most of the minibuffer code was moved into Lisp by Richard Mlynarik). This includes the primitives for completion (although filename completion is in `dired.c'), the lowest-level interface to the minibuffer (if the command loop were cleaned up, this too could be in Lisp), and code for dealing with the echo area (this, too, was mostly moved into Lisp, and the only code remaining is code to call out to Lisp or provide simple bootstrapping implementations early in temacs, before the echo-area Lisp code is loaded).


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by XEmacs Webmaster on August, 3 2012 using texi2html