diff src/event-Xt.c @ 70:131b0175ea99 r20-0b30

Import from CVS: tag r20-0b30
author cvs
date Mon, 13 Aug 2007 09:02:59 +0200
parents 56c54cf7c5b6
children 54cc21c15cbb
line wrap: on
line diff
--- a/src/event-Xt.c	Mon Aug 13 09:00:04 2007 +0200
+++ b/src/event-Xt.c	Mon Aug 13 09:02:59 2007 +0200
@@ -47,6 +47,13 @@
 #include <X11/CoreP.h>		/* Numerous places access the fields of
 				   a core widget directly.  We could
 				   use XtVaGetValues(), but ... */
+#ifdef HAVE_XIM
+#ifdef XIM_MOTIF
+#include <Xm/Xm.h>
+#endif
+#include "lstream.h"
+#include "mule-coding.h"
+#endif
 
 static void enqueue_Xt_dispatch_event (Lisp_Object event);
 
@@ -532,9 +539,9 @@
   struct x_device *xd = DEVICE_X_DATA (d);
 
   xd->need_to_add_mask = 0;
-  xd->last_downkey     = 0;
-  xd->release_time     = 0;
-  xd->down_mask        = 0;
+  xd->last_downkey = 0;
+  xd->release_time = 0;
+  xd->down_mask = 0;
 }
 
 static int
@@ -592,8 +599,18 @@
 /*                  X to Emacs event conversion                         */
 /************************************************************************/
 
+#if (defined(sun) || defined(__sun)) && defined(__GNUC__)
+# define SUNOS_GCC_L0_BUG
+#endif
+
+#ifdef SUNOS_GCC_L0_BUG
+static void
+x_to_emacs_keysym_sunos_bug (Lisp_Object *return_value_sunos_bug, /* #### */
+                             XKeyPressedEvent *event, int simple_p)
+#else /* !SUNOS_GCC_L0_BUG */
 static Lisp_Object
 x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
+#endif /* !SUNOS_GCC_L0_BUG */
      /* simple_p means don't try too hard (ASCII only) */
 {
   char *name;
@@ -602,35 +619,128 @@
      passing in 0) to avoid crashes on German IRIX */
   char dummy[256];
 
-  /* ### FIX this by replacing with calls to XmbLookupString.
-     XLookupString should never be called. --mrb */
+#ifdef HAVE_XIM
+  int len;
+  char buffer[64];
+  char *bufptr = buffer;
+  int   bufsiz = sizeof (buffer);
+  Status status;
+#endif
+
+#ifdef SUNOS_GCC_L0_BUG
+# define return(lose) \
+  do {*return_value_sunos_bug = (lose); goto return_it; } while (0)
+#endif
+
+#ifdef HAVE_XIM
+#ifdef XIM_MOTIF
+#define LOOKUPSTRING \
+  len = XmImMbLookupString (XtWindowToWidget (event->display, event->window), \
+			  event, bufptr, bufsiz, &keysym, &status);
+#else /* XIM_XLIB */
+#define LOOKUPSTRING \
+  len = XmbLookupString \
+    (FRAME_X_XIC (x_window_to_frame \
+		  (get_device_from_display (event->display), event->window)), \
+     event, bufptr, bufsiz, &keysym, &status);
+#endif /* XIM_XLIB */
+ LOOKUPSTRING;
+ check_status:
+
+#ifdef DEBUG_XEMACS
+  if (x_debug_events > 0)
+    {
+      stderr_out ("   status=");
+#define print_status_when(S) if (status == S) stderr_out (#S)
+      print_status_when (XLookupKeySym);
+      print_status_when (XLookupBoth);
+      print_status_when (XLookupChars);
+      print_status_when (XLookupNone);
+      print_status_when (XBufferOverflow);
+      
+      if (status == XLookupKeySym || status == XLookupBoth)
+	stderr_out (" keysym=%s",  XKeysymToString (keysym));
+      if (status == XLookupChars  || status == XLookupBoth)
+	{
+	  if (len != 1)
+	    {
+	      int j;
+	      stderr_out (" chars=\"");
+	      for (j=0; j<len; j++)
+		stderr_out ("%c", bufptr[j]);
+	      stderr_out ("\"");
+	    }
+	  else if (bufptr[0] <= 32 || bufptr[0] >= 127)
+	    stderr_out (" char=0x%x", bufptr[0]);
+	  else
+	    stderr_out (" char=%c", bufptr[0]);
+	}
+      stderr_out ("\n");
+    }
+#endif /* DEBUG_XEMACS */
+
+  switch (status)
+    {
+    case XLookupKeySym:
+    case XLookupBoth: break;
+
+    case XLookupChars:
+      {
+	/* Generate multiple emacs events */
+	struct device *d = get_device_from_display (event->display);
+        Emchar ch;
+        Lisp_Object instream =
+          make_fixed_buffer_input_stream ((unsigned char *) bufptr, len);
+
+        /* ### Use Fget_coding_system (Vcomposed_input_coding_system) */
+        instream =
+	  make_decoding_input_stream (XLSTREAM (instream),
+				      Fget_coding_system (Qautodetect));
+        
+        while ((ch = Lstream_get_emchar (XLSTREAM (instream))) != EOF)
+          {
+            Lisp_Object emacs_event = Fmake_event ();
+            XEVENT (emacs_event)->channel	      = DEVICE_CONSOLE (d);
+            XEVENT (emacs_event)->event_type	      = key_press_event;
+            XEVENT (emacs_event)->timestamp	      = event->time;
+            XEVENT (emacs_event)->event.key.modifiers = 0;
+            XEVENT (emacs_event)->event.key.keysym    = make_char (ch);
+            enqueue_Xt_dispatch_event (emacs_event);
+          }
+        Lstream_close (XLSTREAM (instream));
+	return Qnil;
+      }
+    case XLookupNone: return Qnil;
+    case XBufferOverflow:
+      bufptr = alloca (len+1);
+      bufsiz = len+1;
+      LOOKUPSTRING;
+      goto check_status;
+    }
+#else /* ! HAVE_XIM */
   XLookupString (event, dummy, 200, &keysym, 0);
