]> code.delx.au - gnu-emacs/blobdiff - src/xterm.c
(SYSTEM_TYPE): Use berkeley-unix.
[gnu-emacs] / src / xterm.c
index 25c63512e138d30bf5572f0beef052fe083757a5..c17bf1fc91eddc161cff3515b3c0eba03e29d5f1 100644 (file)
@@ -31,7 +31,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "lisp.h"
 
-/* On 4.3 this loses if it comes after xterm.h.  */
+/* On 4.3 these lose if they come after xterm.h.  */
+#include <stdio.h>
 #include <signal.h>
 
 /* This may include sys/types.h, and that somehow loses
@@ -70,7 +71,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "systime.h"
 
 #include <fcntl.h>
-#include <stdio.h>
 #include <ctype.h>
 #include <errno.h>
 #include <setjmp.h>
@@ -1428,16 +1428,107 @@ pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds)
 /* Any buttons grabbed. */
 unsigned int x_mouse_grabbed;
 
+/* Which modifier keys are on which modifier bits?
+
+   With each keystroke, X returns eight bits indicating which modifier
+   keys were held down when the key was pressed.  The interpretation
+   of the top five modifier bits depends on what keys are attached
+   to them.  If the Meta_L and Meta_R keysyms are on mod5, then mod5
+   is the meta bit.
+   
+   x_meta_mod_mask is a mask containing the bits used for the meta key.
+   It may have more than one bit set, if more than one modifier bit
+   has meta keys on it.  Basically, if EVENT is a KeyPress event,
+   the meta key is pressed if (EVENT.state & x_meta_mod_mask) != 0.  
+
+   x_shift_lock_mask is LockMask if the XK_Shift_Lock keysym is on the
+   lock modifier bit, or zero otherwise.  Non-alphabetic keys should
+   only be affected by the lock modifier bit if XK_Shift_Lock is in
+   use; XK_Caps_Lock should only affect alphabetic keys.  With this
+   arrangement, the lock modifier should shift the character if
+   (EVENT.state & x_shift_lock_mask) != 0.  */
+static int x_meta_mod_mask, x_shift_lock_mask;
+
+/* Initialize mode_switch_bit and modifier_meaning.  */
+static void
+x_find_modifier_meanings ()
+{
+  int min_code, max_code;
+  KeySym *syms;
+  int syms_per_code;
+  XModifierKeymap *mods;
+  int alt_mod_mask = 0;
+
+  x_meta_mod_mask = 0;
+  x_shift_lock_mask = 0;
+  
+  XDisplayKeycodes (x_current_display, &min_code, &max_code);
+  syms = XGetKeyboardMapping (x_current_display,
+                             min_code, max_code - min_code + 1,
+                             &syms_per_code);
+  mods = XGetModifierMapping (x_current_display);
+
+  /* Scan the modifier table to see which modifier bits the Meta and 
+     Alt keysyms are on.  */
+  {
+    int row, col;      /* The row and column in the modifier table. */
+
+    for (row = 3; row < 8; row++)
+      for (col = 0; col < mods->max_keypermod; col++)
+       {
+         KeyCode code =
+           mods->modifiermap[(row * mods->max_keypermod) + col];
+
+         /* Are any of this keycode's keysyms a meta key?  */
+         {
+           int code_col;
+
+           for (code_col = 0; code_col < syms_per_code; code_col++)
+             {
+               int sym = syms[((code - min_code) * syms_per_code) + code_col];
+
+               switch (sym)
+                 {
+                 case XK_Meta_L:
+                 case XK_Meta_R:
+                   x_meta_mod_mask |= (1 << row);
+                   break;
+
+                 case XK_Alt_L:
+                 case XK_Alt_R:
+                   alt_mod_mask |= (1 << row);
+                   break;
+
+                 case XK_Shift_Lock:
+                   /* Ignore this if it's not on the lock modifier.  */
+                   if ((1 << row) == LockMask)
+                     x_shift_lock_mask = LockMask;
+                   break;
+                 }
+             }
+         }
+       }
+  }
+
+  /* If we couldn't find any meta keys, accept any alt keys as meta keys.  */
+  if (! x_meta_mod_mask)
+    x_meta_mod_mask = alt_mod_mask;
+
+  XFree ((char *) syms);
+  XFreeModifiermap (mods);
+}
+
+
 /* Convert a set of X modifier bits to the proper form for a
    struct input_event modifiers value.  */
 
