diff src/event-Xt.c @ 183:e121b013d1f0 r20-3b18

Import from CVS: tag r20-3b18
author cvs
date Mon, 13 Aug 2007 09:54:23 +0200
parents 9ad43877534d
children 3d6bfa290dbd
line wrap: on
line diff
--- a/src/event-Xt.c	Mon Aug 13 09:53:23 2007 +0200
+++ b/src/event-Xt.c	Mon Aug 13 09:54:23 2007 +0200
@@ -171,15 +171,16 @@
 {
   Display *display = DEVICE_X_DISPLAY (d);
   struct x_device *xd = DEVICE_X_DATA (d);
-  int max_code;
   if (xd->x_keysym_map)
     XFree ((char *) xd->x_keysym_map);
-  XDisplayKeycodes (display, &xd->x_keysym_map_min_code,
-		    &max_code);
-  xd->x_keysym_map =
-    XGetKeyboardMapping (display, xd->x_keysym_map_min_code,
-			 max_code - xd->x_keysym_map_min_code + 1,
-			 &xd->x_keysym_map_keysyms_per_code);
+  XDisplayKeycodes (display,
+		    &xd->x_keysym_map_min_code,
+		    &xd->x_keysym_map_max_code);
+  xd->x_keysym_map = XGetKeyboardMapping (display,
+					  xd->x_keysym_map_min_code,
+					  xd->x_keysym_map_max_code -
+					  xd->x_keysym_map_min_code + 1,
+					  &xd->x_keysym_map_keysyms_per_code);
 }
 
 static CONST char *
@@ -188,7 +189,7 @@
   switch (indice)
     {
     case ShiftMapIndex:   return "ModShift";
-    case LockMapIndex:    return "ModLock";   
+    case LockMapIndex:    return "ModLock";
     case ControlMapIndex: return "ModControl";
     case Mod1MapIndex:    return "Mod1";
     case Mod2MapIndex:    return "Mod2";
@@ -401,9 +402,15 @@
 x_key_is_modifier_p (KeyCode keycode, struct device *d)
 {
   struct x_device *xd = DEVICE_X_DATA (d);
-  KeySym *syms = &xd->x_keysym_map [(keycode - xd->x_keysym_map_min_code) *
-				    xd->x_keysym_map_keysyms_per_code];
+  KeySym *syms;
   int i;
+
+  if (keycode < xd->x_keysym_map_min_code ||
+      keycode > xd->x_keysym_map_max_code)
+    return 0;
+
+  syms = &xd->x_keysym_map [(keycode - xd->x_keysym_map_min_code) *
+			   xd->x_keysym_map_keysyms_per_code];
   for (i = 0; i < xd->x_keysym_map_keysyms_per_code; i++)
     if (IsModifierKey (syms [i]) ||
 	syms [i] == XK_Mode_switch) /* why doesn't IsModifierKey count this? */
@@ -443,12 +450,16 @@
   xd = DEVICE_X_DATA (d);
   keycode = ev->xkey.keycode;
   type = ev->type;
-  
+
+  if (keycode < xd->x_keysym_map_min_code ||
+      keycode > xd->x_keysym_map_max_code)
+    return;
+
   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 ||
@@ -566,7 +577,7 @@
      But if shift-lock is down, then it does. */
   if (xd->lock_interpretation == XK_Shift_Lock)
     return 1;
-  
+
   return
     ((sym >= XK_A)        && (sym <= XK_Z))          ||
     ((sym >= XK_a)        && (sym <= XK_z))          ||
@@ -580,7 +591,7 @@
    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.
 
@@ -646,7 +657,7 @@
       /* If it's got a one-character name, that's good enough. */
       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.
@@ -725,7 +736,7 @@
       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)
@@ -765,7 +776,7 @@
         instream =
 	  make_decoding_input_stream (XLSTREAM (instream),
 				      Fget_coding_system (Qautomatic_conversion));
-        
+
         while ((ch = Lstream_get_emchar (XLSTREAM (instream))) != EOF)
           {
             Lisp_Object emacs_event = Fmake_event ();
@@ -855,7 +866,7 @@
 	  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;
@@ -888,11 +899,11 @@
 	       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.  Ignore it. */
+	       or a "dead" key prefix, or XIM input.  Ignore it. */
 	    if (NILP (keysym))
 	      return 0;
 
@@ -941,10 +952,10 @@
 	    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;
@@ -953,17 +964,17 @@
 	  }
       }
     break;
-      
+
     case MotionNotify:
       {
         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 */
-	
+
         /* 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
@@ -979,7 +990,7 @@
                            &event2.x,      &event2.y,
                            &event2.state))
           ev = &event2; /* only one structure copy */
-	
+
         DEVICE_X_MOUSE_TIMESTAMP (d) = ev->time;
 
         XSETFRAME (emacs_event->channel, frame);
@@ -998,7 +1009,7 @@
         emacs_event->event.motion.modifiers = modifiers;
       }
     break;