+#endif /* HAVE_XIM */
 
   if (keysym >= XK_exclam && keysym <= XK_asciitilde)
     /* We must assume that the X keysym numbers for the ASCII graphic
        characters are the same as their ASCII codes.  */
-    return make_char (keysym);
+    return (make_char (keysym));
 
   switch (keysym)
     {
       /* These would be handled correctly by the default case, but by
 	 special-casing them here we don't garbage a string or call intern().
 	 */
-    case XK_BackSpace:	return QKbackspace;
-    case XK_Tab:	return QKtab;
-    case XK_Linefeed:	return QKlinefeed;
-    case XK_Return:	return QKreturn;
-    case XK_Escape:	return QKescape;
-    case XK_space:	return QKspace;
-    case XK_Delete:	return QKdelete;
-    case 0:		return Qnil;
-      /* This kludge prevents bogus Xlib compose conversions.
-         Don't ask why. The following case must be removed when we
-         switch to using XmbLookupString */
-    case XK_Multi_key: XLookupString (event, dummy, 200, &keysym, 0);
-      /* Fallthrough!! */
+    case XK_BackSpace:	return (QKbackspace);
+    case XK_Tab:	return (QKtab);
+    case XK_Linefeed:	return (QKlinefeed);
+    case XK_Return:	return (QKreturn);
+    case XK_Escape:	return (QKescape);
+    case XK_space:	return (QKspace);
+    case XK_Delete:	return (QKdelete);
+    case 0:		return (Qnil);
     default:
-      if (simple_p) return Qnil;
+      if (simple_p) return (Qnil);
       /* #### without return_value_sunos_bug, %l0 (GCC struct return pointer)
        * ####  gets roached (top 8 bits cleared) around this call.
        */
@@ -640,35 +750,45 @@
 	{
 	  char buf [255];
 	  sprintf (buf, "unknown_keysym_0x%X", (int) keysym);
-	  return KEYSYM (buf);
+	  return (KEYSYM (buf));
 	}
       /* If it's got a one-character name, that's good enough. */
-      if (!name[1])
-	return make_char (name[0]);
+      if (!name[1]) return (make_char (name[0]));
       
       /* If it's in the "Keyboard" character set, downcase it.
 	 The case of those keysyms is too totally random for us to
 	 force anyone to remember them.
 	 The case of the other character sets is significant, however.
-       */
-      if ((((unsigned int) keysym) & (~0x1FF)) == ((unsigned int) 0xFE00))
+	 */
+      if ((((unsigned int) keysym) & (~0xFF)) == ((unsigned int) 0xFF00))
 	{
 	  char buf [255];
 	  char *s1, *s2;
-	  for (s1 = name, s2 = buf; *s1; s1++, s2++) {
-	    if (*s1 == '_') {
-	      *s2 = '-';
-	    } else {
-	      *s2 = tolower (* (unsigned char *) s1);
-	    }
-	  }
+	  for (s1 = name, s2 = buf; *s1; s1++, s2++)
+	    *s2 = tolower (* (unsigned char *) s1);
 	  *s2 = 0;
-	  return KEYSYM (buf);
+	  return (KEYSYM (buf));
 	}
-      return KEYSYM (name);
+      return (KEYSYM (name));
     }