-static Lisp_Object
+static unsigned int
 x_convert_modifiers (state)
      unsigned int state;
 {
-  return (  ((state & (ShiftMask | LockMask)) ? shift_modifier : 0)
-         | ((state & ControlMask)            ? ctrl_modifier  : 0)
-         | ((state & Mod1Mask)               ? meta_modifier  : 0));
+  return (  ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0)
+         | ((state & ControlMask)                     ? ctrl_modifier  : 0)
+         | ((state & x_meta_mod_mask)                 ? meta_modifier  : 0));
 }
 
 extern struct frame *x_window_to_scrollbar ();
@@ -1466,7 +1557,9 @@ construct_mouse_click (result, event, f, part, prefix)
   XSET (result->code, Lisp_Int, event->button);
   result->timestamp = event->time;
   result->modifiers = (x_convert_modifiers (event->state)
-                      | (event->type == ButtonRelease ? up_modifier : 0));
+                      | (event->type == ButtonRelease
+                         ? up_modifier 
+                         : down_modifier));
 
   /* Notice if the mouse is still grabbed.  */
   if (event->type == ButtonPress)
@@ -1482,16 +1575,16 @@ construct_mouse_click (result, event, f, part, prefix)
        Vmouse_depressed = Qnil;
     }
 
-  if (part)                    /* Scrollbar event */
+  if (! NILP (part))           /* Scrollbar event */
     {
       int pos, len;
 
       pos = event->y - (f->display.x->v_scrollbar_width - 2);
-      XSET (x_mouse_x, Lisp_Int, pos);
+      x_mouse_x = pos;
       len = ((FONT_HEIGHT (f->display.x->font) * f->height)
             + f->display.x->internal_border_width
             - (2 * (f->display.x->v_scrollbar_width - 2)));
-      XSET (x_mouse_y, Lisp_Int, len);
+      x_mouse_y = len;
 
       result->kind = scrollbar_click;
       result->part = part;
@@ -1505,8 +1598,8 @@ construct_mouse_click (result, event, f, part, prefix)
 
       pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL);
       result->kind = mouse_click;
-      result->x = column;
-      result->y = row;
+      XFASTINT (result->x) = column;
+      XFASTINT (result->y) = row;
       result->frame = f;
     }
 }
@@ -1663,6 +1756,15 @@ XTmouse_position (f, x, y, time)
    sometimes don't work.  */
 static Time enter_timestamp;
 
+/* This holds the state XLookupString needs to implement dead keys
+   and other tricks known as "compose processing".  _X Window System_ 
+   says that a portable program can't use this, but Stephen Gildea assures
+   me that letting the compiler initialize it to zeros will work okay.
+
+   This must be defined outside of XTread_socket, for the same reasons
+   given for enter_timestamp, above.  */
+static XComposeStatus compose_status;
+
 /* Communication with window managers. */
 Atom Xatom_wm_protocols;
 
@@ -1687,7 +1789,7 @@ Atom Xatom_wm_window_moved;         /* When the WM moves us. */
    WAITP is nonzero if we should block until input arrives.
    EXPECTED is nonzero if the caller knows input is available.  */
 
-Lisp_Object
+int
 XTread_socket (sd, bufp, numchars, waitp, expected)
      register int sd;
      register struct input_event *bufp;
@@ -1802,9 +1904,20 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          break;
 
        case PropertyNotify:
-         /* If we were to do this synchronously, there'd be no worry
-            about re-selecting. */
-         x_send_incremental (event);
+
+         /* If we're being told about a root window property, then it's
+            a cut buffer change.  */
+         if (event.xproperty.window == ROOT_WINDOW)
+           x_invalidate_cut_buffer_cache (&event.xproperty);
+
+         /* Otherwise, we're probably handling an incremental
+             selection transmission.  */
+         else
+           {
+             /* If we were to do this synchronously, there'd be no worry
+                about re-selecting. */
+             x_send_incremental (event);
+           }
          break;
 
        case Expose:
@@ -1936,7 +2049,6 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          if (f != 0)
            {
              KeySym keysym;
-             XComposeStatus status;
              char copy_buffer[80];
              int modifiers = event.xkey.state;
 
@@ -1947,12 +2059,10 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                 just clear the meta-key flag to get the 'pure' character.  */
              event.xkey.state &= ~Mod1Mask;
 
-             /* This will have to go some day... */
-             nbytes = XLookupString (&event.xkey,
-                                     copy_buffer,
-                                     80,
-                                     &keysym,
-                                     &status);
+             /* This will have to go some day...  */
+             nbytes =
+               XLookupString (&event.xkey, copy_buffer, 80, &keysym,
+                              &compose_status);
 
              /* Strip off the vendor-specific keysym bit, and take a shot
                 at recognizing the codes.  HP servers have extra keysyms
@@ -1981,7 +2091,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
 
                      if (nbytes == 1)
                        {
-                         if (modifiers & Mod1Mask)
+                         if (modifiers & x_meta_mod_mask)
                            *copy_buffer |= METABIT;
                          bufp->kind = ascii_keystroke;
                          XSET (bufp->code, Lisp_Int, *copy_buffer);
@@ -2231,7 +2341,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
            if (f)
              if (!x_focus_frame || (f == x_focus_frame))
                construct_mouse_click (&emacs_event,
-                                      &event, f, 0, 0);
+                                      &event, f, Qnil, 0);
              else
                continue;
            else
@@ -2306,10 +2416,16 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
 #endif /* ! defined (HAVE_X11) */
 
        case MappingNotify:
-         if (event.xmapping.request == MappingKeyboard)
-           /* Someone has changed the keyboard mapping - flush the
-              local cache.  */
-           XRefreshKeyboardMapping (&event.xmapping);
+         /* Someone has changed the keyboard mapping - update the
+            local cache.  */
+         switch (event.xmapping.request)
+           {
+           case MappingModifier:
+             x_find_modifier_meanings ();
+             /* This is meant to fall through.  */
+           case MappingKeyboard:
+             XRefreshKeyboardMapping (&event.xmapping);
+           }
          break;
 
        default:
@@ -3061,11 +3177,11 @@ x_calc_absolute_position (f)
 #ifdef HAVE_X11
   if (f->display.x->left_pos < 0)
     f->display.x->left_pos
-      = XINT (x_screen_width) - PIXEL_WIDTH (f) + f->display.x->left_pos;
+      = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
 
   if (f->display.x->top_pos < 0)
     f->display.x->top_pos
-      = XINT (x_screen_height) - PIXEL_HEIGHT (f) + f->display.x->top_pos;
+      = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
 #else /* ! defined (HAVE_X11) */
   WINDOWINFO_TYPE parentinfo;
 
@@ -3517,14 +3633,38 @@ x_wm_set_size_hint (f, prompting)
     (x_screen_height - ((2 * f->display.x->internal_border_width)
                        + f->display.x->h_scrollbar_height));
   {
-    int min_rows = 0, min_cols = 0;
-    check_frame_size (f, &min_rows, &min_cols);
-    size_hints.min_width  = ((2 * f->display.x->internal_border_width)
-                            + min_cols * size_hints.width_inc
-                            + f->display.x->v_scrollbar_width);
-    size_hints.min_height = ((2 * f->display.x->internal_border_width)
-                            + min_rows * size_hints.height_inc
-                            + f->display.x->h_scrollbar_height);
+    int base_width, base_height;
+
+    base_width = ((2 * f->display.x->internal_border_width)
+                 + f->display.x->v_scrollbar_width);
+    base_height = ((2 * f->display.x->internal_border_width)
+                  + f->display.x->h_scrollbar_height);
+
+    {
+      int min_rows = 0, min_cols = 0;
+      check_frame_size (f, &min_rows, &min_cols);
+
+      /* The window manager uses the base width hints to calculate the
+        current number of rows and columns in the frame while
+        resizing; min_width and min_height aren't useful for this
+        purpose, since they might not give the dimensions for a
+        zero-row, zero-column frame.
+
+        We use the base_width and base_height members if we have
+        them; otherwise, we set the min_width and min_height members
+        to the size for a zero x zero frame.  */
+
+#ifdef HAVE_X11R4
+      size_hints.flags |= PBaseSize;
+      size_hints.base_width = base_width;
+      size_hints.base_height = base_height;
+      size_hints.min_width  = base_width + min_cols * size_hints.width_inc;
+      size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+#else
+      size_hints.min_width = base_width;
+      size_hints.min_height = base_height;
+#endif
+    }
 
   }
 
@@ -3545,7 +3685,11 @@ x_wm_set_size_hint (f, prompting)
        size_hints.flags |= USSize;
     }
 
+#ifdef HAVE_X11R4
+  XSetWMNormalHints (x_current_display, window, &size_hints);
+#else
   XSetNormalHints (x_current_display, window, &size_hints);
+#endif
 }
 
 /* Used for IconicState or NormalState */
@@ -3637,7 +3781,14 @@ x_term_init (display_name)
                                + 2);
     sprintf (x_id_name, "%s@%s", XSTRING (invocation_name)->data, hostname);
   }
+
+  /* Figure out which modifier bits mean what.  */
+  x_find_modifier_meanings ();
   
+  /* Watch for PropertyNotify events on the root window; we use them
+     to figure out when to invalidate our cache of the cut buffers.  */
+  x_watch_cut_buffer_cache ();
+
   dup2 (ConnectionNumber (x_current_display), 0);
 
 #ifndef SYSV_STREAMS