-      
+
     case ClientMessage:
       {
         /* Patch bogus TAKE_FOCUS messages from MWM; CurrentTime is
@@ -1013,42 +1024,49 @@
           }
       }
     /* fall through */
-      
+
     default: /* it's a magic event */
       {
         struct frame *frame;
         Window w;
-    
+	size_t event_size;
+	XEvent *x_event_copy = &emacs_event->event.magic.underlying_x_event;
+
+#define FROB(event_member, window_member) \
+	x_event_copy->event_member = x_event->event_member; \
+	w = x_event->event_member.window_member
+
         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;
+	  case SelectionRequest: FROB(xselectionrequest, owner);  break;
+	  case SelectionClear:	 FROB(xselectionclear, window);	  break;
+	  case SelectionNotify:	 FROB(xselection, requestor);	  break;
+	  case PropertyNotify:	 FROB(xproperty, window);	  break;
+	  case ClientMessage:	 FROB(xclient, window);		  break;
+	  case ConfigureNotify:	 FROB(xconfigure, window);	  break;
+	  case Expose:
+	  case GraphicsExpose:	 FROB(xexpose, window);		  break;
+	  case MapNotify:
+	  case UnmapNotify:	 FROB(xmap, window);		  break;
+	  case EnterNotify:
+	  case LeaveNotify:	 FROB(xcrossing, window);	  break;
+	  case FocusIn:
+	  case FocusOut:	 FROB(xfocus, window);		  break;
+	  case VisibilityNotify: FROB(xvisibility, window);	  break;
+          default:
+	    w = x_event->xany.window;
+	    *x_event_copy = *x_event;
+	    break;
           }
+#undef FROB
         frame = x_any_window_to_frame (d, w);
-       
+
         if (!frame)
           return 0;
 
         emacs_event->event_type = magic_event;
         XSETFRAME (emacs_event->channel, frame);
-        emacs_event->event.magic.underlying_x_event = *x_event;
+
         break;
       }
     }
@@ -1084,7 +1102,7 @@
     Lisp_Object frm;
     Lisp_Object conser;
     struct gcpro gcpro1;
-    
+
     XSETFRAME (frm, f);
     conser = Fcons (frm, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
     GCPRO1 (conser);
@@ -1105,7 +1123,7 @@
    * 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);
@@ -1138,7 +1156,7 @@
       dispatch_epoch_event (f, event, Qx_map);
 #endif
     }
-  else if (FRAME_VISIBLE_P (f) && !is_visible) 
+  else if (FRAME_VISIBLE_P (f) && !is_visible)
     {
       FRAME_VISIBLE_P (f) = 0;
       va_run_hook_with_args (Qunmap_frame_hook, 1, frame);
@@ -1257,7 +1275,7 @@
       handle_focus_event_1 (f, 1);
 #if 0
       /* If there is a dialog box up, focus on it.
-	 
+
 	 #### Actually, we're raising it too, which is wrong.  We should
 	 #### just focus on it, but lwlib doesn't currently give us an
 	 #### easy way to do that.  This should be fixed.
@@ -1284,7 +1302,7 @@
 emacs_Xt_handle_magic_event (struct Lisp_Event *emacs_event)
 {
   /* This function can GC */
-  XEvent *event = (XEvent *) &emacs_event->event.magic.underlying_x_event;
+  XEvent *event = &emacs_event->event.magic.underlying_x_event;
   struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
 
   if (!FRAME_LIVE_P (f))
@@ -1295,60 +1313,60 @@
     case SelectionRequest:
       x_handle_selection_request (&event->xselectionrequest);
       break;
-      
+
     case SelectionClear:
       x_handle_selection_clear (&event->xselectionclear);
       break;
-      
+
     case SelectionNotify:
       x_handle_selection_notify (&event->xselection);
       break;
-      
+
     case PropertyNotify:
       x_handle_property_notify (&event->xproperty);
 #ifdef EPOCH
       dispatch_epoch_event (f, event, Qx_property_change);
 #endif
       break;
-      
+
     case Expose:
       x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y,
 			     event->xexpose.width, event->xexpose.height);
       break;
-      
+
     case GraphicsExpose: /* This occurs when an XCopyArea's source area was
 			    obscured or not available. */
       x_redraw_exposed_area (f, event->xexpose.x, event->xexpose.y,
 			     event->xexpose.width, event->xexpose.height);
       break;
-      
+
     case MapNotify:
     case UnmapNotify:
       handle_map_event (f, event);
       break;