+#ifdef SUNOS_GCC_L0_BUG
+# undef return
+ return_it:
+  return;
+#endif
 }
 
+#ifdef SUNOS_GCC_L0_BUG
+/* #### */
+static Lisp_Object
+x_to_emacs_keysym (XKeyPressedEvent *event, int simple_p)
+{
+  Lisp_Object return_value_sunos_bug;
+  x_to_emacs_keysym_sunos_bug (&return_value_sunos_bug, event, simple_p);
+  return (return_value_sunos_bug);
+}
+#endif
+
 static void
 set_last_server_timestamp (struct device *d, XEvent *x_event)
 {
@@ -748,7 +868,7 @@
 	     turn C-x into C-X, which would suck.
 	   - the event was a mouse event. */
 	if (modifiers || ! key_event_p)
-	  *state &= (~LockMask);
+          *state &= (~LockMask);
 
 	shift_p = *state & ShiftMask;
 	lock_p  = *state & LockMask;
@@ -769,7 +889,7 @@
 	       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,
@@ -822,16 +942,16 @@
 	    if (! frame)
 	      return 0;	/* not for us */
 	    XSETFRAME (emacs_event->channel, frame);
-
+            
 	    emacs_event->event_type = (x_event->type == ButtonPress) ?
 	      button_press_event : button_release_event;
-
+            
 	    emacs_event->event.button.modifiers = modifiers;
-            emacs_event->timestamp              = ev->time;
-            emacs_event->event.button.button    = ev->button;
-            emacs_event->event.button.x	        = ev->x;
-            emacs_event->event.button.y	        = ev->y;
-          }
+	    emacs_event->timestamp		= ev->time;
+	    emacs_event->event.button.button	= ev->button;
+	    emacs_event->event.button.x		= ev->x;
+	    emacs_event->event.button.y		= ev->y;
+	  }
       }
     break;
       
@@ -936,6 +1056,7 @@
   return 1;
 }
 
+
 
 /************************************************************************/
 /*                           magic-event handling                       */
@@ -944,6 +1065,10 @@
 static void
 handle_focus_event_1 (struct frame *f, int in_p)
 {
+#ifdef HAVE_XIM
+  XIM_focus_event (f, in_p);
+#endif /* HAVE_XIM */
+
   /* On focus change, clear all memory of sticky modifiers
      to avoid non-intuitive behavior. */
   clear_sticky_modifiers (XDEVICE (FRAME_DEVICE (f)));
@@ -992,48 +1117,6 @@
   handle_focus_event_1 (f, event->type == FocusIn);
 }
 
