XEmacs 21.4.9 "Informed Management".
[chise/xemacs-chise.git.1] / src / event-Xt.c
index 40c0752..4345bb1 100644 (file)
@@ -65,19 +65,8 @@ Boston, MA 02111-1307, USA.  */
 #include "offix.h"
 #endif
 
-#ifdef WINDOWSNT
-/* Hmm, under unix we want X modifiers, under NT we want X modifiers if
-   we are running X and Windows modifiers otherwise.
-   gak. This is a kludge until we support multiple native GUIs!
-*/
-#undef MOD_ALT
-#undef MOD_CONTROL
-#undef MOD_SHIFT
-#endif
-
 #include "events-mod.h"
 
-static void enqueue_Xt_dispatch_event (Lisp_Object event);
 static void handle_focus_event_1 (struct frame *f, int in_p);
 
 static struct event_stream *Xt_event_stream;
@@ -97,19 +86,18 @@ XtAppContext Xt_app_con;
 /* Do we accept events sent by other clients? */
 int x_allow_sendevents;
 
-int modifier_keys_are_sticky;
-
 #ifdef DEBUG_XEMACS
-int x_debug_events;
+Fixnum debug_x_events;
 #endif
 
 static int process_events_occurred;
 static int tty_events_occurred;
+static Widget widget_with_focus;
 
 /* Mask of bits indicating the descriptors that we wait for input on */
 extern SELECT_TYPE input_wait_mask, process_only_mask, tty_only_mask;
 
