This commit was generated by cvs2svn to compensate for changes in r5209,
[chise/xemacs-chise.git.1] / src / event-Xt.c
index f984949..4345bb1 100644 (file)
@@ -67,7 +67,6 @@ 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;
@@ -87,14 +86,13 @@ 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;
@@ -312,9 +310,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); 
+        }
     }
 }
 
@@ -690,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;
@@ -725,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 */
     {
@@ -745,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)                                \
@@ -770,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++)
@@ -947,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;
@@ -985,7 +1009,7 @@ x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
 #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)
@@ -1146,6 +1170,25 @@ x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event)
        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
@@ -1280,6 +1323,11 @@ x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event)
         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;
@@ -1305,10 +1353,10 @@ x_event_to_emacs_event (XEvent *x_event, 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;
@@ -1322,6 +1370,11 @@ x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event)
            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;
@@ -1486,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);
@@ -1511,17 +1564,23 @@ handle_focus_event_1 (struct frame *f, int in_p)
      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 click in
-     a widget-glyph but you don't get a correspondng FocusIn when you
+     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
+      && 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;
@@ -1538,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);
@@ -1714,6 +1790,41 @@ 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)
 {
@@ -1729,8 +1840,8 @@ emacs_Xt_force_event_pending (struct frame* f)
   /* Send the drop message */
   XSendEvent(dpy, XtWindow (FRAME_X_SHELL_WIDGET (f)),
             True, NoEventMask, &event);
-  /* Force event pending to check the X queue. */
-  quit_check_signal_tick_count++;
+  /* We rely on SIGIO and friends to realise we have generated an
+     event. */
 }
 
 static void
@@ -1847,8 +1958,8 @@ emacs_Xt_handle_magic_event (Lisp_Event *emacs_event)
       break;
 
     case CreateNotify:
-      printf ("window created\n");
       break;
+
     default:
       break;
     }
@@ -2406,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);
@@ -2419,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);
@@ -2436,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);
@@ -2457,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);
@@ -2471,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);
@@ -2513,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);
@@ -2634,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);
     }
@@ -2900,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;
 
@@ -2918,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        */
@@ -3015,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 {
@@ -3079,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                            */
 /************************************************************************/
 
@@ -3107,6 +3273,8 @@ reinit_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;
 
   the_Xt_timeout_blocktype = Blocktype_new (struct Xt_timeout_blocktype);
 
@@ -3124,16 +3292,7 @@ vars_of_event_Xt (void)
   dispatch_event_queue = Qnil;
   staticpro (&dispatch_event_queue);
   dispatch_event_queue_tail = Qnil;
-  pdump_wire (&dispatch_event_queue_tail);
-
-  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;
+  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.
@@ -3142,14 +3301,14 @@ 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
 }
 
@@ -3192,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);
@@ -3214,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;