diff src/event-Xt.c @ 2:ac2d302a0011 r19-15b2

Import from CVS: tag r19-15b2
author cvs
date Mon, 13 Aug 2007 08:46:35 +0200
parents 376386a54a3c
children 4b173ad71786
line wrap: on
line diff
--- a/src/event-Xt.c	Mon Aug 13 08:45:53 2007 +0200
+++ b/src/event-Xt.c	Mon Aug 13 08:46:35 2007 +0200
@@ -165,15 +165,18 @@
 static CONST char *
 index_to_name (int indice)
 {
-  return ((indice == ShiftMapIndex ? "ModShift"
-           : (indice == LockMapIndex ? "ModLock"
-              : (indice == ControlMapIndex ? "ModControl"
-                 : (indice == Mod1MapIndex ? "Mod1"
-                    : (indice == Mod2MapIndex ? "Mod2"
-                       : (indice == Mod3MapIndex ? "Mod3"
-                          : (indice == Mod4MapIndex ? "Mod4"
-                             : (indice == Mod5MapIndex ? "Mod5"
-                                : "???")))))))));
+  switch (indice)
+    {
+    case ShiftMapIndex:   return "ModShift";
+    case LockMapIndex:    return "ModLock";   
+    case ControlMapIndex: return "ModControl";
+    case Mod1MapIndex:    return "Mod1";
+    case Mod2MapIndex:    return "Mod2";
+    case Mod3MapIndex:    return "Mod3";
+    case Mod4MapIndex:    return "Mod4";
+    case Mod5MapIndex:    return "Mod5";
+    default:              return "???";
+    }
 }
 
 /* Boy, I really wish C had local functions... */
@@ -196,13 +199,13 @@
   struct x_device *xd = DEVICE_X_DATA (d);
   int modifier_index, modifier_key, column, mkpm;
   int warned_about_overlapping_modifiers = 0;
-  int warned_about_predefined_modifiers = 0;
-  int warned_about_duplicate_modifiers = 0;
-  int meta_bit = 0;
+  int warned_about_predefined_modifiers  = 0;
+  int warned_about_duplicate_modifiers   = 0;
+  int meta_bit  = 0;
   int hyper_bit = 0;
   int super_bit = 0;
-  int alt_bit = 0;
-  int mode_bit = 0;
+  int alt_bit   = 0;
+  int mode_bit  = 0;
 
   xd->lock_interpretation = 0;
 
