(coded-charset-entity-reference-alist): Add setting for
[chise/xemacs-chise.git.1] / src / event-Xt.c
index 8c55b2b..ccfde91 100644 (file)
@@ -67,7 +67,9 @@ Boston, MA 02111-1307, USA.  */
 
 #include "events-mod.h"
 
+void enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p);
 static void handle_focus_event_1 (struct frame *f, int in_p);
+static void handle_focus_event_2 (Window w, struct frame *f, int in_p);
 
 static struct event_stream *Xt_event_stream;
 
@@ -310,9 +312,11 @@ maybe_define_x_key_as_self_inserting_character (KeySym keysym, Lisp_Object symbo
     {
       extern Lisp_Object Vcurrent_global_map;
       extern Lisp_Object Qascii_character;
-      Fput (symbol, Qascii_character, character);
-      if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil)))
-       Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command);
+      if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil))) 
+        {
+         Fput (symbol, Qascii_character, character);
+         Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command); 
+        }
     }
 }
 
@@ -457,7 +461,14 @@ x_reset_modifier_mapping (struct device *d)
   xd->lock_interpretation = 0;
 
   if (xd->x_modifier_keymap)
-    XFreeModifiermap (xd->x_modifier_keymap);
+    {
+      XFreeModifiermap (xd->x_modifier_keymap);
+      /* Set it to NULL in case we receive two MappingModifier events in a
+         row, and the second is processed during some CHECK_QUITs within
+         x_reset_key_mapping. If that happens, XFreeModifierMap will be
+         called twice on the same map, and we crash.  */
+      xd->x_modifier_keymap = NULL;
+    }
 
   x_reset_key_mapping (d);
 
@@ -864,7 +875,7 @@ emacs_Xt_mapping_action (Widget w, XEvent* event)
     case MappingKeyboard:  x_reset_key_mapping      (d); break;
     case MappingModifier:  x_reset_modifier_mapping (d); break;
     case MappingPointer:   /* Do something here? */      break;
-    default: abort();
+    default: ABORT();
     }
 }
 
@@ -1536,6 +1547,16 @@ x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event)
 static void
 handle_focus_event_1 (struct frame *f, int in_p)
 {
+  handle_focus_event_2 (XtWindow (FRAME_X_TEXT_WIDGET (f)), f, in_p);
+}
+
+static void
+handle_focus_event_2 (Window win, struct frame *f, int in_p)
+{
+  /* Although this treats focus differently for all widgets (including
+     the frame) it seems to work ok. */
+  Widget needs_it = XtWindowToWidget (FRAME_X_DISPLAY (f), win);
+
 #if XtSpecificationRelease > 5
   widget_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f));
 #endif
@@ -1566,14 +1587,19 @@ handle_focus_event_1 (struct frame *f, int in_p)
      click in the frame. Why is this?  */
   if (in_p
 #if XtSpecificationRelease > 5
-      && FRAME_X_TEXT_WIDGET (f) != widget_with_focus
+      && needs_it != widget_with_focus
 #endif
       )
     {
-      lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f),
-                            FRAME_X_TEXT_WIDGET (f));
+      lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), needs_it);
     }
 
+  /* If we are focusing on a native widget then record and exit. */
+  if (needs_it != FRAME_X_TEXT_WIDGET (f)) {
+    widget_with_focus = needs_it;
+    return;
+  }
+
   /* We have the focus now. See comment in
      emacs_Xt_handle_widget_losing_focus (). */
   if (in_p)
@@ -1595,9 +1621,26 @@ handle_focus_event_1 (struct frame *f, int in_p)
   }
 }
 
