XEmacs 21.2.36 "Notos"
[chise/xemacs-chise.git.1] / src / event-stream.c
index 2b955fe..0d09051 100644 (file)
@@ -23,6 +23,20 @@ Boston, MA 02111-1307, USA.  */
 
 /* Synched up with: Not in FSF. */
 
+/* Authorship:
+
+   Created 1991 by Jamie Zawinski.
+   A great deal of work over the ages by Ben Wing (Mule-ization for 19.12,
+     device abstraction for 19.12/19.13, async timers for 19.14,
+     rewriting of focus code for 19.12, pre-idle hook for 19.12,
+     redoing of signal and quit handling for 19.9 and 19.12,
+     misc-user events to clean up menu/scrollbar handling for 19.11,
+     function-key-map/key-translation-map/keyboard-translate-table for
+     19.13/19.14, open-dribble-file for 19.13, much other cleanup).
+   focus-follows-mouse from Chuck Thompson, 1995.
+   XIM stuff by Martin Buchholz, c. 1996?.
+*/
+
 /* This file has been Mule-ized. */
 
 /*
@@ -38,8 +52,6 @@ Boston, MA 02111-1307, USA.  */
 /* TODO:
    This stuff is way too hard to maintain - needs rework.
 
-   (global-set-key "\C-p" global-map) causes a crash - need recursion check.
-
    C-x @ h <scrollbar-drag> x causes a crash.
 
    The command builder should deal only with key and button events.
@@ -62,14 +74,6 @@ Boston, MA 02111-1307, USA.  */
 #include <config.h>
 #include "lisp.h"
 
-#ifdef HAVE_X_WINDOWS
-#include "console-x.h"         /* for menu accelerators ... */
-#include "gui-x.h"
-#include "../lwlib/lwlib.h"
-#else
-#define lw_menu_active 0
-#endif
-
 #include "blocktype.h"
 #include "buffer.h"
 #include "commands.h"
@@ -81,7 +85,7 @@ Boston, MA 02111-1307, USA.  */
 #include "keymap.h"
 #include "lstream.h"
 #include "macros.h"            /* for defining_keyboard_macro */
-#include "opaque.h"
+#include "menubar.h"            /* #### for evil kludges. */
 #include "process.h"
 #include "window.h"
 
@@ -102,29 +106,30 @@ static int auto_save_interval;
 
 Lisp_Object Qundefined_keystroke_sequence;
 
-Lisp_Object Qcommand_execute;
-
 Lisp_Object Qcommand_event_p;
 
 /* Hooks to run before and after each command.  */
 Lisp_Object Vpre_command_hook, Vpost_command_hook;
 Lisp_Object Qpre_command_hook, Qpost_command_hook;
 
+/* See simple.el */
+Lisp_Object Qhandle_pre_motion_command, Qhandle_post_motion_command;
+
 /* Hook run when XEmacs is about to be idle. */
 Lisp_Object Qpre_idle_hook, Vpre_idle_hook;
 
 /* Control gratuitous keyboard focus throwing. */
 int focus_follows_mouse;
 
-#ifdef ILL_CONCEIVED_HOOK
+int modifier_keys_are_sticky;
+
+#if 0 /* FSF Emacs crap */
 /* Hook run after a command if there's no more input soon.  */
 Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
 
 /* Delay time in microseconds before running post-command-idle-hook.  */
 int post_command_idle_delay;
-#endif /* ILL_CONCEIVED_HOOK */
 
-#ifdef DEFERRED_ACTION_CRAP
 /* List of deferred actions to be performed at a later time.
    The precise format isn't relevant here; we just check whether it is nil.  */
 Lisp_Object Vdeferred_action_list;
@@ -132,7 +137,7 @@ Lisp_Object Vdeferred_action_list;
 /* Function to call to handle deferred actions, when there are any.  */
 Lisp_Object Vdeferred_action_function;
 Lisp_Object Qdeferred_action_function;
-#endif /* DEFERRED_ACTION_CRAP */
+#endif /* FSF Emacs crap */
 
 /* Non-nil disable property on a command means
    do not execute it; call disabled-command-hook's value instead. */
@@ -167,13 +172,20 @@ Lisp_Object Vunread_command_event; /* obsoleteness support */
 static Lisp_Object Qunread_command_events, Qunread_command_event;
 
 /* Previous command, represented by a Lisp object.
-   Does not include prefix commands and arg setting commands */
+   Does not include prefix commands and arg setting commands. */
 Lisp_Object Vlast_command;
 
+/* Contents of this-command-properties for the last command. */
+Lisp_Object Vlast_command_properties;
+
 /* If a command sets this, the value goes into
-   previous-command for the next command. */
+   last-command for the next command. */
 Lisp_Object Vthis_command;
 
+/* If a command sets this, the value goes into
+   last-command-properties for the next command. */
+Lisp_Object Vthis_command_properties;
+
 /* The value of point when the last command was executed.  */
 Bufpos last_point_position;
 
@@ -238,29 +250,7 @@ int recent_keys_ring_index;
    recent-keys. */
 int inhibit_input_event_recording;
 
-/* prefix key(s) that must match in order to activate menu.
-   This is ugly.  fix me.
-   */
-Lisp_Object Vmenu_accelerator_prefix;
-
-/* list of modifier keys to match accelerator for top level menus */
-Lisp_Object Vmenu_accelerator_modifiers;
-
-/* whether menu accelerators are enabled */
-Lisp_Object Vmenu_accelerator_enabled;
-
-/* keymap for auxiliary menu accelerator functions */
-Lisp_Object Vmenu_accelerator_map;
-
-Lisp_Object Qmenu_force;
-Lisp_Object Qmenu_fallback;
-Lisp_Object Qmenu_quit;
-Lisp_Object Qmenu_up;
-Lisp_Object Qmenu_down;
-Lisp_Object Qmenu_left;
-Lisp_Object Qmenu_right;
-Lisp_Object Qmenu_select;
-Lisp_Object Qmenu_escape;
+Lisp_Object Qself_insert_defer_undo;
 
 /* this is in keymap.c */
 extern Lisp_Object Fmake_keymap (Lisp_Object name);
@@ -289,60 +279,6 @@ external_debugging_print_event (char *event_description, Lisp_Object event)
 /* The callback routines for the window system or terminal driver */
 struct event_stream *event_stream;
 
-/* This structure is what we use to encapsulate the state of a command sequence
-   being composed; key events are executed by adding themselves to the command
-   builder; if the command builder is then complete (does not still represent
-   a prefix key sequence) it executes the corresponding command.
- */
-struct command_builder
-{
-  struct lcrecord_header header;
-  Lisp_Object console; /* back pointer to the console this command
-                         builder is for */
-  /* Qnil, or a Lisp_Event representing the first event read
-   *  after the last command completed.  Threaded. */
-  /* #### NYI */
-  Lisp_Object prefix_events;
-  /* Qnil, or a Lisp_Event representing event in the current
-   *  keymap-lookup sequence.  Subsequent events are threaded via
-   *  the event's next slot */
-  Lisp_Object current_events;
-  /* Last elt of above  */
-  Lisp_Object most_current_event;
-  /* Last elt before function map code took over. What this means is:
-     All prefixes up to (but not including) this event have non-nil
-     bindings, but the prefix including this event has a nil binding.
-     Any events in the chain after this one were read solely because
-     we're part of a possible function key.  If we end up with
-     something that's not part of a possible function key, we have to
-     unread all of those events. */
-  Lisp_Object last_non_munged_event;
-  /* One set of values for function-key-map, one for key-translation-map */
-  struct munging_key_translation
-  {
-    /* First event that can begin a possible function key sequence
-       (to be translated according to function-key-map).  Normally
-       this is the first event in the chain.  However, once we've
-       translated a sequence through function-key-map, this will point
-       to the first event after the translated sequence: we don't ever
-       want to translate any events twice through function-key-map, or
-       things could get really screwed up (e.g. if the user created a
-       translation loop).  If this is nil, then the next-read event is
-       the first that can begin a function key sequence. */
-    Lisp_Object first_mungeable_event;
-  } munge_me[2];
-
-  Bufbyte *echo_buf;
-  Bytecount echo_buf_length;          /* size of echo_buf */
-  Bytecount echo_buf_index;           /* index into echo_buf
-                                      * -1 before doing echoing for new cmd */
-  /* Self-insert-command is magic in that it doesn't always push an undo-
-     boundary: up to 20 consecutive self-inserts can happen before an undo-
-     boundary is pushed.  This variable is that counter.
-     */
-  int self_insert_countdown;
-};
-
 static void echo_key_event (struct command_builder *, Lisp_Object event);
 static void maybe_kbd_translate (Lisp_Object event);
 
