*** empty log message ***
[bpt/emacs.git] / src / xterm.c
index b5f87c4..c6fd73c 100644 (file)
@@ -93,6 +93,27 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /*#include <X/Xproto.h>        */
 #endif /* ! defined (HAVE_X11) */
 
+#ifdef FD_SET
+/* We could get this from param.h, but better not to depend on finding that.
+   And better not to risk that it might define other symbols used in this
+   file.  */
+#ifdef FD_SETSIZE
+#define MAXDESC FD_SETSIZE
+#else
+#define MAXDESC 64
+#endif
+#define SELECT_TYPE fd_set
+#else /* no FD_SET */
+#define MAXDESC 32
+#define SELECT_TYPE int
+
+/* Define the macros to access a single-int bitmap of descriptors.  */
+#define FD_SET(n, p) (*(p) |= (1 << (n)))
+#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
+#define FD_ISSET(n, p) (*(p) & (1 << (n)))
+#define FD_ZERO(p) (*(p) = 0)
+#endif /* no FD_SET */
+
 /* For sending Meta-characters.  Do we need this? */
 #define METABIT 0200
 
@@ -250,6 +271,7 @@ extern Cursor XCreateCursor ();
 extern FONT_TYPE *XOpenFont ();
 
 static void flashback ();
+static void redraw_previous_char ();
 
 #ifndef HAVE_X11
 static void dumpqueue ();
@@ -267,7 +289,7 @@ static int XTclear_end_of_line ();
    of the frame being updated, so that the XT... functions do not
    need to take a frame as argument.  Most of the XT... functions
    should never be called except during an update, the only exceptions
-   being XTcursor_to, XTwrite_char and XTreassert_line_highlight.  */
+   being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight.  */
 
 extern int mouse_track_top, mouse_track_left, mouse_track_width;
 
@@ -389,8 +411,8 @@ XTcursor_to (row, col)
    Since the display generation code is responsible for calling
    compute_char_face and compute_glyph_face on everything it puts in
    the display structure, we can assume that the face code on each
-   glyph is a valid index into FRAME_FACES (f), and the one to which
-   we can actually apply intern_face.  */
+   glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
+   to which we can actually apply intern_face.  */
 
 #if 1
 /* This is the multi-face code.  */
@@ -451,13 +473,14 @@ dumpglyphs (f, left, top, gp, n, hl)
          {
            /* The face codes on the glyphs must be valid indices into the
               frame's face table.  */
-           if (cf < 0 || cf >= FRAME_N_FACES (f))
+           if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
+               || FRAME_COMPUTED_FACES (f) [cf] == 0)
              abort ();
 
            if (cf == 1)
              face = FRAME_MODE_LINE_FACE (f);
            else
-             face = intern_face (f, FRAME_FACES (f) [cf]);
+             face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
            font = FACE_FONT (face);
            gc = FACE_GC (face);
            defaulted = 0;
@@ -658,7 +681,9 @@ XTclear_end_of_line (first_unused)
              CHAR_TO_PIXEL_ROW (f, curs_y),
              FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
              FONT_HEIGHT (f->display.x->font), False);
-             
+#if 0
+  redraw_previous_char (f, curs_x, curs_y);
+#endif
 #else /* ! defined (HAVE_X11) */
   XPixSet (FRAME_X_WINDOW (f),
           CHAR_TO_PIXEL_COL (f, curs_x),
@@ -671,6 +696,38 @@ XTclear_end_of_line (first_unused)
   UNBLOCK_INPUT;
 }
 