@@ -413,18 +416,22 @@
 static void
 x_handle_sticky_modifiers (XEvent *ev, struct device *d)
 {
-  struct x_device *xd = DEVICE_X_DATA (d);
-  KeyCode keycode = ev->xkey.keycode;
-  int type = ev->xany.type;
-  int is_modifier =
-    (type == KeyPress || type == KeyRelease) &&
-      x_key_is_modifier_p (keycode, d);
-    
-  if (!modifier_keys_are_sticky)
+  struct x_device *xd;
+  KeyCode keycode;
+  int type;
+
+  if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
     return;
 
-  if (!is_modifier)
-    {
+  xd = DEVICE_X_DATA (d);
+  keycode = ev->xkey.keycode;
+  type = ev->type;
+  
+  if (! ((type == KeyPress || type == KeyRelease) &&
+         x_key_is_modifier_p (keycode, 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 ||
@@ -440,7 +447,10 @@
       if (type == KeyPress || type == ButtonPress)
 	xd->down_mask = 0;
 
-      ev->xkey.state |= xd->need_to_add_mask;
+      if (key_event_p)
+        ev->xkey.state    |= xd->need_to_add_mask;
+      else
+        ev->xbutton.state |= xd->need_to_add_mask;
 
       if (type == KeyRelease && keycode == xd->last_downkey)
 	/* If I hold press-and-release the Control key and then press
@@ -458,13 +468,25 @@
 	   occur at the same time, the key was actually auto-
 	   repeated.  Under Open-Windows, at least, this works.
 	   */
-	xd->release_time = ev->xkey.time;
+	xd->release_time = key_event_p ? ev->xkey.time : ev->xbutton.time;
     }
-  else
+  else                          /* Modifier key pressed */
     {
+      int i;
       KeySym *syms = &xd->x_keysym_map [(keycode - xd->x_keysym_map_min_code) *
 					xd->x_keysym_map_keysyms_per_code];
-      int i;
+
+      /* If a non-modifier key was pressed in the middle of a bunch
+	 of modifiers, then it unsticks all the modifiers that were
+	 previously pressed.  We cannot unstick the modifiers until
+	 now because we want to check for auto-repeat of the
+	 non-modifier key. */
+
+      if (xd->last_downkey)
+	{
+	  xd->last_downkey = 0;
+	  xd->need_to_add_mask = 0;
+	}
 
 #define FROB(mask)				\
 do {						\
@@ -493,33 +515,16 @@
     }						\
 } while (0)
 
-      /* If a non-modifier key was pressed in the middle of a bunch
-	 of modifiers, then it unsticks all the modifiers that were
-	 previously pressed.  We cannot unstick the modifiers until
-	 now because we want to check for auto-repeat of the
-	 non-modifier key. */
-
-      if (xd->last_downkey)
-	{
-	  xd->last_downkey = 0;
-	  xd->need_to_add_mask = 0;
-	}
-
       for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++)
-	{
-	  if (syms[i] == XK_Control_L || syms[i] == XK_Control_R)
-	    FROB (ControlMask);
-	  if (syms[i] == XK_Shift_L || syms[i] == XK_Shift_R)
-	    FROB (ShiftMask);
-	  if (syms[i] == XK_Meta_L || syms[i] == XK_Meta_R)
-	    FROB (xd->MetaMask);
-	  if (syms[i] == XK_Super_L || syms[i] == XK_Super_R)
-	    FROB (xd->SuperMask);
-	  if (syms[i] == XK_Hyper_L || syms[i] == XK_Hyper_R)
-	    FROB (xd->HyperMask);
-	  if (syms[i] == XK_Alt_L || syms[i] == XK_Alt_R)
-	    FROB (xd->AltMask);
-	}
+        switch (syms[i])
+          {
+          case XK_Control_L: case XK_Control_R: FROB (ControlMask);   break;
+          case XK_Shift_L:   case XK_Shift_R:   FROB (ShiftMask);     break;
+          case XK_Meta_L:    case XK_Meta_R:    FROB (xd->MetaMask);  break;
+          case XK_Super_L:   case XK_Super_R:   FROB (xd->SuperMask); break;
+          case XK_Hyper_L:   case XK_Hyper_R:   FROB (xd->HyperMask); break;
+          case XK_Alt_L:     case XK_Alt_R:     FROB (xd->AltMask);   break;
+          }
     }
 #undef FROB
 }
@@ -539,28 +544,32 @@
 keysym_obeys_caps_lock_p (KeySym sym, struct device *d)
 {
   struct x_device *xd = DEVICE_X_DATA (d);
-  /* Eeeeevil hack.  Don't apply caps-lock to things that aren't alphabetic
+  /* Eeeeevil hack.  Don't apply Caps_Lock to things that aren't alphabetic
      characters, where "alphabetic" means something more than simply A-Z.
-     That is, if caps-lock is down, typing ESC doesn't produce Shift-ESC.
+     That is, if Caps_Lock is down, typing ESC doesn't produce Shift-ESC.
      But if shift-lock is down, then it does.
    */
   if (xd->lock_interpretation == XK_Shift_Lock)
     return 1;
-  if (((sym >= XK_A) && (sym <= XK_Z)) ||
-      ((sym >= XK_a) && (sym <= XK_z)) ||
-      ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) ||
-      ((sym >= XK_agrave) && (sym <= XK_odiaeresis)) ||
-      ((sym >= XK_Ooblique) && (sym <= XK_Thorn)) ||
-      ((sym >= XK_oslash) && (sym <= XK_thorn)))
-    return 1;
-  else
-    return 0;
+  
+  return
+    ((sym >= XK_A)        && (sym <= XK_Z))          ||
+    ((sym >= XK_a)        && (sym <= XK_z))          ||
+    ((sym >= XK_Agrave)   && (sym <= XK_Odiaeresis)) ||
+    ((sym >= XK_agrave)   && (sym <= XK_odiaeresis)) ||
+    ((sym >= XK_Ooblique) && (sym <= XK_Thorn))      ||
+    ((sym >= XK_oslash)   && (sym <= XK_thorn));
 }
 
 /* called from EmacsFrame.c (actually from Xt itself) when a
-   MappingNotify event is received.  For non-obvious reasons,
-   our event handler does not see these events, so we need a
-   special translation. */
+   MappingNotify event is received.  In its infinite wisdom, Xt
+   decided that Xt event handlers never get MappingNotify events.
+   O'Reilly Xt Programming Manual 9.1.2 says:
+   
+     MappingNotify is automatically handled by Xt, so it isn't passed
+     to event handlers and you don't need to worry about it.
+
+   Of course, we DO worry about it, so we need a special translation. */
 void
 emacs_Xt_mapping_action (Widget w, XEvent* event)
 {
@@ -574,10 +583,13 @@
      take extra MappingKeyboard events out of the queue before requesting
      the current keymap from the server.
      */
-  if (event->xmapping.request == MappingKeyboard)
-    x_reset_key_mapping (d);
-  else if (event->xmapping.request == MappingModifier)
-    x_reset_modifier_mapping (d);
+  switch (event->xmapping.request)
+    {
+    case MappingKeyboard:  x_reset_key_mapping      (d); break;
+    case MappingModifier:  x_reset_modifier_mapping (d); break;
+    case MappingPointer:   /* Do something here? */      break;
+    default: abort();
+    }
 }
 
 