-static CONST String x_fallback_resources[] =
+static const String x_fallback_resources[] =
 {
   /* This file is automatically generated from the app-defaults file
      in ../etc/Emacs.ad.  These resources are consulted only if no
@@ -121,7 +109,7 @@ static CONST String x_fallback_resources[] =
 
 static Lisp_Object x_keysym_to_emacs_keysym (KeySym keysym, int simple_p);
 void emacs_Xt_mapping_action (Widget w, XEvent *event);
-void debug_process_finalization (struct Lisp_Process *p);
+void debug_process_finalization (Lisp_Process *p);
 void emacs_Xt_event_handler (Widget wid, XtPointer closure, XEvent *event,
                             Boolean *continue_to_dispatch);
 
@@ -175,6 +163,206 @@ Lisp_Object Qsans_modifiers;
    use a pop-up-window instead.)
  */
 
+/* For every key on the keyboard that has a known character correspondence,
+   we define the ascii-character property of the keysym, and make the
+   default binding for the key be self-insert-command.
+
+   The following magic is basically intimate knowledge of X11/keysymdef.h.
+   The keysym mappings defined by X11 are based on the iso8859 standards,
+   except for Cyrillic and Greek.
+
+   In a non-Mule world, a user can still have a multi-lingual editor, by doing
+   (set-face-font "...-iso8859-2" (current-buffer))
+   for all their Latin-2 buffers, etc.  */
+
+static Lisp_Object
+x_keysym_to_character (KeySym keysym)
+{
+#ifdef MULE
+  Lisp_Object charset = Qzero;
+#define USE_CHARSET(var,cs) \
+  ((var) = CHARSET_BY_LEADING_BYTE (LEADING_BYTE_##cs))
+#else
+#define USE_CHARSET(var,lb)
+#endif /* MULE */
+  int code = 0;
+
+  if ((keysym & 0xff) < 0xa0)
+    return Qnil;
+
+  switch (keysym >> 8)
+    {
+    case 0: /* ASCII + Latin1 */
+      USE_CHARSET (charset, LATIN_ISO8859_1);
+      code = keysym & 0x7f;
+      break;
+    case 1: /* Latin2 */
+      USE_CHARSET (charset, LATIN_ISO8859_2);
+      code = keysym & 0x7f;
+      break;
+    case 2: /* Latin3 */
+      USE_CHARSET (charset, LATIN_ISO8859_3);
+      code = keysym & 0x7f;
+      break;
+    case 3: /* Latin4 */
+      USE_CHARSET (charset, LATIN_ISO8859_4);
+      code = keysym & 0x7f;
+      break;
+    case 4: /* Katakana */
+      USE_CHARSET (charset, KATAKANA_JISX0201);
+      if ((keysym & 0xff) > 0xa0)
+       code = keysym & 0x7f;
+      break;
+    case 5: /* Arabic */
+      USE_CHARSET (charset, ARABIC_ISO8859_6);
+      code = keysym & 0x7f;
+      break;
+    case 6: /* Cyrillic */
+      {
+       static unsigned char const cyrillic[] = /* 0x20 - 0x7f */
+       {0x00, 0x72, 0x73, 0x71, 0x74, 0x75, 0x76, 0x77,
+        0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x00, 0x7e, 0x7f,
+        0x70, 0x22, 0x23, 0x21, 0x24, 0x25, 0x26, 0x27,
+        0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x00, 0x2e, 0x2f,
+        0x6e, 0x50, 0x51, 0x66, 0x54, 0x55, 0x64, 0x53,
+        0x65, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+        0x5f, 0x6f, 0x60, 0x61, 0x62, 0x63, 0x56, 0x52,
+        0x6c, 0x6b, 0x57, 0x68, 0x6d, 0x69, 0x67, 0x6a,
+        0x4e, 0x30, 0x31, 0x46, 0x34, 0x35, 0x44, 0x33,
+        0x45, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+        0x3f, 0x4f, 0x40, 0x41, 0x42, 0x43, 0x36, 0x32,
+        0x4c, 0x4b, 0x37, 0x48, 0x4d, 0x49, 0x47, 0x4a};
+       USE_CHARSET (charset, CYRILLIC_ISO8859_5);
+       code = cyrillic[(keysym & 0x7f) - 0x20];
+       break;
+      }
+    case 7: /* Greek */
+      {
+       static unsigned char const greek[] = /* 0x20 - 0x7f */
+       {0x00, 0x36, 0x38, 0x39, 0x3a, 0x5a, 0x00, 0x3c,
+        0x3e, 0x5b, 0x00, 0x3f, 0x00, 0x00, 0x35, 0x2f,
+        0x00, 0x5c, 0x5d, 0x5e, 0x5f, 0x7a, 0x40, 0x7c,
+        0x7d, 0x7b, 0x60, 0x7e, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+        0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+        0x50, 0x51, 0x53, 0x00, 0x54, 0x55, 0x56, 0x57,
+        0x58, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+        0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+        0x70, 0x71, 0x73, 0x72, 0x74, 0x75, 0x76, 0x77,
+        0x78, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+       USE_CHARSET (charset, GREEK_ISO8859_7);
+       code = greek[(keysym & 0x7f) - 0x20];
+       break;
+      }
+    case 8: /* Technical */
+      break;
+    case 9: /* Special */
+      break;
+    case 10: /* Publishing */
+      break;
+    case 11: /* APL */
+      break;
+    case 12: /* Hebrew */
+      USE_CHARSET (charset, HEBREW_ISO8859_8);
+      code = keysym & 0x7f;
+      break;
+    case 13: /* Thai */
+      /* #### This needs to deal with character composition. */
+      USE_CHARSET (charset, THAI_TIS620);
+      code = keysym & 0x7f;
+      break;
+    case 14: /* Korean Hangul */
+      break;
+    case 19: /* Latin 9 - ISO8859-15 - unsupported charset. */
+      break;
+    case 32: /* Currency */
+      break;
+    default:
+      break;
+    }
+
+  if (code == 0)
+    return Qnil;
+
+#ifdef MULE
+  return make_char (MAKE_CHAR (charset, code, 0));
+#else
+  return make_char (code + 0x80);
+#endif
+}
+
+/* #### The way that keysym correspondence to characters should work:
+   - a Lisp_Event should contain a keysym AND a character slot.
+   - keybindings are tried with the keysym.  If no binding can be found,
+   and there is a corresponding character, call self-insert-command.
+
+   #### Nuke x-iso8859-1.el.
+   #### Nuke the Qascii_character property.
+   #### Nuke Vcharacter_set_property.
+*/
+static void
+maybe_define_x_key_as_self_inserting_character (KeySym keysym, Lisp_Object symbol)
+{
+  Lisp_Object character = x_keysym_to_character (keysym);
+
+  if (CHARP (character))
+    {
+      extern Lisp_Object Vcurrent_global_map;
+      extern Lisp_Object Qascii_character;
+      if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil))) 
+        {
+         Fput (symbol, Qascii_character, character);
+         Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command); 
+        }
+    }
+}
+
+static void
+x_has_keysym (KeySym keysym, Lisp_Object hash_table, int with_modifiers)
+{
+  KeySym upper_lower[2];
+  int j;
+
+  if (keysym < 0x80) /* Optimize for ASCII keysyms */
+    return;
+
+  /* If you execute:
+     xmodmap -e 'keysym NN = scaron'
+     and then press (Shift scaron), X11 will return the different
+     keysym `Scaron', but  `xmodmap -pke'  might not even mention `Scaron'.
+     So we "register" both `scaron' and `Scaron'. */
+#ifdef HAVE_XCONVERTCASE
+  XConvertCase (keysym, &upper_lower[0], &upper_lower[1]);
+#else
+  upper_lower[0] = upper_lower[1] = keysym;
+#endif
+
+  for (j = 0; j < (upper_lower[0] == upper_lower[1] ? 1 : 2); j++)
+    {
+      char *name;
+      keysym = upper_lower[j];
+
+      name = XKeysymToString (keysym);
+      if (name)
+       {
+         /* X guarantees NAME to be in the Host Portable Character Encoding */
+         Lisp_Object sym = x_keysym_to_emacs_keysym (keysym, 0);
+         Lisp_Object new_value = with_modifiers ? Qt : Qsans_modifiers;
+         Lisp_Object old_value = Fgethash (sym, hash_table, Qnil);
+
+         if (! EQ (old_value, new_value)
+             && ! (EQ (old_value, Qsans_modifiers) &&
+                   EQ (new_value, Qt)))
+           {
+             maybe_define_x_key_as_self_inserting_character (keysym, sym);
+             Fputhash (build_ext_string (name, Qbinary), new_value, hash_table);
+             Fputhash (sym, new_value, hash_table);
+           }
+       }
+    }
+}
+
 static void
 x_reset_key_mapping (struct device *d)
 {
@@ -212,34 +400,18 @@ x_reset_key_mapping (struct device *d)
       if (keysym[0] == NoSymbol)
        continue;
 
-      {
-       char *name = XKeysymToString (keysym[0]);
-       Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[0], 0);
-       if (name)
-         {
-           Fputhash (build_string (name), Qsans_modifiers, hash_table);
-           Fputhash (sym, Qsans_modifiers, hash_table);
-         }
-      }
+      x_has_keysym (keysym[0], hash_table, 0);
 
       for (j = 1; j < keysyms_per_code; j++)
        {
          if (keysym[j] != keysym[0] &&
              keysym[j] != NoSymbol)
-           {
-             char *name = XKeysymToString (keysym[j]);
-             Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[j], 0);
-             if (name && NILP (Fgethash (sym, hash_table, Qnil)))
-               {
-                 Fputhash (build_string (name), Qt, hash_table);
-                 Fputhash (sym, Qt, hash_table);
-               }
-           }
+           x_has_keysym (keysym[j], hash_table, 1);
        }
     }
 }
 
-static CONST char *
+static const char *
 index_to_name (int indice)
 {
   switch (indice)
@@ -394,7 +566,7 @@ x_reset_modifier_mapping (struct device *d)
      be totally wrong. */
   if (mode_bit)
     {
-      CONST char *warn = 0;
+      const char *warn = 0;
       if      (mode_bit == meta_bit)  warn = "Meta",  meta_bit  = 0;
       else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0;
       else if (mode_bit == super_bit) warn = "Super", super_bit = 0;
@@ -518,20 +690,29 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d)
     { /* Not a modifier key */
       Bool key_event_p = (type == KeyPress || type == KeyRelease);
 
-      if (type == KeyPress && !xd->last_downkey)
-       xd->last_downkey = keycode;
-      else if (type == ButtonPress ||
-              (type == KeyPress && xd->last_downkey &&
-               (keycode != xd->last_downkey ||
-                ev->xkey.time != xd->release_time)))
+      if (type == ButtonPress
+         || (type == KeyPress
+             && ((xd->last_downkey
+                  && ((keycode != xd->last_downkey
+                       || ev->xkey.time != xd->release_time)))
+                 || (INTP (Vmodifier_keys_sticky_time)
+                     && ev->xkey.time
+                     > (xd->modifier_release_time
+                        + XINT (Vmodifier_keys_sticky_time))))))
        {
          xd->need_to_add_mask = 0;
          xd->last_downkey = 0;
        }
+      else if (type == KeyPress && !xd->last_downkey)
+       xd->last_downkey = keycode;
+
       if (type == KeyPress)
        xd->release_time = 0;
       if (type == KeyPress || type == ButtonPress)
-       xd->down_mask = 0;
+       {
+         xd->down_mask = 0;
+         xd->modifier_release_time = 0;
+       }
 
       if (key_event_p)
         ev->xkey.state    |= xd->need_to_add_mask;
@@ -553,7 +734,8 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d)
           So we assume that if the release and the next press
           occur at the same time, the key was actually auto-
           repeated.  Under Open-Windows, at least, this works. */
-       xd->release_time = key_event_p ? ev->xkey.time : ev->xbutton.time;
+       xd->modifier_release_time = xd->release_time
+         = key_event_p ? ev->xkey.time : ev->xbutton.time;
     }
   else                          /* Modifier key pressed */
     {
@@ -573,6 +755,15 @@ x_handle_sticky_modifiers (XEvent *ev, struct device *d)
          xd->need_to_add_mask = 0;
        }
 