+/* Erase the character (if any) at the position just before X, Y in frame F,
+   then redraw it and the character before it.
+   This is necessary when we erase starting at X,
+   in case the character after X overlaps into the one before X.  */
+
+static void
+redraw_previous_char (f, x, y)
+     FRAME_PTR f;
+     int x, y;
+{
+  /* Erase the character before the new ones, in case
+     what was here before overlaps it.
+     Reoutput that character, and the previous character
+     (in case the previous character overlaps it).  */
+  if (x > 0)
+    {
+      int start_x = x - 2;
+      if (start_x < 0)
+       start_x = 0;
+      XClearArea (x_current_display, FRAME_X_WINDOW (f),
+                 CHAR_TO_PIXEL_COL (f, x - 1),
+                 CHAR_TO_PIXEL_ROW (f, y),
+                 FONT_WIDTH (f->display.x->font),
+                 FONT_HEIGHT (f->display.x->font), False);
+
+      dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
+                 CHAR_TO_PIXEL_ROW (f, y),
+                 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
+                 x - start_x, highlight);
+    }
+}
+
 static
 XTclear_frame ()
 {
@@ -1223,9 +1280,14 @@ static void
 frame_highlight (frame)
      struct frame *frame;
 {
-  if (! EQ (Vx_no_window_manager, Qnil))
-    XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
-                     frame->display.x->border_pixel);
+  /* We used to only do this if Vx_no_window_manager was non-nil, but
+     the ICCCM (section 4.1.6) says that the window's border pixmap
+     and border pixel are window attributes which are "private to the
+     client", so we can always change it to whatever we want.  */
+  BLOCK_INPUT;
+  XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
+                   frame->display.x->border_pixel);
+  UNBLOCK_INPUT;
   x_display_cursor (frame, 1);
 }
 
@@ -1233,9 +1295,14 @@ static void
 frame_unhighlight (frame)
      struct frame *frame;
 {
-  if (! EQ (Vx_no_window_manager, Qnil))
-    XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
-                           frame->display.x->border_tile);
+  /* We used to only do this if Vx_no_window_manager was non-nil, but
+     the ICCCM (section 4.1.6) says that the window's border pixmap
+     and border pixel are window attributes which are "private to the
+     client", so we can always change it to whatever we want.  */
+  BLOCK_INPUT;
+  XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
+                         frame->display.x->border_tile);
+  UNBLOCK_INPUT;
   x_display_cursor (frame, 1);
 }
 #else /* ! defined (HAVE_X11) */
@@ -2553,7 +2620,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
   int items_pending;           /* How many items are in the X queue. */
   XEvent event;
   struct frame *f;
-  int event_found;
+  int event_found = 0;
   int prefix;
   Lisp_Object part;
 
@@ -2829,7 +2896,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
              /* The window manager never makes a window invisible
                 ("withdrawn"); all it does is switch between visible
                 and iconified.  Frames get into the invisible state
-                only through x_make_frame_invisible.
+                only through x_make_frame_invisible.  */
              if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
                f->async_iconified = 1;
            }
@@ -2869,7 +2936,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          if (f != 0)
            {
              KeySym keysym, orig_keysym;
-             char copy_buffer[80];
+             unsigned char copy_buffer[80];
              int modifiers;
 
              event.xkey.state
@@ -2893,22 +2960,31 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
 
              if (numchars > 1)
                {
-                 if ((keysym >= XK_BackSpace && keysym <= XK_Escape)
-                     || keysym == XK_Delete
-                     || IsCursorKey (keysym)       /* 0xff50 <= x < 0xff60 */
-                     || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
+                 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
+                      || keysym == XK_Delete
+                      || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
+                      || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
 #ifdef HPUX
-                     /* This recognizes the "extended function keys".
-                        It seems there's no cleaner way.
-                        Test IsModifierKey to avoid handling mode_switch
-                        incorrectly.  */
-                     || (!IsModifierKey (orig_keysym)
-                         && (unsigned) (keysym) >= XK_Select
-                         && (unsigned)(keysym) < XK_KP_Space)
+                      /* This recognizes the "extended function keys".
+                         It seems there's no cleaner way.
+                         Test IsModifierKey to avoid handling mode_switch
+                         incorrectly.  */
+                      || ((unsigned) (keysym) >= XK_Select
+                          && (unsigned)(keysym) < XK_KP_Space)
+#endif
+                      || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
+                      || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
+                      || x_is_vendor_fkey (orig_keysym))
+                     && ! (IsModifierKey (orig_keysym)
+#ifndef HAVE_X11R5
+#ifdef XK_Mode_switch
+                           || ((unsigned)(orig_keysym) == XK_Mode_switch)
+#endif
+#ifdef XK_Num_Lock
+                           || ((unsigned)(orig_keysym) == XK_Num_Lock)
 #endif
-                     || IsKeypadKey (keysym)       /* 0xff80 <= x < 0xffbe */
-                     || IsFunctionKey (keysym)     /* 0xffbe <= x < 0xffe1 */
-                     || x_is_vendor_fkey (orig_keysym)) /* wherever */
+#endif /* not HAVE_X11R5 */
+                           ))
                    {
                      if (temp_index == sizeof temp_buffer / sizeof (short))
                        temp_index = 0;
@@ -3139,17 +3215,20 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                  Window win, child;
                  int win_x, win_y;
 
-                 /* Coords are relative to the parent.
-                    Convert them to root-relative.  */
+                 /* Find the position of the outside upper-left corner of
+                    the window, in the root coordinate system.  Don't
+                    refer to the parent window here; we may be processing
+                    this event after the window manager has changed our
+                    parent, but before we have reached the ReparentNotify.  */
                  XTranslateCoordinates (x_current_display,
                               
                                         /* From-window, to-window.  */
-                                        f->display.x->parent_desc,
+                                        f->display.x->window_desc,
                                         ROOT_WINDOW,
 
                                         /* From-position, to-position.  */
-                                        event.xconfigure.x,
-                                        event.xconfigure.y,
+                                        -event.xconfigure.border_width,
+                                        -event.xconfigure.border_width,
                                         &win_x, &win_y,
 
                                         /* Child of win.  */
@@ -3267,24 +3346,23 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
        }
     }
 
