XEmacs 21.2.18 "Toshima".
[chise/xemacs-chise.git.1] / src / event-Xt.c
index e852322..fcc8a92 100644 (file)
@@ -31,7 +31,6 @@ Boston, MA 02111-1307, USA.  */
 
 #include "blocktype.h"
 #include "buffer.h"
-#include "commands.h"
 #include "console.h"
 #include "console-tty.h"
 #include "events.h"
@@ -79,6 +78,7 @@ Boston, MA 02111-1307, USA.  */
 #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;
 
@@ -181,7 +181,7 @@ x_reset_key_mapping (struct device *d)
   Display *display = DEVICE_X_DISPLAY (d);
   struct x_device *xd = DEVICE_X_DATA (d);
   KeySym *keysym, *keysym_end;
-  Lisp_Object hashtable;
+  Lisp_Object hash_table;
   int key_code_count, keysyms_per_code;
 
   if (xd->x_keysym_map)
@@ -194,12 +194,12 @@ x_reset_key_mapping (struct device *d)
     XGetKeyboardMapping (display, xd->x_keysym_map_min_code, key_code_count,
                         &xd->x_keysym_map_keysyms_per_code);
 
-  hashtable = xd->x_keysym_map_hashtable;
-  if (HASHTABLEP (hashtable))
-    Fclrhash (hashtable);
+  hash_table = xd->x_keysym_map_hash_table;
+  if (HASH_TABLEP (hash_table))
+    Fclrhash (hash_table);
   else
-    xd->x_keysym_map_hashtable = hashtable =
-      make_lisp_hashtable (128, HASHTABLE_NONWEAK, HASHTABLE_EQUAL);
+    xd->x_keysym_map_hash_table = hash_table =
+      make_lisp_hash_table (128, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL);
 
   for (keysym = xd->x_keysym_map,
         keysyms_per_code = xd->x_keysym_map_keysyms_per_code,
@@ -217,8 +217,8 @@ x_reset_key_mapping (struct device *d)
        Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[0], 0);
        if (name)
          {
-           Fputhash (build_string (name), Qsans_modifiers, hashtable);
-           Fputhash (sym, Qsans_modifiers, hashtable);
+           Fputhash (build_string (name), Qsans_modifiers, hash_table);
+           Fputhash (sym, Qsans_modifiers, hash_table);
          }
       }
 
@@ -229,10 +229,10 @@ x_reset_key_mapping (struct device *d)
            {
              char *name = XKeysymToString (keysym[j]);
              Lisp_Object sym = x_keysym_to_emacs_keysym (keysym[j], 0);
-             if (name && NILP (Fgethash (sym, hashtable, Qnil)))
+             if (name && NILP (Fgethash (sym, hash_table, Qnil)))
                {
-                 Fputhash (build_string (name), Qt, hashtable);
-                 Fputhash (sym, Qt, hashtable);
+                 Fputhash (build_string (name), Qt, hash_table);
+                 Fputhash (sym, Qt, hash_table);
                }
            }
        }
@@ -450,7 +450,7 @@ void
 x_init_modifier_mapping (struct device *d)
 {
   struct x_device *xd = DEVICE_X_DATA (d);
-  xd->x_keysym_map_hashtable = Qnil;
+  xd->x_keysym_map_hash_table = Qnil;
   xd->x_keysym_map = NULL;
   xd->x_modifier_keymap = NULL;
   x_reset_modifier_mapping (d);
@@ -658,6 +658,9 @@ void
 emacs_Xt_mapping_action (Widget w, XEvent* event)
 {
   struct device *d = get_device_from_display (event->xany.display);
+
+  if (DEVICE_X_BEING_DELETED (d))
+    return;
 #if 0
   /* nyet.  Now this is handled by Xt. */
   XRefreshKeyboardMapping (&event->xmapping);
@@ -794,7 +797,8 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
          than passing in 0) to avoid crashes on German IRIX */
       char dummy[256];
       XLookupString (event, dummy, 200, &keysym, 0);
-      return x_keysym_to_emacs_keysym (keysym, simple_p);
+      return (IsModifierKey (keysym) || keysym == XK_Mode_switch )
+       ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p);
     }
 #endif /* ! XIM_MOTIF */
 