+      if (xd->modifier_release_time
+         && INTP (Vmodifier_keys_sticky_time)
+         && (ev->xkey.time
+             > xd->modifier_release_time + XINT (Vmodifier_keys_sticky_time)))
+       {
+         xd->need_to_add_mask = 0;
+         xd->down_mask = 0;
+       }
+
 #define FROB(mask)                             \
 do {                                           \
   if (type == KeyPress)                                \
@@ -598,6 +789,7 @@ do {                                                \
          xd->need_to_add_mask |= mask;         \
        }                                       \
     }                                          \
+  xd->modifier_release_time = ev->xkey.time;   \
 } while (0)
 
       for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++)
@@ -775,7 +967,11 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
 
 #ifdef HAVE_XIM
   int len;
-  char buffer[64];
+  /* Some implementations of XmbLookupString don't return
+     XBufferOverflow correctly, so increase the size of the xim input
+     buffer from 64 to the more reasonable size 513, as Emacs has done.
+     From Kenichi Handa. */
+  char buffer[513];
   char *bufptr = buffer;
   int   bufsiz = sizeof (buffer);
   Status status;
@@ -808,11 +1004,12 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
   len = XmImMbLookupString (XtWindowToWidget (event->display, event->window),
                            event, bufptr, bufsiz, &keysym, &status);
 #else /* XIM_XLIB */
-  len = XmbLookupString (xic, event, bufptr, bufsiz, &keysym, &status);
+  if (xic)
+    len = XmbLookupString (xic, event, bufptr, bufsiz, &keysym, &status);
 #endif /* HAVE_XIM */
 
 #ifdef DEBUG_XEMACS