-#if 0
 #ifdef HAVE_SELECT
   if (expected && ! event_found)
     {
       /* AOJ 880406: if select returns true but XPending doesn't, it means that
         there is an EOF condition; in other words, that X has died.
         Act as if there had been a hangup. */
-
       int fd = ConnectionNumber (x_current_display);
-      int mask = 1 << fd;
+      SELECT_TYPE mask;
+      EMACS_TIME timeout;
 
-      if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
-                      (EMACS_TIME) 0)
+      FD_SET(fd, &mask);
+      EMACS_SET_SECS_USECS (timeout, 0, 0);
+      if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0, &timeout)
          && !XStuffPending ())
        kill (getpid (), SIGHUP);
     }
 #endif /* ! defined (HAVE_SELECT) */
-#endif /* ! 0 */
 
 #ifndef HAVE_X11
   if (updating_frame == 0)
@@ -3781,7 +3859,7 @@ x_connection_closed ()
   if (_Xdebug)
     abort ();
 
-  shut_down_emacs (0, 1);
+  shut_down_emacs (0, 1, Qnil);
 
   exit (70);
 }
@@ -3920,8 +3998,14 @@ x_trace_wire ()
 
 #ifdef HAVE_X11
 
+struct font_info
+{
+  XFontStruct *font;
+  char *name;
+};
+
 /* A table of all the fonts we have already loaded.  */
-static XFontStruct **x_font_table;
+static struct font_info *x_font_table;
 
 /* The current capacity of x_font_table.  */
 static int x_font_table_size;
@@ -3944,9 +4028,8 @@ x_new_font (f, fontname)
   /* Get a list of all the fonts that match this name.  Once we
      have a list of matching fonts, we compare them against the fonts
      we already have by comparing font ids.  */
-  font_names = (char **) XListFontsWithInfo (x_current_display, fontname,
-                                            1024, &n_matching_fonts,
-                                            &font_info);
+  font_names = (char **) XListFonts (x_current_display, fontname,
+                                    1024, &n_matching_fonts);
   /* Apparently it doesn't set n_matching_fonts to zero when it can't
      find any matches; font_names == 0 is the only clue.  */
   if (! font_names)
@@ -3964,7 +4047,7 @@ x_new_font (f, fontname)
 
       for (i = 0; i < n_fonts; i++)
        for (j = 0; j < n_matching_fonts; j++)