-      
+
     case EnterNotify:
       if (event->xcrossing.detail != NotifyInferior)
 	{
 	  Lisp_Object frame;
-	  
+
 	  XSETFRAME (frame, f);
 	  /* FRAME_X_MOUSE_P (f) = 1; */
 	  va_run_hook_with_args (Qmouse_enter_frame_hook, 1, frame);
 	}
       break;
-      
+
     case LeaveNotify:
       if (event->xcrossing.detail != NotifyInferior)
 	{
 	  Lisp_Object frame;
-	  
+
 	  XSETFRAME (frame, f);
 	  /* FRAME_X_MOUSE_P (f) = 0; */
 	  va_run_hook_with_args (Qmouse_leave_frame_hook, 1, frame);
 	}
       break;
-      
+
     case FocusIn:
     case FocusOut:
 #ifdef EXTERNAL_WIDGET
@@ -1361,11 +1379,11 @@
 #endif
       handle_focus_event_1 (f, event->type == FocusIn);
       break;
-      
+
     case ClientMessage:
       handle_client_message (f, event);
       break;
-      
+
     case VisibilityNotify: /* window visiblity has changed */
       if (event->xvisibility.window == XtWindow (FRAME_X_SHELL_WIDGET (f)))
 	{
@@ -1373,9 +1391,9 @@
 	    (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(). 
+	  /* 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 */
@@ -1383,7 +1401,7 @@
 				       != VisibilityFullyObscured) ? 1 : -1);
 	}
       break;
-      
+
     case ConfigureNotify:
 #ifdef HAVE_XIM
       XIM_SetGeometry (f);
@@ -1570,10 +1588,10 @@
 	 for that process's fd, so returning without setting any
 	 flags will take care of it.)  To see the problem, uncomment
 	 the stderr_out below, turn NORMAL_QUIT_CHECK_TIMEOUT_MSECS
-	 down to 25, do sh -c 'xemacs -nw -q -f shell 2>/tmp/log' 
+	 down to 25, do sh -c 'xemacs -nw -q -f shell 2>/tmp/log'
 	 and press return repeatedly.  (Seen under AIX & Linux.)
 	 -dkindred@cs.cmu.edu */