@@ -601,7 +613,7 @@
 {
   char *name;
   KeySym keysym = 0;
-  struct device *d = get_device_from_display (event->xany.display);
+  /* struct device *d = get_device_from_display (event->xany.display); */
   /* Apparently it's necessary to specify a dummy here (rather than
      passing in 0) to avoid crashes on German IRIX */
   char dummy[256];
@@ -693,55 +705,35 @@
 static void
 set_last_server_timestamp (struct device *d, XEvent *x_event)
 {
-  switch (x_event->xany.type)
+  Time t;
+  switch (x_event->type)
     {
     case KeyPress:
-    case KeyRelease:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xkey.time;
-      break;
-
+    case KeyRelease:       t = x_event->xkey.time;              break;
     case ButtonPress:
-    case ButtonRelease:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xbutton.time;
-      break;
-
-    case MotionNotify:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xmotion.time;
-      break;
-
+    case ButtonRelease:    t = x_event->xbutton.time;           break;
     case EnterNotify:
-    case LeaveNotify:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xcrossing.time;
-      break;
-      
-    case PropertyNotify:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xproperty.time;
-      break;
-
-    case SelectionClear:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xselectionclear.time;
-      break;
-
-    case SelectionRequest:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xselectionrequest.time;
-      break;
-
-    case SelectionNotify:
-      DEVICE_X_LAST_SERVER_TIMESTAMP (d) = x_event->xselection.time;
-      break;
+    case LeaveNotify:      t = x_event->xcrossing.time;         break;
+    case MotionNotify:     t = x_event->xmotion.time;           break;
+    case PropertyNotify:   t = x_event->xproperty.time;         break;
+    case SelectionClear:   t = x_event->xselectionclear.time;   break;
+    case SelectionRequest: t = x_event->xselectionrequest.time; break;
+    case SelectionNotify:  t = x_event->xselection.time;        break;
+    default: return;
     }
+  DEVICE_X_LAST_SERVER_TIMESTAMP (d) = t;
 }
 
 static int
 x_event_to_emacs_event (XEvent *x_event, struct Lisp_Event *emacs_event)
 {
-  Display *display = x_event->xany.display;
-  struct device *d = get_device_from_display (display);
+  Display *display    = x_event->xany.display;
+  struct device *d    = get_device_from_display (display);
   struct x_device *xd = DEVICE_X_DATA (d);
 
   set_last_server_timestamp (d, x_event);
 
-  switch (x_event->xany.type)
+  switch (x_event->type)
     {
     case KeyRelease:
       x_handle_sticky_modifiers (x_event, d);
@@ -751,283 +743,229 @@
     case ButtonPress:
     case ButtonRelease:
       {
-	unsigned int modifiers = 0;
-	int shift_p;
-	int lock_p;
-#ifdef EXTERNAL_WIDGET
-	struct frame *f = x_any_window_to_frame (d, x_event->xany.window);
-#endif
-	
-	/* If this is a synthetic KeyPress or Button event, and the user
-	   has expressed a disinterest in this security hole, then drop
-	   it on the floor.
-	   */
-	if (((x_event->xany.type == KeyPress)
-	     ? x_event->xkey.send_event
-	     : x_event->xbutton.send_event)
-#ifdef EXTERNAL_WIDGET
-	    /* ben: events get sent to an ExternalShell using XSendEvent.
-	       This is not a perfect solution. */
-	    && !FRAME_X_EXTERNAL_WINDOW_P (f)
-#endif
-	    && !x_allow_sendevents)
-	  return 0;
-	
-	x_handle_sticky_modifiers (x_event, d);
-
-	shift_p = x_event->xkey.state & ShiftMask;
-	lock_p  = x_event->xkey.state & LockMask;
-
-	if (x_event->xany.type == KeyPress)
-	  DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d) = x_event->xkey.time;
-	else
-	  DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d) = x_event->xbutton.time;
+        unsigned int modifiers = 0;
+        int shift_p;
+        int lock_p;
+        Bool key_event_p = (x_event->type == KeyPress);
+        unsigned int *state =
+          key_event_p ? &x_event->xkey.state : &x_event->xbutton.state;
 	
-	/* Ignore the caps-lock key w.r.t. mouse presses and releases. */
-	if (x_event->xany.type != KeyPress)
-	  lock_p = 0;
-	
-	if (x_event->xkey.state & ControlMask)    modifiers |= MOD_CONTROL;
-	if (x_event->xkey.state & xd->MetaMask)   modifiers |= MOD_META;
-	if (x_event->xkey.state & xd->SuperMask)  modifiers |= MOD_SUPER;
-	if (x_event->xkey.state & xd->HyperMask)  modifiers |= MOD_HYPER;
-	if (x_event->xkey.state & xd->AltMask)    modifiers |= MOD_ALT;
+        /* If this is a synthetic KeyPress or Button event, and the user
+           has expressed a disinterest in this security hole, then drop
+           it on the floor. */
+        if ((key_event_p
+             ? x_event->xkey.send_event
+             : x_event->xbutton.send_event)
+#ifdef EXTERNAL_WIDGET
+            /* ben: events get sent to an ExternalShell using XSendEvent.
+               This is not a perfect solution. */
+            && !FRAME_X_EXTERNAL_WINDOW_P (
+              x_any_window_to_frame (d, x_event->xany.window))
+#endif
+            && !x_allow_sendevents)
+          return 0;
+
+        DEVICE_X_MOUSE_TIMESTAMP (d) =
+          DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d) =
+          key_event_p ? x_event->xkey.time : x_event->xbutton.time;
+
+        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;
 
-	/* Ignore the caps-lock key if any other modifiers are down; this is
-	   so that Caps doesn't turn C-x into C-X, which would suck. */
-	if (modifiers)
-	  {
-	    x_event->xkey.state &= (~LockMask);
-	    lock_p = 0;
-	  }
-	
-	if (shift_p || lock_p)
-	  modifiers |= MOD_SHIFT;
-	
-	DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d);
+        /* Ignore the Caps_Lock key if:
+           - any other modifiers are down, so that Caps_Lock doesn't
+             turn C-x into C-X, which would suck.
+           - the event was a mouse event. */
+        if (modifiers || ! key_event_p)
+          *state &= (~LockMask);
+
+        shift_p = *state & ShiftMask;
+        lock_p  = *state & LockMask;
+
+        if (shift_p || lock_p)
+          modifiers |= MOD_SHIFT;
 