-         if (x_font_table[i]->fid == font_info[j].fid)
+         if (!strcmp (x_font_table[i].name, font_names[j]))
            {
              already_loaded = i;
              fontname = font_names[j];
@@ -3974,8 +4057,8 @@ x_new_font (f, fontname)
  found_font:
   
   /* If we have, just return it from the table.  */
-  if (already_loaded > 0)
-    f->display.x->font = x_font_table[already_loaded];
+  if (already_loaded >= 0)
+    f->display.x->font = x_font_table[already_loaded].font;
   
   /* Otherwise, load the font and add it to the table.  */
   else
@@ -4000,9 +4083,9 @@ x_new_font (f, fontname)
       font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
       if (! font)
        {
-         /* Free the information from XListFontsWithInfo.  */
+         /* Free the information from XListFonts.  */
          if (n_matching_fonts)
-           XFreeFontInfo (font_names, font_info, n_matching_fonts);
+           XFreeFontNames (font_names);
          return Qnil;
        }
 
@@ -4011,22 +4094,24 @@ x_new_font (f, fontname)
        {
          x_font_table_size = 16;
          x_font_table
-           = (XFontStruct **) xmalloc (x_font_table_size
-                                       * sizeof (x_font_table[0]));
+           = (struct font_info *) xmalloc (x_font_table_size
+                                           * sizeof (x_font_table[0]));
        }
       /* Do we need to grow the table?  */
       else if (n_fonts >= x_font_table_size)
        {
          x_font_table_size *= 2;
          x_font_table
-           = (XFontStruct **) xrealloc (x_font_table,
-                                        (x_font_table_size
-                                         * sizeof (x_font_table[0])));
+           = (struct font_info *) xrealloc (x_font_table,
+                                            (x_font_table_size
+                                             * sizeof (x_font_table[0])));
        }
 
-      f->display.x->font = x_font_table[n_fonts++] = font;
+      x_font_table[n_fonts].name = (char *) xmalloc (strlen (fontname));
+      bcopy (fontname, x_font_table[n_fonts].name, strlen (fontname) + 1);
+      f->display.x->font = x_font_table[n_fonts++].font = font;
     }
-  
+
   /* Now make the frame display the given font.  */
   if (FRAME_X_WINDOW (f) != 0)
     {
@@ -4044,9 +4129,9 @@ x_new_font (f, fontname)
     Lisp_Object lispy_name = build_string (fontname);
 
 
-    /* Free the information from XListFontsWithInfo.  The data
+    /* Free the information from XListFonts.  The data
        we actually retain comes from XLoadQueryFont.  */
-    XFreeFontInfo (font_names, font_info, n_matching_fonts);
+    XFreeFontNames (font_names);
 
     return lispy_name;
   }
@@ -4081,13 +4166,42 @@ x_calc_absolute_position (f)
      struct frame *f;
 {
 #ifdef HAVE_X11
+  Window win, child;
+  int win_x = 0, win_y = 0;
+
+  /* Find the position of the outside upper-left corner of
+     the inner window, with respect to the outer window.  */
+  if (f->display.x->parent_desc != ROOT_WINDOW)
+    {
+      BLOCK_INPUT;
+      XTranslateCoordinates (x_current_display,
+                              
+                            /* From-window, to-window.  */
+                            f->display.x->window_desc,
+                            f->display.x->parent_desc,
+
+                            /* From-position, to-position.  */
+                            0, 0, &win_x, &win_y,
+
+                            /* Child of win.  */
+                            &child);
+      UNBLOCK_INPUT;
+    }
+
+  /* Treat negative positions as relative to the leftmost bottommost
+     position that fits on the screen.  */
   if (f->display.x->left_pos < 0)
-    f->display.x->left_pos
-      = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
+    f->display.x->left_pos = (x_screen_width 
+                             - f->display.x->border_width - win_x
+                             - PIXEL_WIDTH (f)
+                             + f->display.x->left_pos);
 
   if (f->display.x->top_pos < 0)
-    f->display.x->top_pos
-      = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
+    f->display.x->top_pos = (x_screen_height
+                            - f->display.x->border_width - win_y
+                            - PIXEL_HEIGHT (f)
+                            + f->display.x->top_pos);
+
 #else /* ! defined (HAVE_X11) */
   WINDOWINFO_TYPE parentinfo;
 
@@ -4115,7 +4229,7 @@ x_set_offset (f, xoff, yoff)
   XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
               f->display.x->left_pos, f->display.x->top_pos);
 #ifdef HAVE_X11
-  x_wm_set_size_hint (f, 0);
+  x_wm_set_size_hint (f, 0, xoff, yoff);
 #endif /* ! defined (HAVE_X11) */
   UNBLOCK_INPUT;
 }
@@ -4132,15 +4246,15 @@ x_set_window_size (f, cols, rows)
   BLOCK_INPUT;
 
   check_frame_size (f, &rows, &cols);