@@ -385,19 +321,18 @@ static Lisp_Object recursive_sit_for;
   XRECORD (x, command_builder, struct command_builder)
 #define XSETCOMMAND_BUILDER(x, p) XSETRECORD (x, p, command_builder)
 #define COMMAND_BUILDERP(x) RECORDP (x, command_builder)
-#define GC_COMMAND_BUILDERP(x) GC_RECORDP (x, command_builder)
 #define CHECK_COMMAND_BUILDER(x) CHECK_RECORD (x, command_builder)
 
 static Lisp_Object
-mark_command_builder (Lisp_Object obj, void (*markobj) (Lisp_Object))
+mark_command_builder (Lisp_Object obj)
 {
   struct command_builder *builder = XCOMMAND_BUILDER (obj);
-  markobj (builder->prefix_events);
-  markobj (builder->current_events);
-  markobj (builder->most_current_event);
-  markobj (builder->last_non_munged_event);
-  markobj (builder->munge_me[0].first_mungeable_event);
-  markobj (builder->munge_me[1].first_mungeable_event);
+  mark_object (builder->prefix_events);
+  mark_object (builder->current_events);
+  mark_object (builder->most_current_event);
+  mark_object (builder->last_non_munged_event);
+  mark_object (builder->munge_me[0].first_mungeable_event);
+  mark_object (builder->munge_me[1].first_mungeable_event);
   return builder->console;
 }
 
@@ -413,7 +348,7 @@ finalize_command_builder (void *header, int for_disksave)
 
 DEFINE_LRECORD_IMPLEMENTATION ("command-builder", command_builder,
                                mark_command_builder, internal_object_printer,
-                              finalize_command_builder, 0, 0,
+                              finalize_command_builder, 0, 0, 0,
                               struct command_builder);
 \f
 static void
@@ -432,7 +367,7 @@ allocate_command_builder (Lisp_Object console)
 {
   Lisp_Object builder_obj;
   struct command_builder *builder =
-    alloc_lcrecord_type (struct command_builder, lrecord_command_builder);
+    alloc_lcrecord_type (struct command_builder, &lrecord_command_builder);
 
   builder->console = console;
   reset_command_builder_event_chain (builder);
@@ -509,8 +444,15 @@ event_stream_event_pending_p (int user)
   return event_stream && event_stream->event_pending_p (user);
 }
 
+static void
+event_stream_force_event_pending (struct frame* f)
+{
+  if (event_stream->force_event_pending)
+    event_stream->force_event_pending (f);
+}
+
 static int