-/* both MapNotify and VisibilityNotify can cause this
-   JV is_visible has the same semantics as f->visible*/
-static void
-change_frame_visibility (struct frame *f, int is_visible)
-{
-  Lisp_Object frame = Qnil;
-
-  XSETFRAME (frame, f);
-
-  if (!FRAME_VISIBLE_P (f) && is_visible)
-    {
-      FRAME_VISIBLE_P (f) = is_visible;
-      /* This improves the double flicker when uniconifying a frame
-	 some.  A lot of it is not showing a buffer which has changed
-	 while the frame was iconified.  To fix it further requires
-	 the good 'ol double redisplay structure. */
-      MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
-      va_run_hook_with_args (Qmap_frame_hook, 1, frame);
-#ifdef EPOCH
-      dispatch_epoch_event (f, event, Qx_map);
-#endif
-    }
-  else if (FRAME_VISIBLE_P (f) && !is_visible) 
-    {
-      FRAME_VISIBLE_P (f) = 0;
-      va_run_hook_with_args (Qunmap_frame_hook, 1, frame);
-#ifdef EPOCH
-      dispatch_epoch_event (f, event, Qx_unmap);
-#endif
-    }
-  else if (FRAME_VISIBLE_P (f) * is_visible < 0)
-    {
-      FRAME_VISIBLE_P(f) = - FRAME_VISIBLE_P(f);
-      if (FRAME_REPAINT_P(f))
-	      MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
-      va_run_hook_with_args (Qmap_frame_hook, 1, frame);
-#ifdef EPOCH
-      dispatch_epoch_event (f, event, Qx_map);
-#endif
-    }
-}
-
 static void
 handle_map_event (struct frame *f, XEvent *event)
 {
@@ -1090,14 +1173,34 @@
 	 rather than consulting some internal (and likely
 	 inaccurate) state flag.  Therefore, ignoring the MapNotify
 	 is correct. */
-      if (!FRAME_VISIBLE_P (f) && NILP (Fframe_iconified_p (frame)))
+      if (!f->visible && NILP (Fframe_iconified_p (frame)))
 #endif
-      change_frame_visibility (f, 1);
+      if (!f->visible)
+	{
+	  f->visible = 1;
+	  /* This improves the double flicker when uniconifying a frame
+	     some.  A lot of it is not showing a buffer which has changed
+	     while the frame was iconified.  To fix it further requires
+	     the good 'ol double redisplay structure. */
+	  MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
+	  va_run_hook_with_args (Qmap_frame_hook, 1, frame);
+#ifdef EPOCH
+	  dispatch_epoch_event (f, event, Qx_map);
+#endif
+	}
     }
   else
     {
       FRAME_X_TOTALLY_VISIBLE_P (f) = 0;
-      change_frame_visibility (f, 0);
+      if (f->visible)
+	{
+	  f->visible = 0;
+	  va_run_hook_with_args (Qunmap_frame_hook, 1, frame);
+#ifdef EPOCH
+	  dispatch_epoch_event (f, event, Qx_unmap);
+#endif
+	}
+
       /* Calling Fframe_iconified_p is the only way we have to
          correctly update FRAME_ICONIFIED_P */
       Fframe_iconified_p (frame);
@@ -1123,7 +1226,7 @@
 	 this is so that clicking on the close-box will make emacs prompt
 	 using a dialog box instead of the minibuffer if there are unsaved
 	 buffers.
-       */
+	 */
       enqueue_misc_user_event (frame, Qeval,
 			       list3 (Qdelete_frame, frame, Qt));
     }
@@ -1243,27 +1346,17 @@
       break;
       
     case VisibilityNotify: /* window visiblity has changed */
-      if (event->xvisibility.window == XtWindow (FRAME_X_SHELL_WIDGET (f)))
-	{
-	  FRAME_X_TOTALLY_VISIBLE_P (f) =
-	    (event->xvisibility.state == VisibilityUnobscured);
-	  /* Note that the fvwm pager only sends VisibilityNotify when
-	     changing pages. Is this all we need to do ? JV */
-	  /* Nope.  We must at least trigger a redisplay here.  
-             Since this case seems similar to MapNotify, I've 
-             factored out some code to change_frame_visibility(). 
-	     This triggers the necessary redisplay and runs
-	     (un)map-frame-hook.  - dkindred@cs.cmu.edu */
-	  /* Changed it again to support the tristate visibility flag */
-	  change_frame_visibility (f, (event->xvisibility.state
-				       != VisibilityFullyObscured) ? 1 : -1);
-	}
+      if (event->xvisibility.state == VisibilityUnobscured)
+	FRAME_X_TOTALLY_VISIBLE_P (f) = 1;
+      else
+	FRAME_X_TOTALLY_VISIBLE_P (f) = 0;
       break;
       
     case ConfigureNotify:
 #ifdef HAVE_XIM
       XIM_SetGeometry (f);
 #endif
+#if 0
       /* ### If the following code fails to work, simply always call
          x_smash_bastardly_shell_position always.  In this case we no
          longer rely on the data in the events, merely on their
@@ -1281,6 +1374,7 @@
           FRAME_X_SHELL_WIDGET (f)->core.y = ev->y;
         }
       }
+#endif
       break;
 
     default:
@@ -2521,6 +2615,11 @@
   completed_timeouts = 0;
 
   event_stream = Xt_event_stream;
+  
+#ifdef HAVE_XIM
+  Initialize_Locale();
+#endif /* HAVE_XIM */
+  
   XtToolkitInitialize ();
   Xt_app_con = XtCreateApplicationContext ();
   XtAppSetFallbackResources (Xt_app_con, (String *) x_fallback_resources);
@@ -2538,4 +2637,12 @@
 		         EmacsXtCvtStringToPixel,
 			 (XtConvertArgList) colorConvertArgs,
 			 2, XtCacheByDisplay, EmacsFreePixel);
+
+#ifdef XIM_XLIB
+  XtAppSetTypeConverter (Xt_app_con, XtRString, XtRXimStyles,
+		         EmacsXtCvtStringToXIMStyles,
+			 NULL, 0,
+			 XtCacheByDisplay, EmacsFreeXIMStyles);
+#endif /* XIM_XLIB */
+  
 }