+/* Create a synthetic X focus event. */
+void
+enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p)
+{
+  Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
+  Lisp_Event *ev          = XEVENT (emacs_event);
+  XEvent *x_event = &ev->event.magic.underlying_x_event;
+
+  x_event->type = in_p ? FocusIn : FocusOut;
+  x_event->xfocus.window = XtWindow (wants_it);
+
+  ev->channel              = frame;
+  ev->event_type           = magic_event;
+
+  enqueue_Xt_dispatch_event (emacs_event);
+}
+
 /* 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
+   well just get deleted next and then 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
@@ -1924,7 +1967,7 @@ emacs_Xt_handle_magic_event (Lisp_Event *emacs_event)
       if (FRAME_X_EXTERNAL_WINDOW_P (f))
        break;
 #endif
-      handle_focus_event_1 (f, event->type == FocusIn);
+      handle_focus_event_2 (event->xfocus.window, f, event->type == FocusIn);
       break;
 
     case ClientMessage:
@@ -1973,12 +2016,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. */
 
+/* pending_timeouts is a set (unordered), implemented as a stack.
+   completed_timeouts* is a queue. */
 static struct Xt_timeout
 {
   int id;
   XtIntervalId interval_id;
   struct Xt_timeout *next;
-} *pending_timeouts, *completed_timeouts;
+} *pending_timeouts, *completed_timeouts_head, *completed_timeouts_tail;
 
 static struct Xt_timeout_blocktype
 {
@@ -1991,7 +2036,7 @@ Xt_timeout_callback (XtPointer closure, XtIntervalId *id)
 {
   struct Xt_timeout *timeout = (struct Xt_timeout *) closure;
   struct Xt_timeout *t2 = pending_timeouts;
-  /* Remove this one from the list of pending timeouts */
+  /* Remove this one from the set of pending timeouts */
   if (t2 == timeout)
     pending_timeouts = pending_timeouts->next;
   else
@@ -2000,9 +2045,13 @@ Xt_timeout_callback (XtPointer closure, XtIntervalId *id)
       assert (t2->next);
       t2->next = t2->next->next;
     }
-  /* Add this one to the list of completed timeouts */
-  timeout->next = completed_timeouts;
-  completed_timeouts = timeout;
+  /* Add this one to the queue of completed timeouts */
+  timeout->next = NULL;
+  if (completed_timeouts_head)
+    completed_timeouts_tail->next = timeout;
+  else
+    completed_timeouts_head = timeout;
+  completed_timeouts_tail = timeout;
 }
 
 static int
@@ -2057,24 +2106,27 @@ emacs_Xt_remove_timeout (int id)
        XtRemoveTimeOut (timeout->interval_id);
     }
 
-  /* It could be that the Xt call back was already called but we didn't convert
-     into an Emacs event yet */
-  if (!timeout && completed_timeouts)
+  /* It could be that Xt_timeout_callback was already called but we didn't
+     convert into an Emacs event yet */
+  if (!timeout && completed_timeouts_head)
     {
-      /* Code duplication! */
-      if (id == completed_timeouts->id)
+      /* Thank God for code duplication! */
+      if (id == completed_timeouts_head->id)
        {
-         timeout = completed_timeouts;
-         completed_timeouts = completed_timeouts->next;
+         timeout = completed_timeouts_head;
+         completed_timeouts_head = completed_timeouts_head->next;
+         /* this may not be necessary? */
+         if (!completed_timeouts_head) completed_timeouts_tail = NULL;
        }
       else
        {
-         t2 = completed_timeouts;
+         t2 = completed_timeouts_head;
          while (t2->next && t2->next->id != id) t2 = t2->next;
-         if ( t2->next)   /*found it */
+         if (t2->next)   /* found it */
            {
              timeout = t2->next;
              t2->next = t2->next->next;
+             if (!t2->next) completed_timeouts_tail = t2;
            }
        }
     }