-  f->display.x->vertical_scroll_bar_extra =
-    (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
-     ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
-     : 0);
+  f->display.x->vertical_scroll_bar_extra
+    (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+       ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
+       : 0);
   pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
   pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
 
 #ifdef HAVE_X11
-  x_wm_set_size_hint (f, 0);
+  x_wm_set_size_hint (f, 0, 0, 0);
 #endif /* ! defined (HAVE_X11) */
   XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
 
@@ -4420,6 +4534,14 @@ x_iconify_frame (f)
      IconicState.  */
   x_wm_set_window_state (f, IconicState);
 
+  if (!FRAME_VISIBLE_P (f))
+    {
+      /* If the frame was withdrawn, before, we must map it.  */
+      XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+       XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
+    }
+
   f->async_iconified = 1;
 #else /* ! defined (HAVE_X11) */
   XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
@@ -4537,9 +4659,13 @@ mouse_event_pending_p ()
 
 #ifdef HAVE_X11
 
-x_wm_set_size_hint (f, prompting)
+/* SPEC_X and SPEC_Y are the specified positions.
+   We look only at their sign, to decide the gravity.  */
+
+x_wm_set_size_hint (f, prompting, spec_x, spec_y)
      struct frame *f;
      long prompting;
+     int spec_x, spec_y;
 {
   XSizeHints size_hints;
   Window window = FRAME_X_WINDOW (f);
@@ -4610,6 +4736,23 @@ x_wm_set_size_hint (f, prompting)
        size_hints.flags |= USSize;
     }
 
+  switch (((spec_x < 0) << 1) + (spec_y < 0))
+    {
+    case 0:
+      size_hints.win_gravity = NorthWestGravity;
+      break;
+    case 1:
+      size_hints.win_gravity = SouthWestGravity;
+      break;
+    case 2:
+      size_hints.win_gravity = NorthEastGravity;
+      break;
+    case 3:
+      size_hints.win_gravity = SouthEastGravity;
+      break;
+    }
+  size_hints.flags |= PWinGravity;
+
 #ifdef HAVE_X11R4
   XSetWMNormalHints (x_current_display, window, &size_hints);
 #else
@@ -4669,15 +4812,18 @@ x_term_init (display_name)
 {
   Lisp_Object frame;
   char *defaultvalue;
+#ifndef F_SETOWN_BUG
 #ifdef F_SETOWN
   extern int old_fcntl_owner;
 #endif /* ! defined (F_SETOWN) */
+#endif /* F_SETOWN_BUG */
   
   x_focus_frame = x_highlight_frame = 0;
 
   x_current_display = XOpenDisplay (display_name);
   if (x_current_display == 0)
-    fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n",
+    fatal ("X server %s not responding.\n\
+Check the DISPLAY environment variable or use \"-d\"\n",
           display_name);
 
 #ifdef HAVE_X11
@@ -4742,6 +4888,7 @@ x_term_init (display_name)
 
 #endif /* ! defined (HAVE_X11) */
   
+#ifndef F_SETOWN_BUG
 #ifdef F_SETOWN
   old_fcntl_owner = fcntl (0, F_GETOWN, 0);
 #ifdef F_SETOWN_SOCK_NEG
@@ -4750,16 +4897,12 @@ x_term_init (display_name)
   fcntl (0, F_SETOWN, getpid ());
 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
 #endif /* ! defined (F_SETOWN) */
+#endif /* F_SETOWN_BUG */
 
 #ifdef SIGIO
   init_sigio ();
 #endif /* ! defined (SIGIO) */
 
-  /* Must use interrupt input because we cannot otherwise
-     arrange for C-g to be noticed immediately.
-     We cannot connect it to SIGINT.  */
-  Fset_input_mode (Qt, Qnil, Qt, Qnil);
-
   expose_all_windows = 0;
 
   clear_frame_hook = XTclear_frame;
@@ -4794,6 +4937,9 @@ x_term_init (display_name)
                                   off the bottom */
   baud_rate = 19200;
 
+  /* Try to use interrupt input; if we can't, then start polling.  */
+  Fset_input_mode (Qt, Qnil, Qt, Qnil);
+
   /* Note that there is no real way portable across R3/R4 to get the 
      original error handler.  */
   XHandleError (x_error_quitter);