-  if (x_debug_events > 0)
+  if (debug_x_events > 0)
     {
       stderr_out ("   status=");
 #define print_status_when(S) if (status == S) stderr_out (#S)
@@ -859,10 +1056,9 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
        Lstream *istr;
        struct gcpro gcpro1, gcpro2;
 
-       fb_instream =
-          make_fixed_buffer_input_stream ((unsigned char *) bufptr, len);
+       fb_instream = make_fixed_buffer_input_stream (bufptr, len);
 
-        /* ### Use Fget_coding_system (Vcomposed_input_coding_system) */
+        /* #### Use Fget_coding_system (Vcomposed_input_coding_system) */
        instream =
          make_decoding_input_stream (XLSTREAM (fb_instream),
                                      Fget_coding_system (Qundecided));
@@ -873,7 +1069,7 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
         while ((ch = Lstream_get_emchar (istr)) != EOF)
           {
             Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
-           struct Lisp_Event *ev = XEVENT (emacs_event);
+           Lisp_Event *ev          = XEVENT (emacs_event);
             ev->channel                    = DEVICE_CONSOLE (d);
             ev->event_type         = key_press_event;
             ev->timestamp          = event->time;
@@ -920,7 +1116,7 @@ set_last_server_timestamp (struct device *d, XEvent *x_event)
 }
 
 static int
-x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
+x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event)
 {
   Display *display    = x_event->xany.display;
   struct device *d    = get_device_from_display (display);
@@ -942,7 +1138,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
     case ButtonPress:
     case ButtonRelease:
       {
-       unsigned int modifiers = 0;
+       int modifiers = 0;
        int shift_p, lock_p;
        Bool key_event_p = (x_event->type == KeyPress);
        unsigned int *state =
@@ -969,11 +1165,30 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
 
        x_handle_sticky_modifiers (x_event, d);
 
-       if (*state & ControlMask)    modifiers |= MOD_CONTROL;
-       if (*state & xd->MetaMask)   modifiers |= MOD_META;
-       if (*state & xd->SuperMask)  modifiers |= MOD_SUPER;
-       if (*state & xd->HyperMask)  modifiers |= MOD_HYPER;
-       if (*state & xd->AltMask)    modifiers |= MOD_ALT;
+       if (*state & ControlMask)    modifiers |= XEMACS_MOD_CONTROL;
+       if (*state & xd->MetaMask)   modifiers |= XEMACS_MOD_META;
+       if (*state & xd->SuperMask)  modifiers |= XEMACS_MOD_SUPER;
+       if (*state & xd->HyperMask)  modifiers |= XEMACS_MOD_HYPER;
+       if (*state & xd->AltMask)    modifiers |= XEMACS_MOD_ALT;
+       {
+         int numero_de_botao = -1;
+
+         if (!key_event_p)
+           numero_de_botao = x_event->xbutton.button;
+
+         /* the button gets noted either in the button or the modifiers
+            field, but not both. */
+         if (numero_de_botao != 1 && (*state & Button1Mask))
+           modifiers |= XEMACS_MOD_BUTTON1;
+         if (numero_de_botao != 2 && (*state & Button2Mask))
+           modifiers |= XEMACS_MOD_BUTTON2;
+         if (numero_de_botao != 3 && (*state & Button3Mask))
+           modifiers |= XEMACS_MOD_BUTTON3;
+         if (numero_de_botao != 4 && (*state & Button4Mask))
+           modifiers |= XEMACS_MOD_BUTTON4;
+         if (numero_de_botao != 5 && (*state & Button5Mask))
+           modifiers |= XEMACS_MOD_BUTTON5;
+       }
 
        /* Ignore the Caps_Lock key if:
           - any other modifiers are down, so that Caps_Lock doesn't
@@ -986,7 +1201,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
        lock_p  = *state & LockMask;
 
        if (shift_p || lock_p)
-         modifiers |= MOD_SHIFT;
+         modifiers |= XEMACS_MOD_SHIFT;
 
        if (key_event_p)
          {
@@ -1018,7 +1233,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
                ! (CHAR_OR_CHAR_INTP (keysym)
                   && keysym_obeys_caps_lock_p
                   ((KeySym) XCHAR_OR_CHAR_INT (keysym), d)))
-             modifiers &= (~MOD_SHIFT);
+             modifiers &= (~XEMACS_MOD_SHIFT);
 
            /* If this key contains two distinct keysyms, that is,
               "shift" generates a different keysym than the
@@ -1030,13 +1245,13 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
               in the modifiers slot.  Neither the characters "a",
               "A", "2", nor "@" normally have the shift bit set.
               However, "F1" normally does. */
-           if (modifiers & MOD_SHIFT)
+           if (modifiers & XEMACS_MOD_SHIFT)
              {
                int Mode_switch_p = *state & xd->ModeMask;
                KeySym bot = XLookupKeysym (ev, Mode_switch_p ? 2 : 0);
                KeySym top = XLookupKeysym (ev, Mode_switch_p ? 3 : 1);
                if (top && bot && top != bot)
-                 modifiers &= ~MOD_SHIFT;
+                 modifiers &= ~XEMACS_MOD_SHIFT;
              }
            emacs_event->event_type          = key_press_event;
            emacs_event->timestamp           = ev->time;
@@ -1073,7 +1288,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
       {
         XMotionEvent *ev = &x_event->xmotion;
         struct frame *frame = x_window_to_frame (d, ev->window);
-        unsigned int modifiers = 0;
+        int modifiers = 0;
         XMotionEvent event2;
 
         if (! frame)
@@ -1102,12 +1317,17 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
         emacs_event->timestamp      = ev->time;
         emacs_event->event.motion.x = ev->x;
         emacs_event->event.motion.y = ev->y;
-        if (ev->state & ShiftMask)     modifiers |= MOD_SHIFT;
-        if (ev->state & ControlMask)   modifiers |= MOD_CONTROL;
-        if (ev->state & xd->MetaMask)  modifiers |= MOD_META;
-        if (ev->state & xd->SuperMask) modifiers |= MOD_SUPER;
-        if (ev->state & xd->HyperMask) modifiers |= MOD_HYPER;
-        if (ev->state & xd->AltMask)   modifiers |= MOD_ALT;
+        if (ev->state & ShiftMask)     modifiers |= XEMACS_MOD_SHIFT;
+        if (ev->state & ControlMask)   modifiers |= XEMACS_MOD_CONTROL;
+        if (ev->state & xd->MetaMask)  modifiers |= XEMACS_MOD_META;
+        if (ev->state & xd->SuperMask) modifiers |= XEMACS_MOD_SUPER;
+        if (ev->state & xd->HyperMask) modifiers |= XEMACS_MOD_HYPER;
+        if (ev->state & xd->AltMask)   modifiers |= XEMACS_MOD_ALT;
+        if (ev->state & Button1Mask)   modifiers |= XEMACS_MOD_BUTTON1;
+        if (ev->state & Button2Mask)   modifiers |= XEMACS_MOD_BUTTON2;
+        if (ev->state & Button3Mask)   modifiers |= XEMACS_MOD_BUTTON3;
+        if (ev->state & Button4Mask)   modifiers |= XEMACS_MOD_BUTTON4;
+        if (ev->state & Button5Mask)   modifiers |= XEMACS_MOD_BUTTON5;
         /* Currently ignores Shift_Lock but probably shouldn't
            (but it definitely should ignore Caps_Lock). */
         emacs_event->event.motion.modifiers = modifiers;
@@ -1123,7 +1343,9 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
 #ifdef HAVE_OFFIX_DND
        if (DndIsDropMessage(x_event))
          {
-           unsigned int state, modifiers = 0, button=0;
+           unsigned int state;
+           int modifiers = 0;
+           unsigned int button=0;
            struct frame *frame = x_any_window_to_frame (d, ev->window);
            Extbyte *data;
            unsigned long size, dtype;
@@ -1131,10 +1353,10 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
            Lisp_Object l_dndlist = Qnil, l_item = Qnil;
            struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
 
-           GCPRO4 (l_type, l_data, l_dndlist, l_item);
-
            if (! frame)
              return 0; /* not for us */
+
+           GCPRO4 (l_type, l_data, l_dndlist, l_item);
            XSETFRAME (emacs_event->channel, frame);
 
            emacs_event->event_type = misc_user_event;
@@ -1142,12 +1364,17 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
 
            state=DndDragButtons(x_event);
 
-           if (state & ShiftMask)      modifiers |= MOD_SHIFT;
-           if (state & ControlMask)    modifiers |= MOD_CONTROL;
-           if (state & xd->MetaMask)   modifiers |= MOD_META;
-           if (state & xd->SuperMask)  modifiers |= MOD_SUPER;
-           if (state & xd->HyperMask)  modifiers |= MOD_HYPER;
-           if (state & xd->AltMask)    modifiers |= MOD_ALT;
+           if (state & ShiftMask)      modifiers |= XEMACS_MOD_SHIFT;
+           if (state & ControlMask)    modifiers |= XEMACS_MOD_CONTROL;
+           if (state & xd->MetaMask)   modifiers |= XEMACS_MOD_META;
+           if (state & xd->SuperMask)  modifiers |= XEMACS_MOD_SUPER;
+           if (state & xd->HyperMask)  modifiers |= XEMACS_MOD_HYPER;
+           if (state & xd->AltMask)    modifiers |= XEMACS_MOD_ALT;
+           if (state & Button1Mask)    modifiers |= XEMACS_MOD_BUTTON1;
+           if (state & Button2Mask)    modifiers |= XEMACS_MOD_BUTTON2;
+           if (state & Button3Mask)    modifiers |= XEMACS_MOD_BUTTON3;
+           if (state & Button4Mask)    modifiers |= XEMACS_MOD_BUTTON4;
+           if (state & Button5Mask)    modifiers |= XEMACS_MOD_BUTTON5;
 
            if (state & Button5Mask)    button = Button5;
            if (state & Button4Mask)    button = Button4;
@@ -1190,7 +1417,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
                                            make_string ((Bufbyte *)"8bit", 4),
                                            make_ext_string ((Extbyte *)data,
                                                             strlen((char *)data),
-                                                            FORMAT_CTEXT) ) );
+                                                            Qctext) ) );
                break;
              case DndMIME:
                /* we have to parse this in some way to extract
@@ -1203,7 +1430,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
                l_type = Qdragdrop_MIME;
                l_dndlist = list1 ( make_ext_string ((Extbyte *)data,
                                                     strlen((char *)data),
-                                                    FORMAT_BINARY) );
+                                                    Qbinary) );
                break;
              case DndFile:
              case DndDir:
@@ -1224,7 +1451,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
                   and escaping again will break them (cause % is unsave) */
                l_dndlist = list1 ( make_ext_string ((Extbyte *)data,
                                                     strlen ((char *)data),
-                                                    FORMAT_FILENAME) );
+                                                    Qfile_name) );
                l_type = Qdragdrop_URL;
                break;
              default: /* Unknown, RawData and any other type */