@@ -804,7 +808,8 @@ 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
@@ -843,7 +848,8 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
     {
     case XLookupKeySym:
     case XLookupBoth:
-      return x_keysym_to_emacs_keysym (keysym, simple_p);
+      return (IsModifierKey (keysym) || keysym == XK_Mode_switch )
+       ? Qnil : x_keysym_to_emacs_keysym (keysym, simple_p);
 
     case XLookupChars:
       {
@@ -921,6 +927,10 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
   struct device *d    = get_device_from_display (display);
   struct x_device *xd = DEVICE_X_DATA (d);
 
+  if (DEVICE_X_BEING_DELETED (d))
+     /* #### Uh, is this 0 correct? */
+     return 0;
+
   set_last_server_timestamp (d, x_event);
 
   switch (x_event->type)
@@ -983,20 +993,16 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
          {
            Lisp_Object keysym;
            XKeyEvent *ev = &x_event->xkey;
-           KeyCode keycode = ev->keycode;
-
-           if (x_key_is_modifier_p (keycode, d)) /* it's a modifier key */
-             return 0;
-
            /* This used to compute the frame from the given X window and
               store it here, but we really don't care about the frame. */
            emacs_event->channel = DEVICE_CONSOLE (d);
            keysym = x_to_emacs_keysym (&x_event->xkey, 0);
 
-           /* If the emacs keysym is nil, then that means that the
-              X keysym was NoSymbol, which probably means that
-              we're in the midst of reading a Multi_key sequence,
-              or a "dead" key prefix, or XIM input.  Ignore it. */
+           /* If the emacs keysym is nil, then that means that the X
+              keysym was either a Modifier or NoSymbol, which
+              probably means that we're in the midst of reading a
+              Multi_key sequence, or a "dead" key prefix, or XIM
+              input. Ignore it. */
            if (NILP (keysym))
              return 0;
 
@@ -1042,6 +1048,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
          {
            XButtonEvent *ev = &x_event->xbutton;
            struct frame *frame = x_window_to_frame (d, ev->window);
+
            if (! frame)
              return 0; /* not for us */
            XSETFRAME (emacs_event->channel, frame);
@@ -1054,7 +1061,11 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
            emacs_event->event.button.button    = ev->button;
            emacs_event->event.button.x         = ev->x;
            emacs_event->event.button.y         = ev->y;
-
+           /* because we don't seem to get a FocusIn event for button clicks
+              when a widget-glyph is selected we will assume that we want the
+              focus if a button gets pressed. */
+           if (x_event->type == ButtonPress)
+             handle_focus_event_1 (frame, 1);
          }
       }
     break;
@@ -1131,7 +1142,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
            emacs_event->timestamp  = DEVICE_X_LAST_SERVER_TIMESTAMP (d);
 
            state=DndDragButtons(x_event);
-           
+
            if (state & ShiftMask)      modifiers |= MOD_SHIFT;
            if (state & ControlMask)    modifiers |= MOD_CONTROL;
            if (state & xd->MetaMask)   modifiers |= MOD_META;
@@ -1178,7 +1189,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
                l_type = Qdragdrop_MIME;
                l_dndlist = list1 ( list3 ( list1 ( make_string ((Bufbyte *)"text/plain", 10) ),
                                            make_string ((Bufbyte *)"8bit", 4),
-                                           make_ext_string ((Extbyte *)data, 
+                                           make_ext_string ((Extbyte *)data,
                                                             strlen((char *)data),
                                                             FORMAT_CTEXT) ) );
                break;
@@ -1200,7 +1211,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
              case DndLink:
              case DndExe:
                {
-                 char *hurl = dnd_url_hexify_string (data, "file:");
+                 char *hurl = dnd_url_hexify_string ((char *) data, "file:");
 
                  l_dndlist = list1 ( make_string ((Bufbyte *)hurl,
                                                   strlen (hurl)) );
@@ -1212,7 +1223,7 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
              case DndURL:
                /* as it is a real URL it should already be escaped
                   and escaping again will break them (cause % is unsave) */
-               l_dndlist = list1 ( make_ext_string ((Extbyte *)data, 
+               l_dndlist = list1 ( make_ext_string ((Extbyte *)data,
                                                     strlen ((char *)data),
                                                     FORMAT_FILENAME) );
                l_type = Qdragdrop_URL;
@@ -1300,8 +1311,12 @@ x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
 static void
 handle_focus_event_1 (struct frame *f, int in_p)
 {
-#ifdef HAVE_XIM
-  XIM_focus_event (f, in_p);
+#if XtSpecificationRelease > 5
+  Widget focus_widget = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f));
+#endif
+#if defined(HAVE_XIM) && defined(XIM_XLIB)
+  if (FRAME_X_XIC(f))
+    XIM_focus_event (f, in_p);
 #endif /* HAVE_XIM */
 
   /* On focus change, clear all memory of sticky modifiers
@@ -1315,7 +1330,26 @@ handle_focus_event_1 (struct frame *f, int in_p)
      Actually, we half handle it: we handle it as far as changing the
      box cursor for redisplay, but we don't call any hooks or do any
      select-frame stuff until after the sit-for.
-   */
+
+     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
+     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
+     click in the frame. Why is this?  */
+  if (in_p 
+#if XtSpecificationRelease > 5      
+      && FRAME_X_TEXT_WIDGET (f) != focus_widget
+#endif
+      )
+    {
+      lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f),
+                            FRAME_X_TEXT_WIDGET (f));
+    }
+  /* do the generic event-stream stuff. */
   {
     Lisp_Object frm;
     Lisp_Object conser;
@@ -1337,14 +1371,17 @@ void emacs_Xt_handle_focus_event (XEvent *event);
 void
 emacs_Xt_handle_focus_event (XEvent *event)
 {
+  struct device *d = get_device_from_display (event->xany.display);
+  struct frame *f;
+
+  if (DEVICE_X_BEING_DELETED (d))
+    return;
+
   /*
    * It's curious that we're using x_any_window_to_frame() instead
    * of x_window_to_frame().  I don't know what the impact of this is.
    */
-
-  struct frame *f =
-    x_any_window_to_frame (get_device_from_display (event->xany.display),
-                          event->xfocus.window);
+  f = x_any_window_to_frame (d, event->xfocus.window);
   if (!f)
     /* focus events are sometimes generated just before
        a frame is destroyed. */
@@ -1397,7 +1434,7 @@ handle_map_event (struct frame *f, XEvent *event)
 
       /* Bleagh!!!!!!  Apparently some window managers (e.g. MWM)
         send synthetic MapNotify events when a window is first
-        created, EVENT IF IT'S CREATED ICONIFIED OR INVISIBLE.
+        created, EVEN IF IT'S CREATED ICONIFIED OR INVISIBLE.
         Or something like that.  We initially tried a different
         solution below, but that ran into a different window-
         manager bug.
@@ -1511,7 +1548,7 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
   XEvent *event = &emacs_event->event.magic.underlying_x_event;
   struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
 
-  if (!FRAME_LIVE_P (f))
+  if (!FRAME_LIVE_P (f) || DEVICE_X_BEING_DELETED (XDEVICE (FRAME_DEVICE (f))))
     return;
 
   switch (event->type)
@@ -1572,6 +1609,7 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
 
     case FocusIn:
     case FocusOut:
+
 #ifdef EXTERNAL_WIDGET
       /* External widget lossage: Ben said:
         YUCK.  The only way to make focus changes work properly is to
@@ -1587,7 +1625,7 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
       handle_client_message (f, event);
       break;
 
-    case VisibilityNotify: /* window visiblity has changed */
+    case VisibilityNotify: /* window visibility has changed */
       if (event->xvisibility.window == XtWindow (FRAME_X_SHELL_WIDGET (f)))
        {
          FRAME_X_TOTALLY_VISIBLE_P (f) =
@@ -1606,8 +1644,9 @@ emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
       break;
 
     case ConfigureNotify:
-#ifdef HAVE_XIM
-      XIM_SetGeometry (f);
+#if defined(HAVE_XIM) && defined(XIM_XLIB)
+      if (FRAME_X_XIC(f))
+       XIM_SetGeometry (f);
 #endif
       break;
 
@@ -1686,7 +1725,7 @@ emacs_Xt_remove_timeout (int id)
   struct Xt_timeout *timeout, *t2;
 
   timeout = NULL;
-  
+
   /* Find the timeout on the list of pending ones, if it's still there. */
   if (pending_timeouts)
     {
@@ -1749,6 +1788,8 @@ Xt_timeout_to_emacs_event (struct Lisp_Event *emacs_event)
   /* timeout events have nil as channel */
   emacs_event->timestamp  = 0; /* #### wrong!! */
   emacs_event->event.timeout.interval_id = timeout->id;
+  emacs_event->event.timeout.function = Qnil;
+  emacs_event->event.timeout.object = Qnil;
   Blocktype_free (the_Xt_timeout_blocktype, timeout);
 }
 
@@ -2889,18 +2930,18 @@ vars_of_event_Xt (void)
   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->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;
-  Xt_event_stream->remove_timeout_cb   = emacs_Xt_remove_timeout;
-  Xt_event_stream->select_console_cb   = emacs_Xt_select_console;
-  Xt_event_stream->unselect_console_cb         = emacs_Xt_unselect_console;
-  Xt_event_stream->select_process_cb   = emacs_Xt_select_process;
-  Xt_event_stream->unselect_process_cb         = emacs_Xt_unselect_process;
-  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->event_pending_p      = emacs_Xt_event_pending_p;
+  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;
+  Xt_event_stream->remove_timeout_cb    = emacs_Xt_remove_timeout;
+  Xt_event_stream->select_console_cb    = emacs_Xt_select_console;
+  Xt_event_stream->unselect_console_cb          = emacs_Xt_unselect_console;
+  Xt_event_stream->select_process_cb    = emacs_Xt_select_process;
+  Xt_event_stream->unselect_process_cb          = emacs_Xt_unselect_process;
+  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;
 
   DEFVAR_BOOL ("modifier-keys-are-sticky", &modifier_keys_are_sticky /*
 *Non-nil makes modifier keys sticky.