-	switch (x_event->xany.type)
-	  {
-	  case KeyPress:
-	    {
-	      Lisp_Object keysym;
-	      KeyCode keycode = x_event->xkey.keycode;
-	      
-	      if (x_key_is_modifier_p (keycode, d)) /* it's a modifier key */
-		return 0;
+        if (key_event_p)
+          {
+            Lisp_Object keysym;
+            XKeyEvent *ev = &x_event->xkey;
+            KeyCode keycode = ev->keycode;
+
 
-	      /* 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, 0);
+            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, 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.  Ignore it. */
-	      if (NILP (keysym))
-		return 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.  Ignore it. */
+            if (NILP (keysym))
+              return 0;
 	      
-	      /* More caps-lock garbage: caps-lock should *only* add
-		 the shift modifier to two-case keys (that is, A-Z and
-		 related characters).  So at this point (after looking
-		 up the keysym) if the keysym isn't a dual-case
-		 alphabetic, and if the caps lock key was down but the
-		 shift key wasn't, then turn off the shift modifier.
-		 Gag barf retch. */
-	      /* #### type lossage: assuming equivalence of emacs and
-		 X keysyms */
-	      /* !!#### maybe fix for Mule */
-	      if (! (CHAR_OR_CHAR_INTP (keysym)
-		     && keysym_obeys_caps_lock_p
-		     ((KeySym) XCHAR_OR_CHAR_INT (keysym), d))
-		  && lock_p
-		  && !shift_p)
-		modifiers &= (~MOD_SHIFT);
+            /* More Caps_Lock garbage: Caps_Lock should *only* add the
+               shift modifier to two-case keys (that is, A-Z and
+               related characters). So at this point (after looking up
+               the keysym) if the keysym isn't a dual-case alphabetic,
+               and if the caps lock key was down but the shift key
+               wasn't, then turn off the shift modifier.  Gag barf */
+            /* #### type lossage: assuming equivalence of emacs and
+               X keysyms */
+            /* !!#### maybe fix for Mule */
+            if (lock_p && !shift_p &&
+                ! (CHAR_OR_CHAR_INTP (keysym)
+                   && keysym_obeys_caps_lock_p
+                   ((KeySym) XCHAR_OR_CHAR_INT (keysym), d)))
+              modifiers &= (~MOD_SHIFT);
 	      
-	      /* If this key contains two distinct keysyms, that is,
-		 "shift" generates a different keysym than the
-		 non-shifted key, then don't apply the shift modifier
-		 bit: it's implicit.  Otherwise, if there would be no
-		 other way to tell the difference between the shifted
-		 and unshifted version of this key, apply the shift
-		 bit.  Non-graphics, like Backspace and F1 get the
-		 shift bit 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)
-		{
-		  KeySym top, bot;
-		  if (x_event->xkey.state & xd->ModeMask)
-		    bot = XLookupKeysym (&x_event->xkey, 2),
-		    top = XLookupKeysym (&x_event->xkey, 3);
-		  else
-		    bot = XLookupKeysym (&x_event->xkey, 0),
-		    top = XLookupKeysym (&x_event->xkey, 1);
-		  if (top && bot && top != bot)
-		    modifiers &= ~MOD_SHIFT;
-		}
-	      emacs_event->event_type	   = key_press_event;
-	      emacs_event->timestamp	   = x_event->xkey.time;
-	      emacs_event->event.key.modifiers = modifiers;
-	      emacs_event->event.key.keysym   = keysym;
-	      break;
-	    }
-	  case ButtonPress:
-	  case ButtonRelease:
-	    {
-	      struct frame *frame =
-		x_window_to_frame (d, x_event->xbutton.window);
-	      if (! frame)
-		return 0;	/* not for us */
-	      XSETFRAME (emacs_event->channel, frame);
-	    }
-	    
-	    if (x_event->type == ButtonPress)
-	      emacs_event->event_type    = button_press_event;
-	    else emacs_event->event_type = button_release_event;
-	    emacs_event->timestamp		    = x_event->xbutton.time;
-	    emacs_event->event.button.modifiers = modifiers;
-	    emacs_event->event.button.button    = x_event->xbutton.button;
-	    emacs_event->event.button.x         = x_event->xbutton.x;
-	    emacs_event->event.button.y         = x_event->xbutton.y;
-	    break;
-	  }
+            /* If this key contains two distinct keysyms, that is,
+               "shift" generates a different keysym than the
+               non-shifted key, then don't apply the shift modifier
+               bit: it's implicit.  Otherwise, if there would be no
+               other way to tell the difference between the shifted
+               and unshifted version of this key, apply the shift bit.
+               Non-graphics, like Backspace and F1 get the shift bit
+               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)
+              {
+                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;
+              }
+            emacs_event->event_type	     = key_press_event;
+            emacs_event->timestamp	     = ev->time;
+            emacs_event->event.key.modifiers = modifiers;
+            emacs_event->event.key.keysym    = keysym;
+          }
+        else                    /* Mouse press/release 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);
+            
+            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;
+          }
       }
-      break;
+    break;
       
     case MotionNotify:
       {
-	Window w = x_event->xmotion.window;
-	struct frame *frame = x_window_to_frame (d, w);
-	XEvent event2;
+        XMotionEvent *ev = &x_event->xmotion;
+        struct frame *frame = x_window_to_frame (d, ev->window);
+        unsigned int modifiers = 0;
+        XMotionEvent event2;
 	
-	if (! frame)
-	  return 0; /* not for us */
+        if (! frame)
+          return 0; /* not for us */
 	
-	/* We use MotionHintMask, so we will get only one motion event
-	   until the next time we call XQueryPointer or the user clicks
-	   the mouse.  So call XQueryPointer now (meaning that the event
-	   will be in sync with the server just before Fnext_event()
-	   returns).  If the mouse is still in motion, then the server
-	   will immediately generate exactly one more motion event, which
-	   will be on the queue waiting for us next time around.
-	   */
-	event2 = *x_event;
-	if (XQueryPointer (x_event->xmotion.display, event2.xmotion.window,
-			   &event2.xmotion.root, &event2.xmotion.subwindow,
-			   &event2.xmotion.x_root, &event2.xmotion.y_root,
-			   &event2.xmotion.x, &event2.xmotion.y,
-			   &event2.xmotion.state))
-	  *x_event = event2;
-	
-	DEVICE_X_MOUSE_TIMESTAMP (d) = x_event->xmotion.time;
+        /* We use MotionHintMask, so we will get only one motion event
+           until the next time we call XQueryPointer or the user
+           clicks the mouse.  So call XQueryPointer now (meaning that
+           the event will be in sync with the server just before
+           Fnext_event() returns).  If the mouse is still in motion,
+           then the server will immediately generate exactly one more
+           motion event, which will be on the queue waiting for us
+           next time around. */
+        event2 = *ev;
+        if (XQueryPointer (event2.display, event2.window,
+                           &event2.root,   &event2.subwindow,
+                           &event2.x_root, &event2.y_root,
+                           &event2.x,      &event2.y,
+                           &event2.state))
+          ev = &event2; /* only one structure copy */
 	
-	XSETFRAME (emacs_event->channel, frame);
-	emacs_event->event_type	  = pointer_motion_event;
-	emacs_event->timestamp	  = x_event->xmotion.time;
-	emacs_event->event.motion.x = x_event->xmotion.x;
-	emacs_event->event.motion.y = x_event->xmotion.y;
-	{
-	  unsigned int modifiers = 0;
-	  if (x_event->xmotion.state & ShiftMask)   modifiers |= MOD_SHIFT;
-	  if (x_event->xmotion.state & ControlMask) modifiers |= MOD_CONTROL;
-	  if (x_event->xmotion.state & xd->MetaMask)    modifiers |= MOD_META;
-	  if (x_event->xmotion.state & xd->SuperMask)   modifiers |= MOD_SUPER;
-	  if (x_event->xmotion.state & xd->HyperMask)   modifiers |= MOD_HYPER;
-	  if (x_event->xmotion.state & xd->AltMask)     modifiers |= MOD_ALT;
-	  /* Currently ignores Shift_Lock but probably shouldn't
-	     (but it definitely should ignore Caps_Lock). */
-	  emacs_event->event.motion.modifiers = modifiers;
-	}
+        DEVICE_X_MOUSE_TIMESTAMP (d) = ev->time;
+
+        XSETFRAME (emacs_event->channel, frame);
+        emacs_event->event_type	    = pointer_motion_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;
+        /* Currently ignores Shift_Lock but probably shouldn't
+           (but it definitely should ignore Caps_Lock). */
+        emacs_event->event.motion.modifiers = modifiers;
       }