@@ -2089,9 +2141,11 @@ emacs_Xt_remove_timeout (int id)
 static void
 Xt_timeout_to_emacs_event (Lisp_Event *emacs_event)
 {
-  struct Xt_timeout *timeout = completed_timeouts;
+  struct Xt_timeout *timeout = completed_timeouts_head;
   assert (timeout);
-  completed_timeouts = completed_timeouts->next;
+  completed_timeouts_head = completed_timeouts_head->next;
+  /* probably unnecessary */
+  if (!completed_timeouts_head) completed_timeouts_tail = NULL;
   emacs_event->event_type = timeout_event;
   /* timeout events have nil as channel */
   emacs_event->timestamp  = 0; /* #### wrong!! */
@@ -2333,7 +2387,7 @@ Xt_process_to_emacs_event (Lisp_Event *emacs_event)
          return;
        }
     }
-  abort ();
+  ABORT ();
 }
 
 static void
@@ -2663,7 +2717,7 @@ emacs_Xt_next_event (Lisp_Event *emacs_event)
  we_didnt_get_an_event:
 
   while (NILP (dispatch_event_queue) &&
-        !completed_timeouts         &&
+        !completed_timeouts_head    &&
         !fake_event_occurred        &&
         !process_events_occurred    &&
         !tty_events_occurred)
@@ -2717,7 +2771,7 @@ emacs_Xt_next_event (Lisp_Event *emacs_event)
       if (!Xt_tty_to_emacs_event (emacs_event))
        goto we_didnt_get_an_event;
     }
-  else if (completed_timeouts)
+  else if (completed_timeouts_head)
     Xt_timeout_to_emacs_event (emacs_event);
   else if (fake_event_occurred)
     {
@@ -2903,8 +2957,47 @@ emacs_Xt_quit_p (void)
 static void
 drain_X_queue (void)
 {
+  Lisp_Object devcons, concons;
+  CONSOLE_LOOP (concons)
+  {
+    struct console *con = XCONSOLE (XCAR (concons));
+    if (!con->input_enabled)
+      continue;
+
+    /* sjt sez: Have you tried the loop over devices with XtAppPending(),
+       not XEventsQueued()?
+       Ben Sigelman sez: No.
+       sjt sez: I'm guessing that the reason that your patch "works" is this:
+
+       +      struct device* d;
+       +      Display* display;
+       +      d = XDEVICE (XCAR (devcons));
+       +      if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) {
+
+       Ie, if the device goes down, XEmacs detects that and deletes it.
+       Then the if() fails (DEVICE_X_DISPLAY(d) is NULL), and we don't go
+       into the Xlib-of-no-return.  If you know different, I'd like to hear
+       about it. ;-)
+
+       These ideas haven't been tested; the code below works for Ben.
+    */
+    CONSOLE_DEVICE_LOOP (devcons, con)
+    {
+      struct device* d;
+      Display* display;
+      d = XDEVICE (XCAR (devcons));
+      if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) {
+        display = DEVICE_X_DISPLAY (d);
+        while (XEventsQueued (display, QueuedAfterReading))
+          XtAppProcessEvent (Xt_app_con, XtIMXEvent);
+      }
+    }
+  }
+  /* This is the old code, before Ben Sigelman's patch. */
+  /*
   while (XtAppPending (Xt_app_con) & XtIMXEvent)
     XtAppProcessEvent (Xt_app_con, XtIMXEvent);
+  */
 }
 
 static int
@@ -3087,7 +3180,7 @@ XtConvertArgRec Const colorConvertArgs[] = {
 
 /* JH: We use this because I think there's a possibility this
    is called before the device is properly set up, in which case
-   I don't want to abort. */
+   I don't want to ABORT. */
 extern struct device *get_device_from_display_1 (Display *dpy);
 
 static
@@ -3336,8 +3429,9 @@ void
 init_event_Xt_late (void) /* called when already initialized */
 {
   timeout_id_tick = 1;
-  pending_timeouts = 0;
-  completed_timeouts = 0;
+  pending_timeouts = NULL;
+  completed_timeouts_head = NULL; /* queue is empty */
+  completed_timeouts_tail = NULL; /* just to be picky */
 
   event_stream = Xt_event_stream;