-maybe_read_quit_event (struct Lisp_Event *event)
+maybe_read_quit_event (Lisp_Event *event)
 {
   /* A C-g that came from `sigint_happened' will always come from the
      controlling terminal.  If that doesn't exist, however, then the
@@ -537,7 +479,7 @@ maybe_read_quit_event (struct Lisp_Event *event)
 }
 
 void
-event_stream_next_event (struct Lisp_Event *event)
+event_stream_next_event (Lisp_Event *event)
 {
   Lisp_Object event_obj;
 
@@ -581,7 +523,7 @@ event_stream_next_event (struct Lisp_Event *event)
 }
 
 void
-event_stream_handle_magic_event (struct Lisp_Event *event)
+event_stream_handle_magic_event (Lisp_Event *event)
 {
   check_event_stream_ok (EVENT_STREAM_READ);
   event_stream->handle_magic_event_cb (event);
@@ -624,7 +566,7 @@ event_stream_unselect_console (struct console *con)
 }
 
 void
-event_stream_select_process (struct Lisp_Process *proc)
+event_stream_select_process (Lisp_Process *proc)
 {
   check_event_stream_ok (EVENT_STREAM_PROCESS);
   if (!get_process_selected_p (proc))
@@ -635,7 +577,7 @@ event_stream_select_process (struct Lisp_Process *proc)
 }
 
 void
-event_stream_unselect_process (struct Lisp_Process *proc)
+event_stream_unselect_process (Lisp_Process *proc)
 {
   check_event_stream_ok (EVENT_STREAM_PROCESS);
   if (get_process_selected_p (proc))
@@ -668,6 +610,14 @@ event_stream_quit_p (void)
     event_stream->quit_p_cb ();
 }
 
+static int
+event_stream_current_event_timestamp (struct console *c)
+{
+  if (event_stream && event_stream->current_event_timestamp_cb)
+    return event_stream->current_event_timestamp_cb (c);
+  else
+    return 0;
+}
 
 \f
 /**********************************************************************/
@@ -736,7 +686,10 @@ maybe_echo_keys (struct command_builder *command_builder, int no_snooze)
 
   if (minibuf_level == 0
       && echo_keystrokes > 0.0
-      && !lw_menu_active)
+#if defined (HAVE_X_WINDOWS) && defined (LWLIB_MENUBARS_LUCID)
+      && !x_kludge_lw_menu_active ()
+#endif
+      )
     {
       if (!no_snooze)
        {
@@ -799,7 +752,7 @@ maybe_kbd_translate (Lisp_Object event)
        }
       else if (CHARP (traduit))
        {
-         struct Lisp_Event ev2;
+         Lisp_Event ev2;
 
          /* This used to call Fcharacter_to_event() directly into EVENT,
             but that can eradicate timestamps and other such stuff.
@@ -822,6 +775,17 @@ maybe_kbd_translate (Lisp_Object event)
          XEVENT (event)->event.key.keysym = traduit;
          did_translate = 1;
        }
+      else if (CHARP (traduit))
+       {
+         Lisp_Event ev2;
+
+         zero_event (&ev2);
+         character_to_event (XCHAR (traduit), &ev2,
+                             XCONSOLE (EVENT_CHANNEL (XEVENT (event))), 1, 1);
+         XEVENT (event)->event.key.keysym = ev2.event.key.keysym;
+         XEVENT (event)->event.key.modifiers |= ev2.event.key.modifiers;
+         did_translate = 1;
+       }
     }
 
 #ifdef DEBUG_XEMACS
@@ -985,7 +949,7 @@ Actually, the value is nil only if we can be sure that no input is available.
    used to indicate an absence of a timer. */
 static int low_level_timeout_id_tick;
 
-struct low_level_timeout_blocktype
+static struct low_level_timeout_blocktype
 {
   Blocktype_declare (struct low_level_timeout);
 } *the_low_level_timeout_blocktype;
@@ -1101,38 +1065,40 @@ pop_low_level_timeout (struct low_level_timeout **timeout_list,
 
 static int timeout_id_tick;
 
-/* Since timeout structures contain Lisp_Objects, they need to be GC'd
-   properly.  The opaque data type provides a convenient way of doing
-   this without having to create a new Lisp object, since we can
-   provide our own mark function. */
-
-struct timeout
-{
-  int id; /* Id we use to identify the timeout over its lifetime */
-  int interval_id; /* Id for this particular interval; this may
-                     be different each time the timeout is
-                     signalled.*/
-  Lisp_Object function, object; /* Function and object associated
-                                  with timeout. */
-  EMACS_TIME next_signal_time;  /* Absolute time when the timeout
-                                  is next going to be signalled. */
-  unsigned int resignal_msecs;  /* How far after the next timeout
-                                  should the one after that
-                                  occur? */
-};
-
 static Lisp_Object pending_timeout_list, pending_async_timeout_list;
 
 static Lisp_Object Vtimeout_free_list;
 
 static Lisp_Object
-mark_timeout (Lisp_Object obj, void (*markobj) (Lisp_Object))
+mark_timeout (Lisp_Object obj)
 {
-  struct timeout *tm = (struct timeout *) XOPAQUE_DATA (obj);
-  markobj (tm->function);
+  Lisp_Timeout *tm = XTIMEOUT (obj);
+  mark_object (tm->function);
   return tm->object;
 }
 
+/* Should never, ever be called. (except by an external debugger) */
+static void
+print_timeout (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
+{
+  const Lisp_Timeout *t = XTIMEOUT (obj);
+  char buf[64];
+
+  sprintf (buf, "#<INTERNAL OBJECT (XEmacs bug?) (timeout) 0x%lx>",
+          (unsigned long) t);
+  write_c_string (buf, printcharfun);
+}
+
+static const struct lrecord_description timeout_description[] = {
+  { XD_LISP_OBJECT, offsetof (Lisp_Timeout, function) },
+  { XD_LISP_OBJECT, offsetof (Lisp_Timeout, object) },
+  { XD_END }
+};
+
+DEFINE_LRECORD_IMPLEMENTATION ("timeout", timeout,
+                              mark_timeout, print_timeout,
+                              0, 0, 0, timeout_description, Lisp_Timeout);
+
 /* Generate a timeout and return its ID. */
 
 int
@@ -1141,8 +1107,8 @@ event_stream_generate_wakeup (unsigned int milliseconds,
                              Lisp_Object function, Lisp_Object object,
                              int async_p)
 {
-  Lisp_Object op = allocate_managed_opaque (Vtimeout_free_list, 0);
-  struct timeout *timeout = (struct timeout *) XOPAQUE_DATA (op);
+  Lisp_Object op = allocate_managed_lcrecord (Vtimeout_free_list);
+  Lisp_Timeout *timeout = XTIMEOUT (op);
   EMACS_TIME current_time;
   EMACS_TIME interval;
 
@@ -1191,7 +1157,7 @@ event_stream_resignal_wakeup (int interval_id, int async_p,
                              Lisp_Object *function, Lisp_Object *object)
 {
   Lisp_Object op = Qnil, rest;
-  struct timeout *timeout;
+  Lisp_Timeout *timeout;
   Lisp_Object *timeout_list;
   struct gcpro gcpro1;
   int id;
@@ -1204,16 +1170,16 @@ event_stream_resignal_wakeup (int interval_id, int async_p,
   /* Find the timeout on the list of pending ones. */
   LIST_LOOP (rest, *timeout_list)
     {
-      timeout = (struct timeout *) XOPAQUE_DATA (XCAR (rest));
+      timeout = XTIMEOUT (XCAR (rest));
       if (timeout->interval_id == interval_id)
        break;
     }
 
   assert (!NILP (rest));
   op = XCAR (rest);
-  timeout = (struct timeout *) XOPAQUE_DATA (op);
+  timeout = XTIMEOUT (op);
   /* We make sure to snarf the data out of the timeout object before
-     we free it with free_managed_opaque(). */
+     we free it with free_managed_lcrecord(). */
   id = timeout->id;
   *function = timeout->function;
   *object = timeout->object;
@@ -1255,7 +1221,7 @@ event_stream_resignal_wakeup (int interval_id, int async_p,
       *timeout_list = noseeum_cons (op, *timeout_list);
     }
   else
-    free_managed_opaque (Vtimeout_free_list, op);
+    free_managed_lcrecord (Vtimeout_free_list, op);
 
   UNGCPRO;
   return id;
@@ -1264,7 +1230,7 @@ event_stream_resignal_wakeup (int interval_id, int async_p,
 void
 event_stream_disable_wakeup (int id, int async_p)
 {
-  struct timeout *timeout = 0;
+  Lisp_Timeout *timeout = 0;
   Lisp_Object rest;
   Lisp_Object *timeout_list;
 
@@ -1276,7 +1242,7 @@ event_stream_disable_wakeup (int id, int async_p)
   /* Find the timeout on the list of pending ones, if it's still there. */
   LIST_LOOP (rest, *timeout_list)
     {
-      timeout = (struct timeout *) XOPAQUE_DATA (XCAR (rest));
+      timeout = XTIMEOUT (XCAR (rest));
       if (timeout->id == id)
        break;
     }
@@ -1292,14 +1258,14 @@ event_stream_disable_wakeup (int id, int async_p)
        event_stream_remove_async_timeout (timeout->interval_id);
       else
        event_stream_remove_timeout (timeout->interval_id);
-      free_managed_opaque (Vtimeout_free_list, op);
+      free_managed_lcrecord (Vtimeout_free_list, op);
     }
 }
 
 static int
 event_stream_wakeup_pending_p (int id, int async_p)
 {
-  struct timeout *timeout;
+  Lisp_Timeout *timeout;
   Lisp_Object rest;
   Lisp_Object timeout_list;
   int found = 0;
@@ -1313,7 +1279,7 @@ event_stream_wakeup_pending_p (int id, int async_p)
   /* Find the element on the list of pending ones, if it's still there. */
   LIST_LOOP (rest, timeout_list)
     {
-      timeout = (struct timeout *) XOPAQUE_DATA (XCAR (rest));
+      timeout = XTIMEOUT (XCAR (rest));
       if (timeout->id == id)
        {
          found = 1;
@@ -2016,7 +1982,7 @@ next_event_internal (Lisp_Object target_event, int allow_queued)
     }
   else
     {
-      struct Lisp_Event *e = XEVENT (target_event);
+      Lisp_Event *e = XEVENT (target_event);
 
       /* The command_event_queue was empty.  Wait for an event. */
       event_stream_next_event (e);
@@ -2090,7 +2056,12 @@ The next available event will be
 
 -- any events in `unread-command-events' or `unread-command-event'; else
 -- the next event in the currently executing keyboard macro, if any; else
--- an event queued by `enqueue-eval-event', if any; else
+-- an event queued by `enqueue-eval-event', if any, or any similar event
+   queued internally, such as a misc-user event. (For example, when an item
+   is selected from a menu or from a `question'-type dialog box, the item's
+   callback is not immediately executed, but instead a misc-user event
+   is generated and placed onto this queue; when it is dispatched, the
+   callback is executed.) Else
 -- the next available event from the window system or terminal driver.
 
 In the last case, this function will block until an event is available.
@@ -2123,9 +2094,6 @@ The returned event will be one of the following types:
     XCOMMAND_BUILDER (con->command_builder);
   int store_this_key = 0;
   struct gcpro gcpro1;
-#ifdef LWLIB_MENUBARS_LUCID
-  extern int in_menu_callback;  /* defined in menubar-x.c */
-#endif /* LWLIB_MENUBARS_LUCID */
 
   GCPRO1 (event);
   /* DO NOT do QUIT anywhere within this function or the functions it calls.
@@ -2401,6 +2369,56 @@ but it also makes a provision for displaying keystrokes in the echo area.
   return event;
 }
 
+DEFUN ("dispatch-non-command-events", Fdispatch_non_command_events, 0, 0, 0, /*
+Dispatch any pending "magic" events.
+
+This function is useful for forcing the redisplay of native
+widgets. Normally these are redisplayed through a native window-system
+event encoded as magic event, rather than by the redisplay code.  This
+function does not call redisplay or do any of the other things that
+`next-event' does.
+*/
+       ())
+{
+  /* This function can GC */
+  Lisp_Object event = Qnil;
+  struct gcpro gcpro1;
+  GCPRO1 (event);
+  event = Fmake_event (Qnil, Qnil);
+
+  /* Make sure that there will be something in the native event queue
+     so that externally managed things (e.g. widgets) get some CPU
+     time. */
+  event_stream_force_event_pending (selected_frame ());
+
+  while (event_stream_event_pending_p (0))
+    {
+      QUIT; /* next_event_internal() does not QUIT. */
+
+      /* We're a generator of the command_event_queue, so we can't be a
+        consumer as well.  Also, we have no reason to consult the
+        command_event_queue; there are only user and eval-events there,
+        and we'd just have to put them back anyway.
+       */
+      next_event_internal (event, 0); /* blocks */
+      /* See the comment in accept-process-output about Vquit_flag */
+      if (XEVENT_TYPE (event) == magic_event ||
+         XEVENT_TYPE (event) == timeout_event ||
+         XEVENT_TYPE (event) == process_event ||
+         XEVENT_TYPE (event) == pointer_motion_event)
+       execute_internal_event (event);
+      else
+       {
+         enqueue_command_event_1 (event);
+         break;
+       }
+    }
+
+  Fdeallocate_event (event);
+  UNGCPRO;
+  return Qnil;
+}
+
 static void
 reset_current_events (struct command_builder *command_builder)
 {
@@ -2881,10 +2899,8 @@ If sit-for is called from within a process filter function or timer
   return result;
 }
 
-/* This handy little function is used by xselect.c and energize.c to
-   wait for replies from processes that aren't really processes (that is,
-   the X server and the Energize server).
- */
+/* This handy little function is used by select-x.c to wait for replies
+   from processes that aren't really processes (e.g. the X server) */
 void
 wait_delaying_user_input (int (*predicate) (void *arg), void *predicate_arg)
 {
@@ -3038,7 +3054,7 @@ execute_internal_event (Lisp_Object event)
 
     case timeout_event:
       {
-       struct Lisp_Event *e = XEVENT (event);
+       Lisp_Event *e = XEVENT (event);
        if (!NILP (e->event.timeout.function))
          call1 (e->event.timeout.function,
                 e->event.timeout.object);
@@ -3096,514 +3112,6 @@ command_builder_find_leaf_1 (struct command_builder *builder)
   return event_binding (event0, 1);
 }
 
-#if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID)
-static void
-menu_move_up (void)
-{
-  widget_value *current, *prev;
-  widget_value *entries;
-
-  current = lw_get_entries (False);
-  entries = lw_get_entries (True);
-  prev = NULL;
-  if (current != entries)
-    {
-      while (entries != current)
-       {
-         if (entries->name /*&& entries->enabled*/) prev = entries;
-         entries = entries->next;
-         assert (entries);
-       }
-    }
-
-  if (!prev)
-    /* move to last item */
-    {
-      while (entries->next)
-       {
-         if (entries->name /*&& entries->enabled*/) prev = entries;
-         entries = entries->next;
-       }
-      if (prev)
-       {
-         if (entries->name /*&& entries->enabled*/)
-           prev = entries;
-       }
-      else
-       {
-         /* no selectable items in this menu, pop up to previous level */
-         lw_pop_menu ();
-         return;
-       }
-    }
-  lw_set_item (prev);
-}
-
-static void
-menu_move_down (void)
-{
-  widget_value *current;
-  widget_value *new;
-
-  current = lw_get_entries (False);
-  new = current;
-
-  while (new->next)
-    {
-      new = new->next;
-      if (new->name /*&& new->enabled*/) break;
-    }
-
-  if (new==current||!(new->name/*||new->enabled*/))
-    {
-      new = lw_get_entries (True);
-      while (new!=current)
-       {
-         if (new->name /*&& new->enabled*/) break;
-         new = new->next;
-       }
-      if (new==current&&!(new->name /*|| new->enabled*/))
-       {
-         lw_pop_menu ();
-         return;
-       }
-    }
-
-  lw_set_item (new);
-}
-
-static void
-menu_move_left (void)
-{
-  int level = lw_menu_level ();
-  int l = level;
-  widget_value *current;
-
-  while (level >= 3)
-    {
-      --level;
-      lw_pop_menu ();
-    }
-  menu_move_up ();
-  current = lw_get_entries (False);
-  if (l > 2 && current->contents)
-    lw_push_menu (current->contents);
-}
-
-static void
-menu_move_right (void)
-{
-  int level = lw_menu_level ();
-  int l = level;
-  widget_value *current;
-
-  while (level >= 3)
-    {
-      --level;
-      lw_pop_menu ();
-    }
-  menu_move_down ();
-  current = lw_get_entries (False);
-  if (l > 2 && current->contents)
-    lw_push_menu (current->contents);
-}
-
-static void
-menu_select_item (widget_value *val)
-{
-  if (val == NULL)
-    val = lw_get_entries (False);
-
-  /* is match a submenu? */
-
-  if (val->contents)
-    {
-      /* enter the submenu */
-
-      lw_set_item (val);
-      lw_push_menu (val->contents);
-    }
-  else
-    {
-      /* Execute the menu entry by calling the menu's `select'
-        callback function
-        */
-      lw_kill_menus (val);
-    }
-}
-
-static Lisp_Object
-command_builder_operate_menu_accelerator (struct command_builder *builder)
-{
-  /* this function can GC */
-
-  struct console *con = XCONSOLE (Vselected_console);
-  Lisp_Object evee = builder->most_current_event;
-  Lisp_Object binding;
-  widget_value *entries;
-
-  extern int lw_menu_accelerate; /* lwlib.c */
-
-#if 0
-  {
-    int i;
-    Lisp_Object t;
-    char buf[50];
-
-    t = builder->current_events;
-    i = 0;
-    while (!NILP (t))
-      {
-       i++;
-       sprintf (buf,"OPERATE (%d): ",i);
-       write_c_string (buf, Qexternal_debugging_output);
-       print_internal (t, Qexternal_debugging_output, 1);
-       write_c_string ("\n", Qexternal_debugging_output);
-       t = XEVENT_NEXT (t);
-      }
-  }
-#endif /* 0 */
-
-  /* menu accelerator keys don't go into keyboard macros */
-  if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
-    con->kbd_macro_ptr = con->kbd_macro_end;
-
-  /* don't echo menu accelerator keys */
-  /*reset_key_echo (builder, 1);*/
-
-  if (!lw_menu_accelerate)
-    {
-      /* `convert' mouse display to keyboard display
-        by entering the open submenu
-        */
-      entries = lw_get_entries (False);
-      if (entries->contents)
-       {
-         lw_push_menu (entries->contents);
-         lw_display_menu (CurrentTime);
-       }
-    }
-
-  /* compare event to the current menu accelerators */
-
-  entries=lw_get_entries (True);
-
-  while (entries)
-    {
-      Lisp_Object accel;
-      VOID_TO_LISP (accel, entries->accel);
-      if (entries->name && !NILP (accel))
-       {
-         if (event_matches_key_specifier_p (XEVENT (evee), accel))
-           {
-             /* a match! */
-
-             menu_select_item (entries);
-
-             if (lw_menu_active) lw_display_menu (CurrentTime);
-
-             reset_this_command_keys (Vselected_console, 1);
-             /*reset_command_builder_event_chain (builder);*/
-             return Vmenu_accelerator_map;
-           }
-       }
-      entries = entries->next;
-    }
-
-  /* try to look up event in menu-accelerator-map */
-
-  binding = event_binding_in (evee, Vmenu_accelerator_map, 1);
-
-  if (NILP (binding))
-    {
-      /* beep at user for undefined key */
-      return Qnil;
-    }
-  else
-    {
-      if (EQ (binding, Qmenu_quit))
-       {
-         /* turn off menus and set quit flag */
-         lw_kill_menus (NULL);
-         Vquit_flag = Qt;
-       }
-      else if (EQ (binding, Qmenu_up))
-       {
-         int level = lw_menu_level ();
-         if (level > 2)
-           menu_move_up ();
-       }
-      else if (EQ (binding, Qmenu_down))
-       {
-         int level = lw_menu_level ();
-         if (level > 2)
-           menu_move_down ();
-         else
-           menu_select_item (NULL);
-       }
-      else if (EQ (binding, Qmenu_left))
-       {
-         int level = lw_menu_level ();
-         if (level > 3)
-           {
-             lw_pop_menu ();
-             lw_display_menu (CurrentTime);
-           }
-         else
-           menu_move_left ();
-       }
-      else if (EQ (binding, Qmenu_right))
-       {
-         int level = lw_menu_level ();
-         if (level > 2 &&
-             lw_get_entries (False)->contents)
-           {
-             widget_value *current = lw_get_entries (False);
-             if (current->contents)
-               menu_select_item (NULL);
-           }
-         else
-           menu_move_right ();
-       }
-      else if (EQ (binding, Qmenu_select))
-       menu_select_item (NULL);
-      else if (EQ (binding, Qmenu_escape))
-       {
-         int level = lw_menu_level ();
-
-         if (level > 2)
-           {
-             lw_pop_menu ();
-             lw_display_menu (CurrentTime);
-           }
-         else
-           {
-             /* turn off menus quietly */
-             lw_kill_menus (NULL);
-           }
-       }
-      else if (KEYMAPP (binding))
-       {
-         /* prefix key */
-         reset_this_command_keys (Vselected_console, 1);
-         /*reset_command_builder_event_chain (builder);*/
-         return binding;
-       }
-      else
-       {
-         /* turn off menus and execute binding */
-         lw_kill_menus (NULL);
-         reset_this_command_keys (Vselected_console, 1);
-         /*reset_command_builder_event_chain (builder);*/
-         return binding;
-       }
-    }
-
-  if (lw_menu_active) lw_display_menu (CurrentTime);
-
-  reset_this_command_keys (Vselected_console, 1);
-  /*reset_command_builder_event_chain (builder);*/
-
-  return Vmenu_accelerator_map;
-}
-
-static Lisp_Object
-menu_accelerator_junk_on_error (Lisp_Object errordata, Lisp_Object ignored)
-{
-  Vmenu_accelerator_prefix    = Qnil;
-  Vmenu_accelerator_modifiers = Qnil;
-  Vmenu_accelerator_enabled   = Qnil;
-  if (!NILP (errordata))
-    {
-      Lisp_Object args[2];
-
-      args[0] = build_string ("Error in menu accelerators (setting to nil)");
-      /* #### This should call
-        (with-output-to-string (display-error errordata))
-        but that stuff is all in Lisp currently. */
-      args[1] = errordata;
-      warn_when_safe_lispobj
-       (Qerror, Qwarning,
-        emacs_doprnt_string_lisp ((CONST Bufbyte *) "%s: %s",
-                                  Qnil, -1, 2, args));
-    }
-
-  return Qnil;
-}
-
-static Lisp_Object
-menu_accelerator_safe_compare (Lisp_Object event0)
-{
-  if (CONSP (Vmenu_accelerator_prefix))
-    {
-      Lisp_Object t;
-      t=Vmenu_accelerator_prefix;
-      while (!NILP (t)
-            && !NILP (event0)
-            && event_matches_key_specifier_p (XEVENT (event0), Fcar (t)))
-       {
-         t = Fcdr (t);
-         event0 = XEVENT_NEXT (event0);
-       }
-      if (!NILP (t))
-       return Qnil;
-    }
-  else if (NILP (event0))
-    return Qnil;
-  else if (event_matches_key_specifier_p (XEVENT (event0), Vmenu_accelerator_prefix))
-    event0 = XEVENT_NEXT (event0);
-  else
-    return Qnil;
-  return event0;
-}
-
-static Lisp_Object
-menu_accelerator_safe_mod_compare (Lisp_Object cons)
-{
-  return (event_matches_key_specifier_p (XEVENT (XCAR (cons)), XCDR (cons))
-         ? Qt
-         : Qnil);
-}
-
-static Lisp_Object
-command_builder_find_menu_accelerator (struct command_builder *builder)
-{
-  /* this function can GC */
-  Lisp_Object event0 = builder->current_events;
-  struct console *con = XCONSOLE (Vselected_console);
-  struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
-  Widget menubar_widget;
-
-  /* compare entries in event0 against the menu prefix */
-
-  if ((!CONSOLE_X_P (XCONSOLE (builder->console))) || NILP (event0) ||
-      XEVENT (event0)->event_type != key_press_event)
-    return Qnil;
-
-  if (!NILP (Vmenu_accelerator_prefix))
-    {
-      event0 = condition_case_1 (Qerror,
-                                menu_accelerator_safe_compare,
-                                event0,
-                                menu_accelerator_junk_on_error,
-                                Qnil);
-    }
-
-  if (NILP (event0))
-    return Qnil;
-
-  menubar_widget = FRAME_X_MENUBAR_WIDGET (f);
-  if (menubar_widget
-      && CONSP (Vmenu_accelerator_modifiers))
-    {
-      Lisp_Object fake;
-      Lisp_Object last = Qnil;
-      struct gcpro gcpro1;
-      Lisp_Object matchp;
-
-      widget_value *val;
-      LWLIB_ID id = XPOPUP_DATA (f->menubar_data)->id;
-
-      val = lw_get_all_values (id);
-      if (val)
-       {
-         val = val->contents;
-
-         fake = Fcopy_sequence (Vmenu_accelerator_modifiers);
-         last = fake;
-
-         while (!NILP (Fcdr (last)))
-           last = Fcdr (last);
-
-         Fsetcdr (last, Fcons (Qnil, Qnil));
-         last = Fcdr (last);
-       }
-
-      fake = Fcons (Qnil, fake);
-
-      GCPRO1 (fake);
-
-      while (val)
-       {
-         Lisp_Object accel;
-         VOID_TO_LISP (accel, val->accel);
-         if (val->name && !NILP (accel))
-           {
-             Fsetcar (last, accel);
-             Fsetcar (fake, event0);
-             matchp = condition_case_1 (Qerror,
-                                        menu_accelerator_safe_mod_compare,
-                                        fake,
-                                        menu_accelerator_junk_on_error,
-                                        Qnil);
-             if (!NILP (matchp))
-               {
-                 /* we found one! */
-
-                 lw_set_menu (menubar_widget, val);
-                 /* yah - yet another hack.
-                    pretend emacs timestamp is the same as an X timestamp,
-                    which for the moment it is.  (read events.h)
-                    */
-                 lw_map_menu (XEVENT (event0)->timestamp);
-
-                 if (val->contents)
-                   lw_push_menu (val->contents);
-
-                 lw_display_menu (CurrentTime);
-
-                 /* menu accelerator keys don't go into keyboard macros */
-                 if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
-                   con->kbd_macro_ptr = con->kbd_macro_end;
-
-                 /* don't echo menu accelerator keys */
-                 /*reset_key_echo (builder, 1);*/
-                 reset_this_command_keys (Vselected_console, 1);
-                 UNGCPRO;
-
-                 return Vmenu_accelerator_map;
-               }
-           }
-
-         val = val->next;
-       }
-
-      UNGCPRO;
-    }
-  return Qnil;
-}
-
-
-DEFUN ("accelerate-menu", Faccelerate_menu, 0, 0, "_", /*
-Make the menubar active.  Menu items can be selected using menu accelerators
-or by actions defined in menu-accelerator-map.
-*/
-       ())
-{
-  struct console *con = XCONSOLE (Vselected_console);
-  struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con));
-  LWLIB_ID id;
-  widget_value *val;
-
-  if (NILP (f->menubar_data))
-    error ("Frame has no menubar.");
-
-  id = XPOPUP_DATA (f->menubar_data)->id;
-  val = lw_get_all_values (id);
-  val = val->contents;
-  lw_set_menu (FRAME_X_MENUBAR_WIDGET (f), val);
-  lw_map_menu (CurrentTime);
-
-  lw_display_menu (CurrentTime);
-
-  /* menu accelerator keys don't go into keyboard macros */
-  if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro))
-    con->kbd_macro_ptr = con->kbd_macro_end;
-
-  return Qnil;
-}
-#endif /* HAVE_X_WINDOWS && HAVE_MENUBARS */
-
 /* See if we can do function-key-map or key-translation-map translation
    on the current events in the command builder.  If so, do this, and
    return the resulting binding, if any. */
@@ -3725,9 +3233,11 @@ command_builder_find_leaf (struct command_builder *builder,
        return Qnil;
     }
 
-  /* if we're currently in a menu accelerator, check there for further events */
+  /* if we're currently in a menu accelerator, check there for further
+     events */
+  /* #### fuck me!  who wrote this crap?  think "abstraction", baby. */
 #if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID)
-  if (lw_menu_active)
+  if (x_kludge_lw_menu_active ())
     {
       return command_builder_operate_menu_accelerator (builder);
     }
@@ -3778,14 +3288,14 @@ command_builder_find_leaf (struct command_builder *builder,
       Lisp_Object terminal = builder->most_current_event;
       struct key_data* key = & XEVENT (terminal)->event.key;
       Emchar c = 0;
-      if ((key->modifiers & MOD_SHIFT)
+      if ((key->modifiers & XEMACS_MOD_SHIFT)
           || (CHAR_OR_CHAR_INTP (key->keysym)
               && ((c = XCHAR_OR_CHAR_INT (key->keysym)), c >= 'A' && c <= 'Z')))
         {
-          struct Lisp_Event terminal_copy = *XEVENT (terminal);
+          Lisp_Event terminal_copy = *XEVENT (terminal);
 
-          if (key->modifiers & MOD_SHIFT)
-            key->modifiers &= (~ MOD_SHIFT);
+          if (key->modifiers & XEMACS_MOD_SHIFT)
+            key->modifiers &= (~ XEMACS_MOD_SHIFT);
           else
             key->keysym = make_char (c + 'a' - 'A');
 
@@ -4175,7 +3685,7 @@ lookup_command_event (struct command_builder *command_builder,
     if (EVENTP (recent)
        && event_matches_key_specifier_p (XEVENT (recent), Vmeta_prefix_char))
       {
-       struct Lisp_Event *e;
+       Lisp_Event *e;
        /* When we see a sequence like "ESC x", pretend we really saw "M-x".
           DoubleThink the recent-keys and this-command-keys as well. */
 
@@ -4186,10 +3696,10 @@ lookup_command_event (struct command_builder *command_builder,
        Fcopy_event (event, recent);
        e = XEVENT (recent);
        if (e->event_type == key_press_event)
-         e->event.key.modifiers |= MOD_META;
+         e->event.key.modifiers |= XEMACS_MOD_META;
        else if (e->event_type == button_press_event
                 || e->event_type == button_release_event)
-         e->event.button.modifiers |= MOD_META;
+         e->event.button.modifiers |= XEMACS_MOD_META;
        else
          abort ();
 
@@ -4220,7 +3730,11 @@ lookup_command_event (struct command_builder *command_builder,
 
     if (KEYMAPP (leaf))
       {
-       if (!lw_menu_active)
+#if defined (HAVE_X_WINDOWS) && defined (LWLIB_MENUBARS_LUCID)
+        if (!x_kludge_lw_menu_active ())
+#else
+       if (1)
+#endif
          {
            Lisp_Object prompt = Fkeymap_prompt (leaf, Qt);
            if (STRINGP (prompt))
@@ -4240,19 +3754,20 @@ lookup_command_event (struct command_builder *command_builder,
            else
              maybe_echo_keys (command_builder, 0);
          }
-       else if (!NILP (Vquit_flag)) {
-         Lisp_Object quit_event = Fmake_event(Qnil, Qnil);
-         struct Lisp_Event *e = XEVENT (quit_event);
-         /* if quit happened during menu acceleration, pretend we read it */
-         struct console *con = XCONSOLE (Fselected_console ());
-         int ch = CONSOLE_QUIT_CHAR (con);
-
-         character_to_event (ch, e, con, 1, 1);
-         e->channel = make_console (con);
-
-         enqueue_command_event (quit_event);
-         Vquit_flag = Qnil;
-       }
+       else if (!NILP (Vquit_flag))
+         {
+           Lisp_Object quit_event = Fmake_event (Qnil, Qnil);
+           Lisp_Event *e = XEVENT (quit_event);
+           /* if quit happened during menu acceleration, pretend we read it */
+           struct console *con = XCONSOLE (Fselected_console ());
+           int ch = CONSOLE_QUIT_CHAR (con);
+
+           character_to_event (ch, e, con, 1, 1);
+           e->channel = make_console (con);
+
+           enqueue_command_event (quit_event);
+           Vquit_flag = Qnil;
+         }
       }
     else if (!NILP (leaf))
       {
@@ -4371,6 +3886,9 @@ execute_command_event (struct command_builder *command_builder,
       {
        /* Start a new command next time */
        Vlast_command = Vthis_command;
+       Vlast_command_properties = Vthis_command_properties;
+       Vthis_command_properties = Qnil;
+
        /* Emacs 18 doesn't unconditionally clear the echoed keystrokes,
           so we don't either */
        reset_this_command_keys (make_console (con), 0);
@@ -4391,6 +3909,9 @@ pre_command_hook (void)
   safe_run_hook_trapping_errors
     ("Error in `pre-command-hook' (setting hook to nil)",
      Qpre_command_hook, 1);
+
+  /* This is a kludge, but necessary; see simple.el */
+  call0 (Qhandle_pre_motion_command);
 }
 
 /* Run the post command hook. */
@@ -4410,14 +3931,18 @@ post_command_hook (void)
 
   Lisp_Object win = Fselected_window (Qnil);
 
-#if 0
   /* If the last command deleted the frame, `win' might be nil.
      It seems safest to do nothing in this case. */
-  /* ### This doesn't really fix the problem,
+  /* Note: Someone added the following comment and put #if 0's around
+     this code, not realizing that doing this invites a crash in the
+     line after. */
+  /* #### This doesn't really fix the problem,
      if delete-frame is called by some hook */
   if (NILP (win))
     return;
-#endif
+
+  /* This is a kludge, but necessary; see simple.el */
+  call0 (Qhandle_post_motion_command);
 
   if (! zmacs_region_stays
       && (!MINI_WINDOW_P (XWINDOW (win))
@@ -4430,12 +3955,10 @@ post_command_hook (void)
     ("Error in `post-command-hook' (setting hook to nil)",
      Qpost_command_hook, 1);
 
-#ifdef DEFERRED_ACTION_CRAP
+#if 0 /* FSF Emacs crap */
   if (!NILP (Vdeferred_action_list))
     call0 (Vdeferred_action_function);
-#endif
 
-#ifdef ILL_CONCEIVED_HOOK
   if (NILP (Vunread_command_events)
       && NILP (Vexecuting_macro)
       && !NILP (Vpost_command_idle_hook)
@@ -4444,9 +3967,9 @@ post_command_hook (void)
   safe_run_hook_trapping_errors
     ("Error in `post-command-idle-hook' (setting hook to nil)",
      Qpost_command_idle_hook, 1);
-#endif
+#endif /* FSF Emacs crap */
 
-#if 0 /* FSFmacs */
+#if 0 /* FSF Emacs */
   if (!NILP (current_buffer->mark_active))
     {
       if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
@@ -4458,7 +3981,7 @@ post_command_hook (void)
               BUF_MODIFF (current_buffer) != prev_modiff)
        run_hook (intern ("activate-mark-hook"));
     }
-#endif /* FSFmacs */
+#endif /* FSF Emacs */
 
   /* #### Kludge!!! This is necessary to make sure that things
      are properly positioned even if post-command-hook moves point.
@@ -4492,7 +4015,7 @@ Magic events are handled as necessary.
 {
   /* This function can GC */
   struct command_builder *command_builder;
-  struct Lisp_Event *ev;
+  Lisp_Event *ev;
   Lisp_Object console;
   Lisp_Object channel;
 
@@ -4606,15 +4129,35 @@ Magic events are handled as necessary.
          }
        else /* key sequence is bound to a command */
          {
+           int magic_undo = 0;
+           int magic_undo_count = 20;
+
            Vthis_command = leaf;
+
            /* Don't push an undo boundary if the command set the prefix arg,
               or if we are executing a keyboard macro, or if in the
               minibuffer.  If the command we are about to execute is
               self-insert, it's tricky: up to 20 consecutive self-inserts may
               be done without an undo boundary.  This counter is reset as
               soon as a command other than self-insert-command is executed.
-              */
-           if (! EQ (leaf, Qself_insert_command))
+
+              Programmers can also use the `self-insert-defer-undo'
+              property to install that behavior on functions other
+              than `self-insert-command', or to change the magic
+              number 20 to something else.  #### DOCUMENT THIS!  */
+
+           if (SYMBOLP (leaf))
+             {
+               Lisp_Object prop = Fget (leaf, Qself_insert_defer_undo, Qnil);
+               if (NATNUMP (prop))
+                 magic_undo = 1, magic_undo_count = XINT (prop);
+               else if (!NILP (prop))
+                 magic_undo = 1;
+               else if (EQ (leaf, Qself_insert_command))
+                 magic_undo = 1;
+             }
+
+           if (!magic_undo)
              command_builder->self_insert_countdown = 0;
            if (NILP (XCONSOLE (console)->prefix_arg)
                && NILP (Vexecuting_macro)
@@ -4628,10 +4171,10 @@ Magic events are handled as necessary.
                && command_builder->self_insert_countdown == 0)
              Fundo_boundary ();
 
-           if (EQ (leaf, Qself_insert_command))
+           if (magic_undo)
              {
                if (--command_builder->self_insert_countdown < 0)
-                 command_builder->self_insert_countdown = 20;
+                 command_builder->self_insert_countdown = magic_undo_count;
              }
            execute_command_event
               (command_builder,
@@ -4817,7 +4360,7 @@ That is not right.
 
 Calling this function directs the translated event to replace
 the original event, so that only one version of the event actually
-appears in the echo area and in the value of `this-command-keys.'.
+appears in the echo area and in the value of `this-command-keys'.
 */
        ())
 {
@@ -4841,9 +4384,7 @@ dribble_out_event (Lisp_Object event)
        {
          Emchar ch = XCHAR (keysym);
          Bufbyte str[MAX_EMCHAR_LEN];
-         Bytecount len;
-
-         len = set_charptr_emchar (str, ch);
+         Bytecount len = set_charptr_emchar (str, ch);
          Lstream_write (XLSTREAM (Vdribble_file), str, len);
        }
       else if (string_char_length (XSYMBOL (keysym)->name) == 1)
@@ -4897,6 +4438,23 @@ If FILE is nil, close any open dribble file.
 }
 
 \f
+
+DEFUN ("current-event-timestamp", Fcurrent_event_timestamp, 0, 1, 0, /*
+Return the current event timestamp of the window system associated with CONSOLE.
+CONSOLE defaults to the selected console if omitted.
+*/
+       (console))
+{
+  struct console *c = decode_console (console);
+  int tiempo = event_stream_current_event_timestamp (c);
+
+  /* This junk is so that timestamps don't get to be negative, but contain
+     as many bits as this particular emacs will allow.
+   */
+  return make_int (((1L << (VALBITS - 1)) - 1) & tiempo);
+}
+
+\f
 /************************************************************************/
 /*                            initialization                            */
 /************************************************************************/
@@ -4904,12 +4462,13 @@ If FILE is nil, close any open dribble file.
 void
 syms_of_event_stream (void)
 {
+  INIT_LRECORD_IMPLEMENTATION (command_builder);
+  INIT_LRECORD_IMPLEMENTATION (timeout);
+
   defsymbol (&Qdisabled, "disabled");
   defsymbol (&Qcommand_event_p, "command-event-p");
 
-  deferror (&Qundefined_keystroke_sequence, "undefined-keystroke-sequence",
-            "Undefined keystroke sequence", Qerror);
-  defsymbol (&Qcommand_execute, "command-execute");
+  DEFERROR_STANDARD (Qundefined_keystroke_sequence, Qinvalid_argument);
 
   DEFSUBR (Frecent_keys);
   DEFSUBR (Frecent_keys_ring_size);
@@ -4927,23 +4486,22 @@ syms_of_event_stream (void)
   DEFSUBR (Fadd_async_timeout);
   DEFSUBR (Fdisable_async_timeout);
   DEFSUBR (Fdispatch_event);
+  DEFSUBR (Fdispatch_non_command_events);
   DEFSUBR (Fread_key_sequence);
   DEFSUBR (Fthis_command_keys);
   DEFSUBR (Freset_this_command_lengths);
   DEFSUBR (Fopen_dribble_file);
-#if defined(HAVE_X_WINDOWS) && defined(LWLIB_MENUBARS_LUCID)
-  DEFSUBR (Faccelerate_menu);
-#endif
+  DEFSUBR (Fcurrent_event_timestamp);
 
   defsymbol (&Qpre_command_hook, "pre-command-hook");
   defsymbol (&Qpost_command_hook, "post-command-hook");
   defsymbol (&Qunread_command_events, "unread-command-events");
   defsymbol (&Qunread_command_event, "unread-command-event");
   defsymbol (&Qpre_idle_hook, "pre-idle-hook");
-#ifdef ILL_CONCEIVED_HOOK
+  defsymbol (&Qhandle_pre_motion_command, "handle-pre-motion-command");
+  defsymbol (&Qhandle_post_motion_command, "handle-post-motion-command");
+#if 0 /* FSF Emacs crap */
   defsymbol (&Qpost_command_idle_hook, "post-command-idle-hook");
-#endif
-#ifdef DEFERRED_ACTION_CRAP
   defsymbol (&Qdeferred_action_function, "deferred-action-function");
 #endif
   defsymbol (&Qretry_undefined_key_binding_unshifted,
@@ -4951,37 +4509,41 @@ syms_of_event_stream (void)
   defsymbol (&Qauto_show_make_point_visible,
             "auto-show-make-point-visible");
 
-  defsymbol (&Qmenu_force, "menu-force");
-  defsymbol (&Qmenu_fallback, "menu-fallback");
-
-  defsymbol (&Qmenu_quit, "menu-quit");
-  defsymbol (&Qmenu_up, "menu-up");
-  defsymbol (&Qmenu_down, "menu-down");
-  defsymbol (&Qmenu_left, "menu-left");
-  defsymbol (&Qmenu_right, "menu-right");
-  defsymbol (&Qmenu_select, "menu-select");
-  defsymbol (&Qmenu_escape, "menu-escape");
-
+  defsymbol (&Qself_insert_defer_undo, "self-insert-defer-undo");
   defsymbol (&Qcancel_mode_internal, "cancel-mode-internal");
 }
 
 void
-vars_of_event_stream (void)
+reinit_vars_of_event_stream (void)
 {
   recent_keys_ring_index = 0;
   recent_keys_ring_size = 100;
+  num_input_chars = 0;
+  Vtimeout_free_list = make_lcrecord_list (sizeof (Lisp_Timeout),
+                                          &lrecord_timeout);
+  staticpro_nodump (&Vtimeout_free_list);
+  the_low_level_timeout_blocktype =
+    Blocktype_new (struct low_level_timeout_blocktype);
+  something_happened = 0;
+  recursive_sit_for = Qnil;
+}
+
+void
+vars_of_event_stream (void)
+{
+  reinit_vars_of_event_stream ();
   Vrecent_keys_ring = Qnil;
   staticpro (&Vrecent_keys_ring);
 
   Vthis_command_keys = Qnil;
   staticpro (&Vthis_command_keys);
   Vthis_command_keys_tail = Qnil;
-
-  num_input_chars = 0;
+  pdump_wire (&Vthis_command_keys_tail);
 
   command_event_queue = Qnil;
   staticpro (&command_event_queue);
   command_event_queue_tail = Qnil;
+  pdump_wire (&command_event_queue_tail);
 
   Vlast_selected_frame = Qnil;
   staticpro (&Vlast_selected_frame);
@@ -4992,20 +4554,9 @@ vars_of_event_stream (void)
   pending_async_timeout_list = Qnil;
   staticpro (&pending_async_timeout_list);
 
-  Vtimeout_free_list = make_opaque_list (sizeof (struct timeout),
-                                        mark_timeout);
-  staticpro (&Vtimeout_free_list);
-
-  the_low_level_timeout_blocktype =
-    Blocktype_new (struct low_level_timeout_blocktype);
-
-  something_happened = 0;
-
   last_point_position_buffer = Qnil;
   staticpro (&last_point_position_buffer);
 
-  recursive_sit_for = Qnil;
-
   DEFVAR_LISP ("echo-keystrokes", &Vecho_keystrokes /*
 *Nonzero means echo unfinished commands after this many seconds of pause.
 */ );
@@ -5038,7 +4589,7 @@ Normal hook run when XEmacs it about to be idle.
 This occurs whenever it is going to block, waiting for an event.
 This generally happens as a result of a call to `next-event',
 `next-command-event', `sit-for', `sleep-for', `accept-process-output',
-`x-get-selection', or various Energize-specific commands.
+or `x-get-selection'.
 Errors running the hook are caught and ignored.
 */ );
   Vpre_idle_hook = Qnil;
@@ -5047,11 +4598,11 @@ Errors running the hook are caught and ignored.
 *Variable to control XEmacs behavior with respect to focus changing.
 If this variable is set to t, then XEmacs will not gratuitously change
 the keyboard focus.  XEmacs cannot in general detect when this mode is
-use by the window manager, so it is up to the user to set it.
+used by the window manager, so it is up to the user to set it.
 */ );
   focus_follows_mouse = 0;
 
-#ifdef ILL_CONCEIVED_HOOK
+#if 0 /* FSF Emacs crap */
   /* Ill-conceived because it's not run in all sorts of cases
      where XEmacs is blocking.  That's what `pre-idle-hook'
      is designed to solve. */
@@ -5068,9 +4619,7 @@ Delay time before running `post-command-idle-hook'.
 This is measured in microseconds.
 */ );
   post_command_idle_delay = 5000;
-#endif /* ILL_CONCEIVED_HOOK */
 
-#ifdef DEFERRED_ACTION_CRAP
   /* Random FSFmacs crap.  There is absolutely nothing to gain,
      and a great deal to lose, in using this in place of just
      setting `post-command-hook'. */
@@ -5086,7 +4635,7 @@ This function is called with no arguments after each command
 whenever `deferred-action-list' is non-nil.
 */ );
   Vdeferred_action_function = Qnil;
-#endif /* DEFERRED_ACTION_CRAP */
+#endif /* FSF Emacs crap */
 
   DEFVAR_LISP ("last-command-event", &Vlast_command_event /*
 Last keyboard or mouse button event that was part of a command.  This
@@ -5176,6 +4725,23 @@ will be in `last-command' during the following command.
 */ );
   Vthis_command = Qnil;
 
+  DEFVAR_LISP ("last-command-properties", &Vlast_command_properties /*
+Value of `this-command-properties' for the last command.
+Used by commands to help synchronize consecutive commands, in preference
+to looking at `last-command' directly.
+*/ );
+  Vlast_command_properties = Qnil;
+
+  DEFVAR_LISP ("this-command-properties", &Vthis_command_properties /*
+Properties set by the current command.
+At the beginning of each command, the current value of this variable is
+copied to `last-command-properties', and then it is set to nil.  Use `putf'
+to add properties to this variable.  Commands should use this to communicate
+with pre/post-command hooks, subsequent commands, wrapping commands, etc.
+in preference to looking at and/or setting `this-command'.
+*/ );
+  Vthis_command_properties = Qnil;
+
   DEFVAR_LISP ("help-char", &Vhelp_char /*
 Character to recognize as meaning Help.
 When it is read, do `(eval help-form)', and display result if it's a string.
@@ -5209,6 +4775,10 @@ Each key-press event is looked up in this table as follows:
    keysym changed and its modifiers left alone.  This is useful for
    dealing with non-standard X keyboards, such as the grievous damage
    that Sun has inflicted upon the world.
+-- If an entry maps a symbol to a character, then a key-press event
+   whose keysym is the former symbol (with any modifiers at all) gets
+   changed into a key-press event matching the latter character, and the
+   resulting modifiers are the union of the original and new modifiers.
 -- If an entry maps a character to a character, then a key-press event
    matching the former character gets converted to a key-press event
    matching the latter character.  This is useful on ASCII terminals
@@ -5217,6 +4787,16 @@ Each key-press event is looked up in this table as follows:
 -- If an entry maps a character to a symbol, then a key-press event
    matching the character gets converted to a key-press event whose
    keysym is the given symbol and which has no modifiers.
+
+Here's an example: This makes typing parens and braces easier by rerouting
+their positions to eliminate the need to use the Shift key.
+
+  (keyboard-translate ?[ ?()
+  (keyboard-translate ?] ?))
+  (keyboard-translate ?{ ?[)
+  (keyboard-translate ?} ?])
+  (keyboard-translate 'f11 ?{)
+  (keyboard-translate 'f12 ?})
 */ );
 
   DEFVAR_LISP ("retry-undefined-key-binding-unshifted",
@@ -5229,6 +4809,15 @@ you should *bind* this, not set it.
 */ );
     Vretry_undefined_key_binding_unshifted = Qt;
 
+  DEFVAR_BOOL ("modifier-keys-are-sticky", &modifier_keys_are_sticky /*
+*Non-nil makes modifier keys sticky.
+This means that you can release the modifier key before pressing down
+the key that you wish to be modified.  Although this is non-standard
+behavior, it is recommended because it reduces the strain on your hand,
+thus reducing the incidence of the dreaded Emacs-pinky syndrome.
+*/ );
+  modifier_keys_are_sticky = 0;
+
 #ifdef HAVE_XIM
   DEFVAR_LISP ("composed-character-default-binding",
                &Vcomposed_character_default_binding /*
@@ -5289,41 +4878,6 @@ and is one of the following:
 Non-nil inhibits recording of input-events to recent-keys ring.
 */ );
   inhibit_input_event_recording = 0;
-
-  DEFVAR_LISP("menu-accelerator-prefix", &Vmenu_accelerator_prefix /*
-Prefix key(s) that must be typed before menu accelerators will be activated.
-Set this to a value acceptable by define-key.
-*/ );
-  Vmenu_accelerator_prefix = Qnil;
-
-  DEFVAR_LISP ("menu-accelerator-modifiers", &Vmenu_accelerator_modifiers /*
-Modifier keys which must be pressed to get to the top level menu accelerators.
-This is a list of modifier key symbols.  All modifier keys must be held down
-while a valid menu accelerator key is pressed in order for the top level
-menu to become active.
-
-See also menu-accelerator-enabled and menu-accelerator-prefix.
-*/ );
-  Vmenu_accelerator_modifiers = list1 (Qmeta);
-
-  DEFVAR_LISP ("menu-accelerator-enabled", &Vmenu_accelerator_enabled /*
-Whether menu accelerator keys can cause the menubar to become active.
-If 'menu-force or 'menu-fallback, then menu accelerator keys can
-be used to activate the top level menu.  Once the menubar becomes active, the
-accelerator keys can be used regardless of the value of this variable.
-
-menu-force is used to indicate that the menu accelerator key takes
-precedence over bindings in the current keymap(s).  menu-fallback means
-that bindings in the current keymap take precedence over menu accelerator keys.
-Thus a top level menu with an accelerator of "T" would be activated on a
-keypress of Meta-t if menu-accelerator-enabled is menu-force.
-However, if menu-accelerator-enabled is menu-fallback, then
-Meta-t will not activate the menubar and will instead run the function
-transpose-words, to which it is normally bound.
-
-See also menu-accelerator-modifiers and menu-accelerator-prefix.
-*/ );
-  Vmenu_accelerator_enabled = Qnil;
 }
 
 void
@@ -5331,41 +4885,6 @@ complex_vars_of_event_stream (void)
 {
   Vkeyboard_translate_table =
     make_lisp_hash_table (100, HASH_TABLE_NON_WEAK, HASH_TABLE_EQ);
-
-  DEFVAR_LISP ("menu-accelerator-map", &Vmenu_accelerator_map /*
-Keymap for use when the menubar is active.
-The actions menu-quit, menu-up, menu-down, menu-left, menu-right,
-menu-select and menu-escape can be mapped to keys in this map.
-
-menu-quit    Immediately deactivate the menubar and any open submenus without
-             selecting an item.
-menu-up      Move the menu cursor up one row in the current menu.  If the
-             move extends past the top of the menu, wrap around to the bottom.
-menu-down    Move the menu cursor down one row in the current menu.  If the
-             move extends past the bottom of the menu, wrap around to the top.
-             If executed while the cursor is in the top level menu, move down
-             into the selected menu.
-menu-left    Move the cursor from a submenu into the parent menu.  If executed
-             while the cursor is in the top level menu, move the cursor to the
-             left.  If the move extends past the left edge of the menu, wrap
-             around to the right edge.
-menu-right   Move the cursor into a submenu.  If the cursor is located in the
-             top level menu or is not currently on a submenu heading, then move
-             the cursor to the next top level menu entry.  If the move extends
-             past the right edge of the menu, wrap around to the left edge.
-menu-select  Activate the item under the cursor.  If the cursor is located on
-             a submenu heading, then move the cursor into the submenu.
-menu-escape  Pop up to the next level of menus.  Moves from a submenu into its
-             parent menu.  From the top level menu, this deactivates the
-             menubar.
-
-This keymap can also contain normal key-command bindings, in which case the
-menubar is deactivated and the corresponding command is executed.
-
-The action bindings used by the menu accelerator code are designed to mimic
-the actions of menu traversal keys in a commonly used PC operating system.
-*/ );
-  Vmenu_accelerator_map = Fmake_keymap(Qnil);
 }
 
 void
@@ -5374,8 +4893,7 @@ init_event_stream (void)
   if (initialized)
     {
 #ifdef HAVE_UNIXOID_EVENT_LOOP
-      /*      if (strcmp (display_use, "mswindows") != 0)*/
-       init_event_unixoid ();
+      init_event_unixoid ();
 #endif
 #ifdef HAVE_X_WINDOWS
       if (!strcmp (display_use, "x"))
@@ -5390,12 +4908,14 @@ init_event_stream (void)
          {
            /* For TTY's, use the Xt event loop if we can; it allows
               us to later open an X connection. */
-#if defined (HAVE_X_WINDOWS) && !defined (DEBUG_TTY_EVENT_STREAM)
+#if defined (HAVE_MS_WINDOWS) && (!defined (HAVE_TTY) \
+                || (defined (HAVE_MSG_SELECT) \
+           && !defined (DEBUG_TTY_EVENT_STREAM)))
+           init_event_mswindows_late ();
+#elif defined (HAVE_X_WINDOWS) && !defined (DEBUG_TTY_EVENT_STREAM)
            init_event_Xt_late ();
 #elif defined (HAVE_TTY)
            init_event_tty_late ();
-#elif defined (HAVE_MS_WINDOWS)
-           init_event_mswindows_late ();
 #endif
          }
       init_interrupts_late ();