-      break;
+    break;
       
     case ClientMessage:
-      /* Patch bogus TAKE_FOCUS messages from MWM; CurrentTime is passed as the
-	 timestamp of the TAKE_FOCUS, which the ICCCM explicitly prohibits. */
-      if (x_event->xclient.message_type == DEVICE_XATOM_WM_PROTOCOLS (d)
-	  && x_event->xclient.data.l[0] == DEVICE_XATOM_WM_TAKE_FOCUS (d)
-	  && x_event->xclient.data.l[1] == 0)
-	{
-	  x_event->xclient.data.l[1] = DEVICE_X_LAST_SERVER_TIMESTAMP (d);
-	}
-      /* fall through */
+      {
+        /* Patch bogus TAKE_FOCUS messages from MWM; CurrentTime is
+           passed as the timestamp of the TAKE_FOCUS, which the ICCCM
+           explicitly prohibits. */
+        XClientMessageEvent *ev = &x_event->xclient;
+        if (ev->message_type == DEVICE_XATOM_WM_PROTOCOLS (d)
+            && ev->data.l[0] == DEVICE_XATOM_WM_TAKE_FOCUS (d)
+            && ev->data.l[1] == 0)
+          {
+            ev->data.l[1] = DEVICE_X_LAST_SERVER_TIMESTAMP (d);
+          }
+      }
+    /* fall through */
       
     default: /* it's a magic event */
       {
-	struct frame *f;
-	  
-	switch (x_event->type)
-	  {
-	    /* Note: the number of cases could be reduced to two or
-	       three by using xany.window, but it's perhaps clearer
-	       and potentially more robust this way */
-	  case SelectionRequest:
-	    f = x_window_to_frame (d, x_event->xselectionrequest.owner);
-	    break;
-      
-	  case SelectionClear:
-	    f = x_window_to_frame (d, x_event->xselectionclear.window);
-	    break;
-      
-	  case SelectionNotify:
-	    f = x_window_to_frame (d, x_event->xselection.requestor);
-	    break;
-      
-	  case PropertyNotify:
-	    f = x_window_to_frame (d, x_event->xproperty.window);
-	    break;
-      
-	  case Expose:
-	  case GraphicsExpose:
-	    f = x_window_to_frame (d, x_event->xexpose.window);
-	    break;
-      
-	  case MapNotify:
-	  case UnmapNotify:
-	    f = x_any_window_to_frame (d, x_event->xmap.window);
-	    break;
-      
-	  case EnterNotify:
-	  case LeaveNotify:
-	    f = x_any_window_to_frame (d, x_event->xcrossing.window);
-	    break;
+        struct frame *frame;
+        Window w;
+    
+        switch (x_event->type)
+          {
+            /* Note: the number of cases could be reduced to two or
+               three by using xany.window, but it's perhaps clearer
+               and potentially more robust this way */
+          case SelectionRequest: w = x_event->xselectionrequest.owner; break;
+          case SelectionClear:   w = x_event->xselectionclear.window;  break;
+          case SelectionNotify:  w = x_event->xselection.requestor;    break;
+          case PropertyNotify:   w = x_event->xproperty.window;        break;
+          case ClientMessage:    w = x_event->xclient.window;          break;
+          case ConfigureNotify:  w = x_event->xconfigure.window;       break;
+          case Expose:
+          case GraphicsExpose:   w = x_event->xexpose.window;          break;
+          case MapNotify:
+          case UnmapNotify:      w = x_event->xmap.window;             break;
+          case EnterNotify:
+          case LeaveNotify:      w = x_event->xcrossing.window;        break;
+          case FocusIn:
+          case FocusOut:         w = x_event->xfocus.window;           break;
+          case VisibilityNotify: w = x_event->xvisibility.window;      break;
+          default:               w = x_event->xany.window;             break;
+          }
+        frame = x_any_window_to_frame (d, w);
+       
+        if (!frame)
+          return 0;
 
-	  case FocusIn:
-	  case FocusOut:
-	    /* It's curious that we're using x_any_window_to_frame()
-	       here.  I don't know if this causes problems. */
-	    f = x_any_window_to_frame (d, x_event->xfocus.window);
-      
-	  case ClientMessage:
-	    f = x_any_window_to_frame (d, x_event->xclient.window);
-	    break;
-      
-	  case MappingNotify:
-	  case VisibilityNotify:
-	    f = x_any_window_to_frame (d, x_event->xvisibility.window);
-	    break;
-      
-	  case ConfigureNotify:
-	    f = x_any_window_to_frame (d, x_event->xconfigure.window);
-	    break;
-
-	  default:
-	    f = x_any_window_to_frame (d, x_event->xany.window);
-	    break;
-	  }
-
-	if (!f)
-	  return 0;
-
-	emacs_event->event_type = magic_event;
-	XSETFRAME (emacs_event->channel, f);
-	memcpy ((char *) &emacs_event->event.magic.underlying_x_event,
-		(char *) x_event,
-		sizeof (XEvent));
-	break;
+        emacs_event->event_type = magic_event;
+        XSETFRAME (emacs_event->channel, frame);
+        emacs_event->event.magic.underlying_x_event = *x_event;
+        break;
       }
     }
   return 1;