@@ -1232,7 +1459,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
                                            make_string ((Bufbyte *)"8bit", 4),
                                            make_ext_string ((Extbyte *)data,
                                                             size,
-                                                            FORMAT_BINARY) ) );
+                                                            Qbinary) ) );
                l_type = Qdragdrop_MIME;
                break;
              }
@@ -1281,6 +1508,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
          case FocusIn:
          case FocusOut:         FROB(xfocus, window);            break;
          case VisibilityNotify: FROB(xvisibility, window);       break;
+         case CreateNotify: FROB(xcreatewindow, window);         break;
           default:
            w = x_event->xany.window;
            *x_event_copy = *x_event;
@@ -1311,7 +1539,7 @@ static void
 handle_focus_event_1 (struct frame *f, int in_p)
 {
 #if XtSpecificationRelease > 5
-  Widget focus_widget = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f));
+  widget_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f));
 #endif
 #ifdef HAVE_XIM
   XIM_focus_event (f, in_p);
@@ -1332,21 +1560,27 @@ handle_focus_event_1 (struct frame *f, int in_p)
      Unfortunately native widgets break the model because they grab
      the keyboard focus and nothing sets it back again. I cannot find
      any reasonable way to do this elsewhere so we assert here that
-     the keybpard focus is on the emacs text widget. Menus and dialogs
+     the keyboard focus is on the emacs text widget. Menus and dialogs
      do this in their selection callback, but we don't want that since
      a button having focus is legitimate. An edit field having focus
-     is mandatory. Weirdly you get a FocusOut event when you glick in
-     a widget-glyph but you don't get a correspondng FocusIn when you
+     is mandatory. Weirdly you get a FocusOut event when you click in
+     a widget-glyph but you don't get a corresponding FocusIn when you
      click in the frame. Why is this?  */
-  if (in_p 
-#if XtSpecificationRelease > 5      
-      && FRAME_X_TEXT_WIDGET (f) != focus_widget
+  if (in_p
+#if XtSpecificationRelease > 5
+      && FRAME_X_TEXT_WIDGET (f) != widget_with_focus
 #endif
       )
     {
       lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f),
                             FRAME_X_TEXT_WIDGET (f));
     }
+
+  /* We have the focus now. See comment in
+     emacs_Xt_handle_widget_losing_focus (). */
+  if (in_p)
+    widget_with_focus = NULL;
+
   /* do the generic event-stream stuff. */
   {
     Lisp_Object frm;
@@ -1363,6 +1597,23 @@ handle_focus_event_1 (struct frame *f, int in_p)
   }
 }
 
+/* The idea here is that when a widget glyph gets unmapped we don't
+   want the focus to stay with it if it has focus - because it may
+   well just get deleted next andthen we have lost the focus until the
+   user does something. So handle_focus_event_1 records the widget
+   with keyboard focus when FocusOut is processed, and then, when a
+   widget gets unmapped, it calls this function to restore focus if
+   appropriate. */
+void emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget);
+void
+emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget)
+{
+  if (losing_widget == widget_with_focus)
+    {
+      handle_focus_event_1 (f, 1);
+    }
+}
+
 /* This is called from the external-widget code */
 
 void emacs_Xt_handle_focus_event (XEvent *event);
@@ -1539,8 +1790,62 @@ handle_client_message (struct frame *f, XEvent *event)
     }
 }
 
+/* #### I'm struggling to understand how the X event loop really works. 
+   Here is the problem:
+   
+   When widgets get mapped / changed etc the actual display updates
+   are done asynchronously via X events being processed - this
+   normally happens when XtAppProcessEvent() gets called. However, if
+   we are executing lisp code or even doing redisplay we won't
+   necessarily process X events for a very long time. This has the
+   effect of widgets only getting updated when XEmacs only goes into
+   idle, or some other event causes processing of the X event queue.
+
+   XtAppProcessEvent can get called from the following places:
+
+     emacs_Xt_next_event () - this is normal event processing, almost
+     any non-X event will take precedence and this means that we
+     cannot rely on it to do the right thing at the right time for
+     widget display.
+
+     drain_X_queue () - this happens when SIGIO gets tripped,
+     processing the event queue allows C-g to be checked for. It gets
+     called from emacs_Xt_event_pending_p ().
+
+   In order to solve this I have tried introducing a list primitive -
+   dispatch-non-command-events - which forces processing of X events
+   related to display. Unfortunately this has a number of problems,
+   one is that it is possible for event_stream_event_pending_p to
+   block for ever if there isn't actually an event. I guess this can
+   happen if we drop the synthetic event for reason. It also relies on
+   SIGIO processing which makes things rather fragile.
+
+   People have seen behaviour whereby XEmacs blocks until you move the
+   mouse. This seems to indicate that dispatch-non-command-events is
+   blocking. It may be that in a SIGIO world forcing SIGIO processing
+   does the wrong thing.
+*/
+static void
+emacs_Xt_force_event_pending (struct frame* f)
+{
+  XEvent event;
+
+  Display* dpy = DEVICE_X_DISPLAY (XDEVICE (FRAME_DEVICE  (f)));
+  event.xclient.type           = ClientMessage;
+  event.xclient.display                = dpy;
+  event.xclient.message_type   = XInternAtom (dpy, "BumpQueue", False);
+  event.xclient.format         = 32;
+  event.xclient.window         = 0;
+
+  /* Send the drop message */
+  XSendEvent(dpy, XtWindow (FRAME_X_SHELL_WIDGET (f)),
+            True, NoEventMask, &event);
+  /* We rely on SIGIO and friends to realise we have generated an
+     event. */
+}
+
 static void
-emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
+emacs_Xt_handle_magic_event (Lisp_Event *emacs_event)
 {
   /* This function can GC */
   XEvent *event = &emacs_event->event.magic.underlying_x_event;
@@ -1568,8 +1873,13 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
       break;
 
     case Expose:
-      x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y,
-                            event->xexpose.width, event->xexpose.height);
+      if (!check_for_ignored_expose (f, event->xexpose.x, event->xexpose.y,
+                                    event->xexpose.width, event->xexpose.height)
+         &&
+         !find_matching_subwindow (f, event->xexpose.x, event->xexpose.y,
+         event->xexpose.width, event->xexpose.height))
+       x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y,
+                              event->xexpose.width, event->xexpose.height);
       break;
 
     case GraphicsExpose: /* This occurs when an XCopyArea's source area was
@@ -1647,6 +1957,9 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
 #endif
       break;
 
+    case CreateNotify:
+      break;
+
     default:
       break;
     }
@@ -1662,14 +1975,14 @@ static int timeout_id_tick;
 /* Xt interval id's might not fit into an int (they're pointers, as it
    happens), so we need to provide a conversion list. */
 
-struct Xt_timeout
+static struct Xt_timeout
 {
   int id;
   XtIntervalId interval_id;
   struct Xt_timeout *next;
 } *pending_timeouts, *completed_timeouts;
 
-struct Xt_timeout_blocktype
+static struct Xt_timeout_blocktype
 {
   Blocktype_declare (struct Xt_timeout);
 } *the_Xt_timeout_blocktype;
@@ -1776,7 +2089,7 @@ emacs_Xt_remove_timeout (int id)
 }
 
 static void
-Xt_timeout_to_emacs_event (struct Lisp_Event *emacs_event)
+Xt_timeout_to_emacs_event (Lisp_Event *emacs_event)
 {
   struct Xt_timeout *timeout = completed_timeouts;
   assert (timeout);
@@ -1943,7 +2256,7 @@ unselect_filedesc (int fd)
 }
 
 static void
-emacs_Xt_select_process (struct Lisp_Process *p)
+emacs_Xt_select_process (Lisp_Process *p)
 {
   Lisp_Object process;
   int infd = event_stream_unixoid_select_process (p);
@@ -1953,7 +2266,7 @@ emacs_Xt_select_process (struct Lisp_Process *p)
 }
 
 static void
-emacs_Xt_unselect_process (struct Lisp_Process *p)
+emacs_Xt_unselect_process (Lisp_Process *p)
 {
   int infd = event_stream_unixoid_unselect_process (p);
 
@@ -1982,7 +2295,7 @@ emacs_Xt_delete_stream_pair (Lisp_Object instream, Lisp_Object outstream)
    If we've still got pointers to it in this file, we're gonna lose hard.
  */
 void
-debug_process_finalization (struct Lisp_Process *p)
+debug_process_finalization (Lisp_Process *p)
 {
 #if 0 /* #### */
   int i;
@@ -2002,25 +2315,27 @@ debug_process_finalization (struct Lisp_Process *p)
 }
 
 static void
-Xt_process_to_emacs_event (struct Lisp_Event *emacs_event)
+Xt_process_to_emacs_event (Lisp_Event *emacs_event)
 {
   int i;
-  Lisp_Object process;
 
   assert (process_events_occurred > 0);
+
   for (i = 0; i < MAXDESC; i++)
     {
-      process = filedesc_with_input[i];
+      Lisp_Object process = filedesc_with_input[i];
       if (PROCESSP (process))
-       break;
+       {
+         filedesc_with_input[i] = Qnil;
+         process_events_occurred--;
+         /* process events have nil as channel */
+         emacs_event->event_type = process_event;
+         emacs_event->timestamp  = 0; /* #### */
+         emacs_event->event.process.process = process;
+         return;
+       }
     }
-  assert (i < MAXDESC);
-  filedesc_with_input[i] = Qnil;
-  process_events_occurred--;
-  /* process events have nil as channel */
-  emacs_event->event_type = process_event;
-  emacs_event->timestamp  = 0; /* #### */
-  emacs_event->event.process.process = process;
+  abort ();
 }
 
 static void
@@ -2028,9 +2343,6 @@ emacs_Xt_select_console (struct console *con)
 {
   Lisp_Object console;
   int infd;
-#ifdef HAVE_GPM
-  int mousefd;
-#endif
 
   if (CONSOLE_X_P (con))
     return; /* X consoles are automatically selected for when we
@@ -2038,22 +2350,6 @@ emacs_Xt_select_console (struct console *con)
   infd = event_stream_unixoid_select_console (con);
   XSETCONSOLE (console, con);
   select_filedesc (infd, console);
-#ifdef HAVE_GPM
-  /* On a stream device (ie: noninteractive), bad things can happen. */
-  if (EQ (CONSOLE_TYPE (con), Qtty)) {
-    mousefd = CONSOLE_TTY_MOUSE_FD (con);
-       /* We check filedesc_to_what_closure[fd] here because if you run
-       ** XEmacs from a TTY, it will fire up GPM, select the mouse fd, then
-       ** if you run gnuattach to connect to another TTY, it will fire up
-       ** GPM again, and try to reselect the mouse fd.  GPM uses the same
-       ** fd for every connection apparently, and select_filedesc will
-       ** fail its assertion if we try to select it twice.
-       */
-    if ((mousefd >= 0) && !filedesc_to_what_closure[mousefd]) {
-      select_filedesc (mousefd, console);
-    }
-  }
-#endif
 }
 
 static void
@@ -2061,9 +2357,6 @@ emacs_Xt_unselect_console (struct console *con)
 {
   Lisp_Object console;
   int infd;
-#ifdef HAVE_GPM
-  int mousefd;
-#endif
 
   if (CONSOLE_X_P (con))
     return; /* X consoles are automatically selected for when we
@@ -2071,15 +2364,6 @@ emacs_Xt_unselect_console (struct console *con)
   infd = event_stream_unixoid_unselect_console (con);
   XSETCONSOLE (console, con);
   unselect_filedesc (infd);
-#ifdef HAVE_GPM
-  /* On a stream device (ie: noninteractive), bad things can happen. */
-  if (EQ (CONSOLE_TYPE (con), Qtty)) {
-    mousefd = CONSOLE_TTY_MOUSE_FD (con);
-    if (mousefd >= 0) {
-      unselect_filedesc (mousefd);
-    }
-  }
-#endif
 }
 
 /* read an event from a tty, if one is available.  Returns non-zero
@@ -2091,7 +2375,7 @@ emacs_Xt_unselect_console (struct console *con)
    to be deleted.) */
 
 static int
-Xt_tty_to_emacs_event (struct Lisp_Event *emacs_event)
+Xt_tty_to_emacs_event (Lisp_Event *emacs_event)
 {
   int i;
 
@@ -2137,12 +2421,12 @@ describe_event_window (Window window, Display *display)
       char *buf = alloca_array (char, XSTRING_LENGTH (f->name) + 4);
       sprintf (buf, " \"%s\"", XSTRING_DATA (f->name));
       write_string_to_stdio_stream (stderr, 0, (Bufbyte *) buf, 0,
-                                   strlen (buf), FORMAT_TERMINAL);
+                                   strlen (buf), Qterminal, 1);
     }
   stderr_out ("\n");
 }
 