-      if (!poll_fds_for_input (temp_mask)) 
+      if (!poll_fds_for_input (temp_mask))
 	{
 #if 0
 	  stderr_out ("mark_what_as_being_ready: no input available (fd=%d)\n",
@@ -1619,7 +1637,7 @@
   closure = (struct what_is_ready_closure *) xmalloc (sizeof (*closure));
   closure->fd = fd;
   closure->what = what;
-  closure->id = 
+  closure->id =
     XtAppAddInput (Xt_app_con, fd,
 		   (XtPointer) (XtInputReadMask /* | XtInputExceptMask */),
 		   Xt_what_callback, closure);
@@ -1676,10 +1694,8 @@
 static void
 emacs_Xt_select_process (struct Lisp_Process *p)
 {
-  int infd;
   Lisp_Object process;
-
-  infd = event_stream_unixoid_select_process (p);
+  int infd = event_stream_unixoid_select_process (p);
 
   XSETPROCESS (process, p);
   select_filedesc (infd, process);
@@ -1688,9 +1704,7 @@
 static void
 emacs_Xt_unselect_process (struct Lisp_Process *p)
 {
-  int infd;
-
-  infd = event_stream_unixoid_unselect_process (p);
+  int infd = event_stream_unixoid_unselect_process (p);
 
   unselect_filedesc (infd);
 }
@@ -1758,7 +1772,14 @@
   /* On a stream device (ie: noninteractive), bad things can happen. */
   if (EQ (CONSOLE_TYPE (con), Qtty)) {
     mousefd = CONSOLE_TTY_MOUSE_FD (con);
-    if (mousefd >= 0) {
+	/* We check filedesc_to_what_closure[fd] here because if you run
+	** XEmacs from a TTY, it will fire up GPM, select the mouse fd, then
+	** if you run gnuattach to connect to another TTY, it will fire up
+	** GPM again, and try to reselect the mouse fd.  GPM uses the same
+	** fd for every connection apparently, and select_filedesc will
+	** fail its assertion if we try to select it twice.
+	*/
+    if ((mousefd >= 0) && !filedesc_to_what_closure[mousefd]) {
       select_filedesc (mousefd, console);
     }
   }
@@ -1911,12 +1932,12 @@
 	stderr_out ("     detail: %s\n", XEvent_detail_to_string(ev->detail));
 	break;
       }
-      
+
     case KeyPress:
       {
 	XKeyEvent *ev = &event->xkey;
 	unsigned int state = ev->state;
-	
+
 	describe_event_window (ev->window, ev->display);
 	stderr_out ("   subwindow: %ld\n", ev->subwindow);
 	stderr_out ("   state: ");
@@ -1929,7 +1950,7 @@
 	if (state & Mod3Mask)    stderr_out ("Mod3 ");
 	if (state & Mod4Mask)    stderr_out ("Mod4 ");
 	if (state & Mod5Mask)    stderr_out ("Mod5 ");
-	
+
 	if (! state)
 	  stderr_out ("vanilla\n");
 	else
@@ -1939,7 +1960,7 @@
 	stderr_out ("   keycode: 0x%x\n", ev->keycode);
       }
     break;
-    
+
     case Expose:
       if (x_debug_events > 1)
 	{
@@ -1952,7 +1973,7 @@
       else
 	stderr_out ("\n");
       break;
-      
+
     case GraphicsExpose:
       if (x_debug_events > 1)
 	{
@@ -1968,7 +1989,7 @@
       else
 	stderr_out ("\n");
       break;
-    
+
     case EnterNotify:
     case LeaveNotify:
       if (x_debug_events > 1)
@@ -2015,7 +2036,7 @@
       else
 	stderr_out ("\n");
       break;
-    
+
     case ClientMessage:
       {
 	XClientMessageEvent *ev = &event->xclient;
@@ -2030,7 +2051,7 @@
 	stderr_out ("\n");
 	break;
       }
-	
+
     default:
       stderr_out ("\n");
       break;
@@ -2073,9 +2094,7 @@
 signal_special_Xt_user_event (Lisp_Object channel, Lisp_Object function,
 			      Lisp_Object object)
 {
-  Lisp_Object event;
-
-  event = Fmake_event ();
+  Lisp_Object event = Fmake_event ();
 
   XEVENT (event)->event_type = misc_user_event;
   XEVENT (event)->channel = channel;
@@ -2083,7 +2102,7 @@
   XEVENT (event)->event.eval.object = object;
 
   enqueue_Xt_dispatch_event (event);
-}  
+}
 
 static void
 emacs_Xt_next_event (struct Lisp_Event *emacs_event)
@@ -2149,8 +2168,7 @@
     Xt_timeout_to_emacs_event (emacs_event);
   else if (fake_event_occurred)
     {
-      /* A dummy event, so that a cycle of the command loop will
-	 occur. */
+      /* A dummy event, so that a cycle of the command loop will occur. */
       fake_event_occurred = 0;
       /* eval events have nil as channel */
       emacs_event->event_type = eval_event;
@@ -2407,7 +2425,7 @@
 	 signal_event_pipe to generate actual input in the form
 	 of an identity eval event or something. (#### maybe this
 	 actually happens?) */
-	 
+
       if (poll_fds_for_input (process_only_mask))
 	return 1;
 
@@ -2513,7 +2531,7 @@
   String       params[1];
   Cardinal     num_params  = 1;
   XtAppContext the_app_con = XtDisplayToApplicationContext (dpy);
-  
+
   if (*num_args != 2) {
     XtAppWarningMsg(the_app_con, "wrongParameters", "cvtStringToPixel",
                     "XtToolkitError",
@@ -2549,11 +2567,11 @@
     status = allocate_nearest_color (DisplayOfScreen(screen), colormap,
                                      &screenColor);
   }
-  
+
   if (status == 0) {
     params[0] = str;
     /* Server returns a specific error code but Xlib discards it.  Ugh */
-    if (XLookupColor(DisplayOfScreen(screen), colormap, (char*)str,
+    if (XLookupColor(DisplayOfScreen(screen), colormap, (char*) str,
                      &exactColor, &screenColor)) {
       XtAppWarningMsg(the_app_con, "noColormap", "cvtStringToPixel",
                       "XtToolkitError",
@@ -2565,7 +2583,7 @@
                       "XtToolkitError",
                       "Color name \"%s\" is not defined", params, &num_params);
     }
-    
+
     *closure_ret = False;
     return False;
   } else {
@@ -2670,15 +2688,15 @@
   completed_timeouts = 0;
 
   event_stream = Xt_event_stream;
-  
+
 #if defined(HAVE_XIM) || defined(USE_XFONTSET)
   Initialize_Locale();
 #endif /* HAVE_XIM || USE_XFONTSET */
-  
+
   XtToolkitInitialize ();
   Xt_app_con = XtCreateApplicationContext ();
   XtAppSetFallbackResources (Xt_app_con, (String *) x_fallback_resources);
-  
+
   /* In xselect.c */
   x_selection_timeout = (XtAppGetSelectionTimeout (Xt_app_con) / 1000);
   XSetErrorHandler (x_error_handler);
@@ -2701,5 +2719,5 @@
 			 NULL, 0,
 			 XtCacheByDisplay, EmacsFreeXIMStyles);
 #endif /* XIM_XLIB */
-  
+
 }