@@ -1086,7 +1024,7 @@
     /* focus events are sometimes generated just before
        a frame is destroyed. */
     return;
-  handle_focus_event_1 (f, event->xany.type == FocusIn);
+  handle_focus_event_1 (f, event->type == FocusIn);
 }
 
 static void
@@ -1095,7 +1033,7 @@
   Lisp_Object frame = Qnil;
 
   XSETFRAME (frame, f);
-  if (event->xany.type == MapNotify)
+  if (event->type == MapNotify)
     {
       XWindowAttributes xwa;
 
@@ -1310,19 +1248,13 @@
       if (FRAME_X_EXTERNAL_WINDOW_P (f))
 	break;
 #endif
-      handle_focus_event_1 (f, event->xany.type == FocusIn);
+      handle_focus_event_1 (f, event->type == FocusIn);
       break;
       
     case ClientMessage:
       handle_client_message (f, event);
       break;
       
-#if 0
-      /* this is where we ought to be handling this event, but
-	 we don't see it here. --ben */
-    case MappingNotify:	/* The user has run xmodmap */
-#endif    
-      
     case VisibilityNotify: /* window visiblity has changed */
       if (event->xvisibility.state == VisibilityUnobscured)
 	FRAME_X_TOTALLY_VISIBLE_P (f) = 1;
@@ -1331,10 +1263,26 @@
       break;
       
     case ConfigureNotify:
-      if (event->xconfigure.window != XtWindow (FRAME_X_SHELL_WIDGET (f)))
-	break;
-      FRAME_X_SHELL_WIDGET (f)->core.x = event->xconfigure.x;
-      FRAME_X_SHELL_WIDGET (f)->core.y = event->xconfigure.y;
+#ifdef HAVE_XIM
+      XIC_SetGeometry (f);
+#endif
+      /* ### 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
+         occurrence.  */
+      /* ### Well, actually we shouldn't have to ever call
+         x_smash_bastardly_shell_position.  We should just call
+         XtTranslateCoordinates and only access the core.{x,y} fields
+         using XtGetValue -- mrb */
+      {
+        XConfigureEvent *ev = &event->xconfigure;
+      if (ev->window == XtWindow (FRAME_X_SHELL_WIDGET (f)) &&
+          ! (ev->x == 0 && ev->y == 0 && !ev->send_event))
+        {
+          FRAME_X_SHELL_WIDGET (f)->core.x = ev->x;
+          FRAME_X_SHELL_WIDGET (f)->core.y = ev->y;
+        }
+      }
       break;
 
     default:
@@ -1759,12 +1707,11 @@
 {
   switch (mode)
   {
-  case NotifyNormal: return "Normal";
-  case NotifyGrab: return "Grab";
-  case NotifyUngrab: return "Ungrab";
+  case NotifyNormal:	   return "Normal";
+  case NotifyGrab:	   return "Grab";
+  case NotifyUngrab:	   return "Ungrab";
   case NotifyWhileGrabbed: return "WhileGrabbed";
-  default:
-    return "???";
+  default:		   return "???";
   }
 }
 
@@ -1773,15 +1720,14 @@
 {
   switch (detail)
   {
-  case NotifyAncestor: return "Ancestor";
-  case NotifyInferior: return "Inferior";
-  case NotifyNonlinear: return "Nonlinear";
-  case NotifyNonlinearVirtual: return "NonlinearVirtual";
-  case NotifyPointer: return "Pointer";
-  case NotifyPointerRoot: return "PointerRoot";
-  case NotifyDetailNone: return "DetailNone";
-  default:
-    return "???";
+  case NotifyAncestor:		return "Ancestor";
+  case NotifyInferior:		return "Inferior";
+  case NotifyNonlinear:		return "Nonlinear";
+  case NotifyNonlinearVirtual:	return "NonlinearVirtual";
+  case NotifyPointer:		return "Pointer";
+  case NotifyPointerRoot:	return "PointerRoot";
+  case NotifyDetailNone:	return "DetailNone";
+  default:			return "???";
   }
 }
 
@@ -1790,11 +1736,10 @@
 {
   switch (state)
   {
-  case VisibilityFullyObscured: return "FullyObscured";
+  case VisibilityFullyObscured:	    return "FullyObscured";
   case VisibilityPartiallyObscured: return "PartiallyObscured";
-  case VisibilityUnobscured: return "Unobscured";
-  default:
-    return "???";
+  case VisibilityUnobscured:        return "Unobscured";
+  default:			    return "???";
   }
 }
 
@@ -1854,11 +1799,11 @@
 	keysym = x_to_emacs_keysym (event, 0);
 	if (CHAR_OR_CHAR_INTP (keysym))
 	  {
-	    if (XCHAR_OR_CHAR_INT (keysym) > 32
-		&& XCHAR_OR_CHAR_INT (keysym) < 127)
-	      stderr_out ("   keysym: %c\n", XCHAR_OR_CHAR_INT (keysym));
+            Emchar c = XCHAR_OR_CHAR_INT (keysym);
+	    if (c > 32 && c < 127)
+	      stderr_out ("   keysym: %c\n", c);
 	    else
-	      stderr_out ("   keysym: %d\n", XCHAR_OR_CHAR_INT (keysym));
+	      stderr_out ("   keysym: %d\n", c);
 	  }
 	else
 	  stderr_out ("   keysym: %s\n", string_data (XSYMBOL (keysym)->name));
@@ -1870,8 +1815,8 @@
 	{
 	  XExposeEvent *ev = &event->xexpose;
 	  describe_event_window (ev->window, ev->display);
-	  stderr_out ("   region: %d %d %d %d\n", ev->x, ev->y,
-		      ev->width, ev->height);
+	  stderr_out ("   region: x=%d y=%d width=%d height=%d\n",
+                      ev->x, ev->y, ev->width, ev->height);
 	  stderr_out ("    count: %d\n", ev->count);
 	}
       else
@@ -1886,8 +1831,8 @@
 	  stderr_out ("    major: %s\n",
 		      (ev ->major_code == X_CopyArea  ? "CopyArea" :
 		       (ev->major_code == X_CopyPlane ? "CopyPlane" : "?")));
-	  stderr_out ("   region: %d %d %d %d\n", ev->x, ev->y,
-		      ev->width, ev->height);
+	  stderr_out ("   region: x=%d y=%d width=%d height=%d\n",
+                      ev->x, ev->y, ev->width, ev->height);
 	  stderr_out ("    count: %d\n", ev->count);
 	}
       else
@@ -2016,9 +1961,9 @@
  we_didnt_get_an_event:
 
   while (NILP (dispatch_event_queue) &&
-	 !completed_timeouts &&
-	 !fake_event_occurred &&
-	 !process_events_occurred &&
+	 !completed_timeouts         &&
+	 !fake_event_occurred        &&
+	 !process_events_occurred    &&
 	 !tty_events_occurred)
     {