-static CONST char *
+static const char *
 XEvent_mode_to_string (int mode)
 {
   switch (mode)
@@ -2155,7 +2439,7 @@ XEvent_mode_to_string (int mode)
   }
 }
 
-static CONST char *
+static const char *
 XEvent_detail_to_string (int detail)
 {
   switch (detail)
@@ -2171,7 +2455,7 @@ XEvent_detail_to_string (int detail)
   }
 }
 
-static CONST char *
+static const char *
 XEvent_visibility_to_string (int state)
 {
   switch (state)
@@ -2233,7 +2517,7 @@ describe_event (XEvent *event)
     break;
 
     case Expose:
-      if (x_debug_events > 1)
+      if (debug_x_events > 1)
        {
          XExposeEvent *ev = &event->xexpose;
          describe_event_window (ev->window, ev->display);
@@ -2246,7 +2530,7 @@ describe_event (XEvent *event)
       break;
 
     case GraphicsExpose:
-      if (x_debug_events > 1)
+      if (debug_x_events > 1)
        {
          XGraphicsExposeEvent *ev = &event->xgraphicsexpose;
          describe_event_window (ev->drawable, ev->display);
@@ -2263,7 +2547,7 @@ describe_event (XEvent *event)
 
     case EnterNotify:
     case LeaveNotify:
-      if (x_debug_events > 1)
+      if (debug_x_events > 1)
        {
          XCrossingEvent *ev = &event->xcrossing;
          describe_event_window (ev->window, ev->display);
@@ -2284,7 +2568,7 @@ describe_event (XEvent *event)
       break;
 
     case ConfigureNotify:
-      if (x_debug_events > 1)
+      if (debug_x_events > 1)
        {
          XConfigureEvent *ev = &event->xconfigure;
          describe_event_window (ev->window, ev->display);
@@ -2298,7 +2582,7 @@ describe_event (XEvent *event)
       break;
 
     case VisibilityNotify:
-      if (x_debug_events > 1)
+      if (debug_x_events > 1)
        {
          XVisibilityEvent *ev = &event->xvisibility;
          describe_event_window (ev->window, ev->display);
@@ -2340,7 +2624,7 @@ describe_event (XEvent *event)
 
 static Lisp_Object dispatch_event_queue, dispatch_event_queue_tail;
 
-static void
+void
 enqueue_Xt_dispatch_event (Lisp_Object event)
 {
   enqueue_event (event, &dispatch_event_queue, &dispatch_event_queue_tail);
@@ -2376,7 +2660,7 @@ signal_special_Xt_user_event (Lisp_Object channel, Lisp_Object function,
 }
 
 static void
-emacs_Xt_next_event (struct Lisp_Event *emacs_event)
+emacs_Xt_next_event (Lisp_Event *emacs_event)
 {
  we_didnt_get_an_event:
 
@@ -2461,7 +2745,7 @@ emacs_Xt_event_handler (Widget wid /* unused */,
   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
 
 #ifdef DEBUG_XEMACS
-  if (x_debug_events > 0)
+  if (debug_x_events > 0)
     {
       describe_event (event);
     }
@@ -2727,7 +3011,11 @@ emacs_Xt_event_pending_p (int user_p)
   /* quit_check_signal_tick_count is volatile so try to avoid race conditions
      by using a temporary variable */
   tick_count_val = quit_check_signal_tick_count;
-  if (last_quit_check_signal_tick_count != tick_count_val)
+  if (last_quit_check_signal_tick_count != tick_count_val
+#if !defined (SIGIO) || defined (CYGWIN)
+      || (XtIMXEvent & XtAppPending (Xt_app_con))
+#endif 
+      )
     {
       last_quit_check_signal_tick_count = tick_count_val;
 
@@ -2745,6 +3033,21 @@ emacs_Xt_event_pending_p (int user_p)
   return 0;
 }
 
+static int
+emacs_Xt_current_event_timestamp (struct console *c)
+{
+  /* semi-yuck. */
+  Lisp_Object devs = CONSOLE_DEVICE_LIST (c);
+
+  if (NILP (devs))
+    return 0;
+  else
+    {
+      struct device *d = XDEVICE (XCAR (devs));
+      return DEVICE_X_LAST_SERVER_TIMESTAMP (d);
+    }
+}
+
 \f
 /************************************************************************/
 /*            replacement for standard string-to-pixel converter        */
@@ -2761,10 +3064,10 @@ emacs_Xt_event_pending_p (int user_p)
    the '#if 0'.  Note, however, that I got "unknown structure"
    errors when I tried this. */
 XtConvertArgRec Const colorConvertArgs[] = {
-  {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
-   sizeof(Screen *)},
-  {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
-   sizeof(Colormap)}
+  { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.screen),
+    sizeof (Screen *) },
+  { XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.colormap),
+    sizeof (Colormap) }
 };
 
 #endif
@@ -2842,9 +3145,9 @@ Boolean EmacsXtCvtStringToPixel (
   if ((d = get_device_from_display_1(dpy))) {
     visual = DEVICE_X_VISUAL(d);
     if (colormap != DEVICE_X_COLORMAP(d)) {
-      XtAppWarningMsg(the_app_con, "wierdColormap", "cvtStringToPixel",
+      XtAppWarningMsg(the_app_con, "weirdColormap", "cvtStringToPixel",
                      "XtToolkitWarning",
-                     "The colormap passed to cvtStringToPixel doesn't match the one registerd to the device.\n",
+                     "The colormap passed to cvtStringToPixel doesn't match the one registered to the device.\n",
                      NULL, 0);
       status = XAllocNamedColor(dpy, colormap, (char*)str, &screenColor, &exactColor);
     } else {
@@ -2906,6 +3209,42 @@ static void EmacsFreePixel (
 
 \f
 /************************************************************************/
+/*            handle focus changes for native widgets                  */
+/************************************************************************/
+static void
+emacs_Xt_event_widget_focus_in (Widget   w,
+                               XEvent   *event,
+                               String   *params,
+                               Cardinal *num_params)
+{
+  struct frame* f =
+    x_any_widget_or_parent_to_frame (get_device_from_display (event->xany.display), w);
+
+  XtSetKeyboardFocus (FRAME_X_SHELL_WIDGET (f), w);
+}
+
+static void
+emacs_Xt_event_widget_focus_out (Widget   w,
+                                XEvent   *event,
+                                String   *params,
+                                Cardinal *num_params)
+{
+}
+
+static XtActionsRec widgetActionsList[] =
+{
+  {"widget-focus-in",  emacs_Xt_event_widget_focus_in  },
+  {"widget-focus-out", emacs_Xt_event_widget_focus_out },
+};
+
+static void
+emacs_Xt_event_add_widget_actions (XtAppContext ctx)
+{
+  XtAppAddActions (ctx, widgetActionsList, 2);
+}
+
+\f
+/************************************************************************/
 /*                            initialization                            */
 /************************************************************************/
 
@@ -2914,20 +3253,15 @@ syms_of_event_Xt (void)
 {
   defsymbol (&Qkey_mapping, "key-mapping");
   defsymbol (&Qsans_modifiers, "sans-modifiers");
+  defsymbol (&Qself_insert_command, "self-insert-command");
 }
 
 void
-vars_of_event_Xt (void)
+reinit_vars_of_event_Xt (void)
 {
-  dispatch_event_queue = Qnil;
-  staticpro (&dispatch_event_queue);
-  dispatch_event_queue_tail = Qnil;
-
-  /* this function only makes safe calls */
-  init_what_input_once ();
-
   Xt_event_stream = xnew (struct event_stream);
   Xt_event_stream->event_pending_p      = emacs_Xt_event_pending_p;
+  Xt_event_stream->force_event_pending          = emacs_Xt_force_event_pending;
   Xt_event_stream->next_event_cb        = emacs_Xt_next_event;
   Xt_event_stream->handle_magic_event_cb = emacs_Xt_handle_magic_event;
   Xt_event_stream->add_timeout_cb       = emacs_Xt_add_timeout;
@@ -2939,15 +3273,26 @@ vars_of_event_Xt (void)
   Xt_event_stream->quit_p_cb            = emacs_Xt_quit_p;
   Xt_event_stream->create_stream_pair_cb = emacs_Xt_create_stream_pair;
   Xt_event_stream->delete_stream_pair_cb = emacs_Xt_delete_stream_pair;
+  Xt_event_stream->current_event_timestamp_cb =
+    emacs_Xt_current_event_timestamp;
 
-  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;
+  the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype);
+
+  last_quit_check_signal_tick_count = 0;
+
+  /* this function only makes safe calls */
+  init_what_input_once ();
+}
+
+void
+vars_of_event_Xt (void)
+{
+  reinit_vars_of_event_Xt ();
+
+  dispatch_event_queue = Qnil;
+  staticpro (&dispatch_event_queue);
+  dispatch_event_queue_tail = Qnil;
+  dump_add_root_object (&dispatch_event_queue_tail);
 
   DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents /*
 *Non-nil means to allow synthetic events.  Nil means they are ignored.
@@ -2956,19 +3301,15 @@ Beware: allowing emacs to process SendEvents opens a big security hole.
   x_allow_sendevents = 0;
 
 #ifdef DEBUG_XEMACS
-  DEFVAR_INT ("x-debug-events", &x_debug_events /*
+  DEFVAR_INT ("debug-x-events", &debug_x_events /*
 If non-zero, display debug information about X events that XEmacs sees.
 Information is displayed on stderr.  Currently defined values are:
 
 1 == non-verbose output
 2 == verbose output
 */ );
-  x_debug_events = 0;
+  debug_x_events = 0;
 #endif
-
-  the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype);
-
-  last_quit_check_signal_tick_count = 0;
 }
 
 /* This mess is a hack that patches the shell widget to treat visual inheritance
@@ -3010,12 +3351,12 @@ init_event_Xt_late (void) /* called when already initialized */
   Xt_app_con = XtCreateApplicationContext ();
   XtAppSetFallbackResources (Xt_app_con, (String *) x_fallback_resources);
 
-  /* In xselect.c */
+  /* In select-x.c */
   x_selection_timeout = (XtAppGetSelectionTimeout (Xt_app_con) / 1000);
   XSetErrorHandler (x_error_handler);
   XSetIOErrorHandler (x_IO_error_handler);
 
-#ifndef WINDOWSNT
+#ifndef WIN32_NATIVE
   XtAppAddInput (Xt_app_con, signal_event_pipe[0],
                 (XtPointer) (XtInputReadMask /* | XtInputExceptMask */),
                 Xt_what_callback, 0);
@@ -3032,6 +3373,8 @@ init_event_Xt_late (void) /* called when already initialized */
                         NULL, 0,
                         XtCacheByDisplay, EmacsFreeXIMStyles);
 #endif /* XIM_XLIB */
+  /* Add extra actions to native widgets to handle focus and friends. */
+  emacs_Xt_event_add_widget_actions (Xt_app_con);
 
   /* insert the visual inheritance patch/hack described above */
   orig_shell_init_proc = shellClassRec.core_class.initialize;