]> code.delx.au - gnu-emacs/blobdiff - src/dispnew.c
(archive-l-e): New optional argument `float' means generate a float value.
[gnu-emacs] / src / dispnew.c
index 35e03eff9c65de30ef4eb7394ac30f14aa70dfcd..da5e9c6e3986aafda51a50ea2f8349bac1ed4e35 100644 (file)
@@ -1,6 +1,7 @@
 /* Updating of data structures for redisplay.
-   Copyright (C) 1985,86,87,88,93,94,95,97,98,1999,2000,01,02,2003
-       Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
+                 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+                 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,8 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 #include <signal.h>
@@ -1184,6 +1185,9 @@ increment_row_positions (row, delta, delta_bytes)
   MATRIX_ROW_END_CHARPOS (row) += delta;
   MATRIX_ROW_END_BYTEPOS (row) += delta_bytes;
 
+  if (!row->enabled_p)
+    return;
+
   /* Increment positions in glyphs.  */
   for (area = 0; area < LAST_AREA; ++area)
     for (i = 0; i < row->used[area]; ++i)
@@ -1513,12 +1517,14 @@ row_equal_p (w, a, b, mouse_face_p)
            return 0;
        }
 
-      if (a->truncated_on_left_p != b->truncated_on_left_p
-         || a->fill_line_p != b->fill_line_p
-         || a->truncated_on_right_p != b->truncated_on_right_p
-         || a->overlay_arrow_p != b->overlay_arrow_p
-         || a->continued_p != b->continued_p
-         || a->indicate_empty_line_p != b->indicate_empty_line_p
+      if (a->fill_line_p != b->fill_line_p
+         || a->cursor_in_fringe_p != b->cursor_in_fringe_p
+         || a->left_fringe_bitmap != b->left_fringe_bitmap
+         || a->left_fringe_face_id != b->left_fringe_face_id
+         || a->right_fringe_bitmap != b->right_fringe_bitmap
+         || a->right_fringe_face_id != b->right_fringe_face_id
+         || a->overlay_arrow_bitmap != b->overlay_arrow_bitmap
+         || a->exact_window_width_line_p != b->exact_window_width_line_p
          || a->overlapped_p != b->overlapped_p
          || (MATRIX_ROW_CONTINUATION_LINE_P (a)
              != MATRIX_ROW_CONTINUATION_LINE_P (b))
@@ -1909,10 +1915,10 @@ allocate_matrices_for_frame_redisplay (window, x, y, dim_only_p,
              || dim.width != w->desired_matrix->matrix_w
              || dim.height != w->desired_matrix->matrix_h
              || (margin_glyphs_to_reserve (w, dim.width,
-                                           w->right_margin_cols)
+                                           w->left_margin_cols)
                  != w->desired_matrix->left_margin_glyphs)
              || (margin_glyphs_to_reserve (w, dim.width,
-                                           w->left_margin_cols)
+                                           w->right_margin_cols)
                  != w->desired_matrix->right_margin_glyphs))
            *window_change_flags |= CHANGED_LEAF_MATRIX;
 
@@ -1980,7 +1986,7 @@ required_matrix_height (w)
       int ch_height = FRAME_SMALLEST_FONT_HEIGHT (f);
       int window_pixel_height = window_box_height (w) + abs (w->vscroll);
       return (((window_pixel_height + ch_height - 1)
-              / ch_height)
+              / ch_height) * w->nrows_scale_factor
              /* One partially visible line at the top and
                 bottom of the window.  */
              + 2
@@ -2008,7 +2014,7 @@ required_matrix_width (w)
 
       /* Compute number of glyphs needed in a glyph row.  */
       return (((window_pixel_width + ch_width - 1)
-              / ch_width)
+              / ch_width) * w->ncols_scale_factor
              /* 2 partially visible columns in the text area.  */
              + 2
              /* One partially visible column at the right
@@ -2717,9 +2723,15 @@ build_frame_matrix_from_leaf_window (frame_matrix, w)
       if (!WINDOW_RIGHTMOST_P (w))
        {
          struct Lisp_Char_Table *dp = window_display_table (w);
-         right_border_glyph = (dp && INTEGERP (DISP_BORDER_GLYPH (dp))
-                               ? XINT (DISP_BORDER_GLYPH (dp))
-                               : '|');
+
+         right_border_glyph
+           = ((dp && INTEGERP (DISP_BORDER_GLYPH (dp)))
+              ? spec_glyph_lookup_face (w, XINT (DISP_BORDER_GLYPH (dp)))
+              : '|');
+
+         if (FAST_GLYPH_FACE (right_border_glyph) <= 0)
+           right_border_glyph
+             = FAST_MAKE_GLYPH (right_border_glyph, VERTICAL_BORDER_FACE_ID);
        }
     }
   else
@@ -2775,6 +2787,7 @@ build_frame_matrix_from_leaf_window (frame_matrix, w)
              SET_CHAR_GLYPH_FROM_GLYPH (*border, right_border_glyph);
            }
 
+#if GLYPH_DEBUG
          /* Window row window_y must be a slice of frame row
             frame_y.  */
          xassert (glyph_row_slice_p (window_row, frame_row));
@@ -2782,7 +2795,6 @@ build_frame_matrix_from_leaf_window (frame_matrix, w)
          /* If rows are in sync, we don't have to copy glyphs because
             frame and window share glyphs.  */
 
-#if GLYPH_DEBUG
          strcpy (w->current_matrix->method, w->desired_matrix->method);
          add_window_display_history (w, w->current_matrix->method, 0);
 #endif
@@ -2800,6 +2812,27 @@ build_frame_matrix_from_leaf_window (frame_matrix, w)
     }
 }
 
+/* Given a user-specified glyph, possibly including a Lisp-level face
+   ID, return a glyph that has a realized face ID.
+   This is used for glyphs displayed specially and not part of the text;
+   for instance, vertical separators, truncation markers, etc.  */
+
+GLYPH
+spec_glyph_lookup_face (w, glyph)
+     struct window *w;
+     GLYPH glyph;
+{
+  int lface_id = FAST_GLYPH_FACE (glyph);
+  /* Convert the glyph's specified face to a realized (cache) face.  */
+  if (lface_id > 0)
+    {
+      int face_id = merge_faces (XFRAME (w->frame),
+                                Qt, lface_id, DEFAULT_FACE_ID);
+      glyph
+       = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), face_id);
+    }
+  return glyph;
+}
 
 /* Add spaces to a glyph row ROW in a window matrix.
 
@@ -3162,15 +3195,21 @@ mirror_line_dance (w, unchanged_at_top, nlines, copy_from, retained_p)
                  struct glyph_matrix *m2;
                  int m2_from;
 
-                 w2 = frame_row_to_window (root, frame_to);
-                 m2 = w2->current_matrix;
-                 m2_from = frame_from - m2->matrix_y;
-                 copy_row_except_pointers (m->rows + window_to,
-                                           m2->rows + m2_from);
-
-                 /* If frame line is empty, window line is empty, too.  */
-                 if (!retained_p[copy_from[i]])
-                   m->rows[window_to].enabled_p = 0;
+                 w2 = frame_row_to_window (root, frame_from);
+                 /* ttn@surf.glug.org: when enabling menu bar using `emacs
+                    -nw', FROM_FRAME sometimes has no associated window.
+                    This check avoids a segfault if W2 is null.  */
+                 if (w2)
+                   {
+                     m2 = w2->current_matrix;
+                     m2_from = frame_from - m2->matrix_y;
+                     copy_row_except_pointers (m->rows + window_to,
+                                               m2->rows + m2_from);
+
+                     /* If frame line is empty, window line is empty, too.  */
+                     if (!retained_p[copy_from[i]])
+                       m->rows[window_to].enabled_p = 0;
+                   }
                  sync_p = 1;
                }
              else if (from_inside_window_p)
@@ -3285,9 +3324,7 @@ window_to_frame_hpos (w, hpos)
      struct window *w;
      int hpos;
 {
-  struct frame *f = XFRAME (w->frame);
-
-  xassert (!FRAME_WINDOW_P (f));
+  xassert (!FRAME_WINDOW_P (XFRAME (w->frame)));
   hpos += WINDOW_LEFT_EDGE_COL (w);
   return hpos;
 }
@@ -3450,6 +3487,7 @@ direct_output_for_insert (g)
          /* Can't do it in a continued line because continuation
             lines would change.  */
          (glyph_row->continued_p
+          || glyph_row->exact_window_width_line_p
           /* Can't use this method if the line overlaps others or is
              overlapped by others because these other lines would
              have to be redisplayed.  */
@@ -3655,6 +3693,10 @@ direct_output_for_insert (g)
       cursor_to (y, x);
     }
 
+#ifdef HAVE_WINDOW_SYSTEM
+  update_window_fringes (w, 0);
+#endif
+
   if (rif)
     rif->update_window_end_hook (w, 1, 0);
   update_end (f);
@@ -3822,10 +3864,15 @@ update_frame (f, force_p, inhibit_hairy_id_p)
       paused_p = update_window_tree (root_window, force_p);
       update_end (f);
 
-#if 0 /* This flush is a performance bottleneck under X,
-        and it doesn't seem to be necessary anyway.  */
-      rif->flush_display (f);
-#endif
+      /* This flush is a performance bottleneck under X,
+        and it doesn't seem to be necessary anyway (in general).
+         It is necessary when resizing the window with the mouse, or
+        at least the fringes are not redrawn in a timely manner.  ++kfs */
+      if (f->force_flush_display_p)
+       {
+         rif->flush_display (f);
+         f->force_flush_display_p = 0;
+       }
     }
   else
     {
@@ -3916,6 +3963,7 @@ update_single_window (w, force_p)
     }
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
 
 /* Redraw lines from the current matrix of window W that are
    overlapped by other rows.  YB is bottom-most y-position in W.  */
@@ -3988,23 +4036,33 @@ redraw_overlapping_rows (w, yb)
 
       if (row->overlapping_p && i > 0 && bottom_y < yb)
        {
-         if (row->used[LEFT_MARGIN_AREA])
-           rif->fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
-
-         if (row->used[TEXT_AREA])
-           rif->fix_overlapping_area (w, row, TEXT_AREA);
-
-         if (row->used[RIGHT_MARGIN_AREA])
-           rif->fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
-
-         /* Record in neighbour rows that ROW overwrites part of their
-            display.  */
-         if (row->phys_ascent > row->ascent && i > 0)
-           MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p = 1;
-         if ((row->phys_height - row->phys_ascent
-              > row->height - row->ascent)
-             && bottom_y < yb)
-           MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p = 1;
+         int overlaps = 0;
+
+         if (MATRIX_ROW_OVERLAPS_PRED_P (row)
+             && !MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p)
+           overlaps |= OVERLAPS_PRED;
+         if (MATRIX_ROW_OVERLAPS_SUCC_P (row)
+             && !MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p)
+           overlaps |= OVERLAPS_SUCC;
+
+         if (overlaps)
+           {
+             if (row->used[LEFT_MARGIN_AREA])
+               rif->fix_overlapping_area (w, row, LEFT_MARGIN_AREA, overlaps);
+
+             if (row->used[TEXT_AREA])
+               rif->fix_overlapping_area (w, row, TEXT_AREA, overlaps);
+
+             if (row->used[RIGHT_MARGIN_AREA])
+               rif->fix_overlapping_area (w, row, RIGHT_MARGIN_AREA, overlaps);
+
+             /* Record in neighbour rows that ROW overwrites part of
+                their display.  */
+             if (overlaps & OVERLAPS_PRED)
+               MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p = 1;
+             if (overlaps & OVERLAPS_SUCC)
+               MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p = 1;
+           }
        }
 
       if (bottom_y >= yb)
@@ -4012,6 +4070,8 @@ redraw_overlapping_rows (w, yb)
     }
 }
 
+#endif /* HAVE_WINDOW_SYSTEM */
+
 
 #ifdef GLYPH_DEBUG
 
@@ -4052,18 +4112,16 @@ update_window (w, force_p)
   extern int input_pending;
   extern Lisp_Object do_mouse_tracking;
 #if GLYPH_DEBUG
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
-#endif
-
   /* Check that W's frame doesn't have glyph matrices.  */
-  xassert (FRAME_WINDOW_P (f));
+  xassert (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w))));
   xassert (updating_frame != NULL);
+#endif
 
   /* Check pending input the first time so that we can quickly return.  */
   if (redisplay_dont_pause)
     force_p = 1;
   else
-    detect_input_pending ();
+    detect_input_pending_ignore_squeezables ();
 
   /* If forced to complete the update, or if no input is pending, do
      the update.  */
@@ -4098,7 +4156,6 @@ update_window (w, force_p)
          update_window_line (w, MATRIX_ROW_VPOS (mode_line_row,
                                                  desired_matrix),
                              &mouse_face_overwritten_p);
-         changed_p = 1;
        }
 
       /* Find first enabled row.  Optimizations in redisplay_internal
@@ -4118,19 +4175,11 @@ update_window (w, force_p)
              goto set_cursor;
            }
          else if (rc > 0)
-           /* We've scrolled the display.  */
-           force_p = 1;
-         changed_p = 1;
-       }
-
-      /* Update the header line after scrolling because a new header
-        line would otherwise overwrite lines at the top of the window
-        that can be scrolled.  */
-      if (header_line_row && header_line_row->enabled_p)
-       {
-         header_line_row->y = 0;
-         update_window_line (w, 0, &mouse_face_overwritten_p);
-         changed_p = 1;
+           {
+             /* We've scrolled the display.  */
+             force_p = 1;
+             changed_p = 1;
+           }
        }
 
       /* Update the rest of the lines.  */
@@ -4145,7 +4194,7 @@ update_window (w, force_p)
               scrolling large windows with repeated scroll-up
               commands will too quickly pause redisplay.  */
            if (!force_p && ++n_updated % preempt_count == 0)
-             detect_input_pending ();
+             detect_input_pending_ignore_squeezables ();
 
            changed_p |= update_window_line (w, vpos,
                                             &mouse_face_overwritten_p);
@@ -4169,14 +4218,25 @@ update_window (w, force_p)
 
     set_cursor:
 
+      /* Update the header line after scrolling because a new header
+        line would otherwise overwrite lines at the top of the window
+        that can be scrolled.  */
+      if (header_line_row && header_line_row->enabled_p)
+       {
+         header_line_row->y = 0;
+         update_window_line (w, 0, &mouse_face_overwritten_p);
+       }
+
       /* Fix the appearance of overlapping/overlapped rows.  */
       if (!paused_p && !w->pseudo_window_p)
        {
+#ifdef HAVE_WINDOW_SYSTEM
          if (changed_p && rif->fix_overlapping_area)
            {
              redraw_overlapped_rows (w, yb);
              redraw_overlapping_rows (w, yb);
            }
+#endif
 
          /* Make cursor visible at cursor position of W.  */
          set_window_cursor_after_update (w);
@@ -4192,6 +4252,10 @@ update_window (w, force_p)
       strcpy (w->current_matrix->method, w->desired_matrix->method);
 #endif
 
+#ifdef HAVE_WINDOW_SYSTEM
+      update_window_fringes (w, 0);
+#endif
+
       /* End the update of window W.  Don't set the cursor if we
          paused updating the display because in this case,
          set_window_cursor_after_update hasn't been called, and
@@ -4292,10 +4356,14 @@ update_text_area (w, vpos)
       int overlapping_glyphs_p = current_row->contains_overlapping_glyphs_p;
       int desired_stop_pos = desired_row->used[TEXT_AREA];
 
-      /* If the desired row extends its face to the text area end,
+      /* If the desired row extends its face to the text area end, and
+        unless the current row also does so at the same position,
         make sure we write at least one glyph, so that the face
         extension actually takes place.  */
-      if (MATRIX_ROW_EXTENDS_FACE_P (desired_row))
+      if (MATRIX_ROW_EXTENDS_FACE_P (desired_row)
+         && (desired_stop_pos < current_row->used[TEXT_AREA]
+             || (desired_stop_pos == current_row->used[TEXT_AREA]
+                 && !MATRIX_ROW_EXTENDS_FACE_P (current_row))))
        --desired_stop_pos;
 
       stop = min (current_row->used[TEXT_AREA], desired_stop_pos);
@@ -4414,7 +4482,10 @@ update_text_area (w, vpos)
             has to be cleared, if and only if we did a write_glyphs
             above.  This is made sure by setting desired_stop_pos
             appropriately above.  */
-         xassert (i < desired_row->used[TEXT_AREA]);
+         xassert (i < desired_row->used[TEXT_AREA]
+                  || ((desired_row->used[TEXT_AREA]
+                       == current_row->used[TEXT_AREA])
+                      && MATRIX_ROW_EXTENDS_FACE_P (current_row)));
        }
       else if (MATRIX_ROW_EXTENDS_FACE_P (current_row))
        {
@@ -4510,13 +4581,11 @@ update_window_line (w, vpos, mouse_face_overwritten_p)
       if (!current_row->enabled_p
          || desired_row->y != current_row->y
          || desired_row->visible_height != current_row->visible_height
-         || desired_row->overlay_arrow_p != current_row->overlay_arrow_p
-         || desired_row->truncated_on_left_p != current_row->truncated_on_left_p
-         || desired_row->truncated_on_right_p != current_row->truncated_on_right_p
-         || desired_row->continued_p != current_row->continued_p
+         || desired_row->cursor_in_fringe_p != current_row->cursor_in_fringe_p
+         || desired_row->overlay_arrow_bitmap != current_row->overlay_arrow_bitmap
+         || current_row->redraw_fringe_bitmaps_p
          || desired_row->mode_line_p != current_row->mode_line_p
-         || (desired_row->indicate_empty_line_p
-             != current_row->indicate_empty_line_p)
+         || desired_row->exact_window_width_line_p != current_row->exact_window_width_line_p
          || (MATRIX_ROW_CONTINUATION_LINE_P (desired_row)
              != MATRIX_ROW_CONTINUATION_LINE_P (current_row)))
        rif->after_update_window_line_hook (desired_row);
@@ -4769,6 +4838,7 @@ scrolling_window (w, header_line_p)
 
       if (c->enabled_p
          && d->enabled_p
+         && !d->redraw_fringe_bitmaps_p
          && c->y == d->y
          && MATRIX_ROW_BOTTOM_Y (c) <= yb
          && MATRIX_ROW_BOTTOM_Y (d) <= yb
@@ -4824,6 +4894,7 @@ scrolling_window (w, header_line_p)
          && MATRIX_ROW (current_matrix, i - 1)->enabled_p
         && (MATRIX_ROW (current_matrix, i - 1)->y
             == MATRIX_ROW (desired_matrix, j - 1)->y)
+        && !MATRIX_ROW (desired_matrix, j - 1)->redraw_fringe_bitmaps_p
          && row_equal_p (w,
                         MATRIX_ROW (desired_matrix, i - 1),
                          MATRIX_ROW (current_matrix, j - 1), 1))
@@ -5016,6 +5087,13 @@ scrolling_window (w, header_line_p)
            to = MATRIX_ROW (current_matrix, r->desired_vpos + j);
            from = MATRIX_ROW (desired_matrix, r->desired_vpos + j);
            to_overlapped_p = to->overlapped_p;
+           if (!from->mode_line_p && !w->pseudo_window_p
+               && (to->left_fringe_bitmap != from->left_fringe_bitmap
+                   || to->right_fringe_bitmap != from->right_fringe_bitmap
+                   || to->left_fringe_face_id != from->left_fringe_face_id
+                   || to->right_fringe_face_id != from->right_fringe_face_id
+                   || to->overlay_arrow_bitmap != from->overlay_arrow_bitmap))
+             from->redraw_fringe_bitmaps_p = 1;
            assign_row (to, from);
            to->enabled_p = 1, from->enabled_p = 0;
            to->overlapped_p = to_overlapped_p;
@@ -5026,8 +5104,8 @@ scrolling_window (w, header_line_p)
   for (i = 0; i < row_entry_idx; ++i)
     row_table[row_entry_pool[i].bucket] = NULL;
 
-  /* Value is non-zero to indicate that we scrolled the display.  */
-  return 1;
+  /* Value is > 0 to indicate that we scrolled the display.  */
+  return nruns;
 }
 
 
@@ -5068,7 +5146,7 @@ update_frame_1 (f, force_p, inhibit_id_p)
 
   if (redisplay_dont_pause)
     force_p = 1;
-  else if (!force_p && detect_input_pending ())
+  else if (!force_p && detect_input_pending_ignore_squeezables ())
     {
       pause = 1;
       goto do_pause;
@@ -5124,7 +5202,7 @@ update_frame_1 (f, force_p, inhibit_id_p)
            }
 
          if ((i - 1) % preempt_count == 0)
-           detect_input_pending ();
+           detect_input_pending_ignore_squeezables ();
 
          update_frame_line (f, i);
        }
@@ -5687,21 +5765,27 @@ update_frame_line (f, vpos)
  ***********************************************************************/
 
 /* Determine what's under window-relative pixel position (*X, *Y).
-   Return in *OBJECT the object (string or buffer) that's there.
-   Return in *POS the position in that object. Adjust *X and *Y
-   to character positions.  */
+   Return the object (string or buffer) that's there.
+   Return in *POS the position in that object.
+   Adjust *X and *Y to character positions.  */
 
-void
-buffer_posn_from_coords (w, x, y, object, pos)
+Lisp_Object
+buffer_posn_from_coords (w, x, y, pos, object, dx, dy, width, height)
      struct window *w;
      int *x, *y;
-     Lisp_Object *object;
      struct display_pos *pos;
+     Lisp_Object *object;
+     int *dx, *dy;
+     int *width, *height;
 {
   struct it it;
   struct buffer *old_current_buffer = current_buffer;
   struct text_pos startp;
+  Lisp_Object string;
   struct glyph_row *row;
+#ifdef HAVE_WINDOW_SYSTEM
+  struct image *img = 0;
+#endif
   int x0, x1;
 
   current_buffer = XBUFFER (w->buffer);
@@ -5714,42 +5798,96 @@ buffer_posn_from_coords (w, x, y, object, pos)
   move_it_to (&it, -1, x0 + it.first_visible_x, *y, -1,
              MOVE_TO_X | MOVE_TO_Y);
 
+  current_buffer = old_current_buffer;
+
+  *dx = x0 + it.first_visible_x - it.current_x;
+  *dy = *y - it.current_y;
+
+  string =  w->buffer;
+  if (STRINGP (it.string))
+    string = it.string;
+  *pos = it.current;
+
+#ifdef HAVE_WINDOW_SYSTEM
+  if (it.what == IT_IMAGE)
+    {
+      if ((img = IMAGE_FROM_ID (it.f, it.image_id)) != NULL
+         && !NILP (img->spec))
+       *object = img->spec;
+    }
+#endif
+
+  if (it.vpos < w->current_matrix->nrows
+      && (row = MATRIX_ROW (w->current_matrix, it.vpos),
+         row->enabled_p))
+    {
+      if (it.hpos < row->used[TEXT_AREA])
+       {
+         struct glyph *glyph = row->glyphs[TEXT_AREA] + it.hpos;
+#ifdef HAVE_WINDOW_SYSTEM
+         if (img)
+           {
+             *dy -= row->ascent - glyph->ascent;
+             *dx += glyph->slice.x;
+             *dy += glyph->slice.y;
+             /* Image slices positions are still relative to the entire image */
+             *width = img->width;
+             *height = img->height;
+           }
+         else
+#endif
+           {
+             *width = glyph->pixel_width;
+             *height = glyph->ascent + glyph->descent;
+           }
+       }
+      else
+       {
+         *width = 0;
+         *height = row->height;
+       }
+    }
+  else
+    {
+      *width = *height = 0;
+    }
+
   /* Add extra (default width) columns if clicked after EOL. */
   x1 = max(0, it.current_x + it.pixel_width - it.first_visible_x);
   if (x0 > x1)
     it.hpos += (x0 - x1) / WINDOW_FRAME_COLUMN_WIDTH (w);
 
-  current_buffer = old_current_buffer;
-
-  *object = STRINGP (it.string) ? it.string : w->buffer;
-  *pos = it.current;
   *x = it.hpos;
   *y = it.vpos;
+
+  return string;
 }
 
 
 /* Value is the string under window-relative coordinates X/Y in the
-   mode or header line of window W, or nil if none.  MODE_LINE_P non-zero
-   means look at the mode line.  *CHARPOS is set to the position in
-   the string returned.  */
+   mode line or header line (PART says which) of window W, or nil if none.
+   *CHARPOS is set to the position in the string returned.  */
 
 Lisp_Object
-mode_line_string (w, x, y, part, charpos)
+mode_line_string (w, part, x, y, charpos, object, dx, dy, width, height)
      struct window *w;
-     int *x, *y;
      enum window_part part;
+     int *x, *y;
      int *charpos;
+     Lisp_Object *object;
+     int *dx, *dy;
+     int *width, *height;
 {
   struct glyph_row *row;
   struct glyph *glyph, *end;
-  int x0;
+  int x0, y0;
   Lisp_Object string = Qnil;
 
   if (part == ON_MODE_LINE)
     row = MATRIX_MODE_LINE_ROW (w->current_matrix);
   else
     row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
-
+  y0 = *y - row->y;
   *y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix);
 
   if (row->mode_line_p && row->enabled_p)
@@ -5758,20 +5896,43 @@ mode_line_string (w, x, y, part, charpos)
          it's the one we were looking for.  */
       glyph = row->glyphs[TEXT_AREA];
       end = glyph + row->used[TEXT_AREA];
-      for (x0 = *x; glyph < end && x0 > glyph->pixel_width; ++glyph)
+      for (x0 = *x; glyph < end && x0 >= glyph->pixel_width; ++glyph)
        x0 -= glyph->pixel_width;
       *x = glyph - row->glyphs[TEXT_AREA];
       if (glyph < end)
        {
          string = glyph->object;
          *charpos = glyph->charpos;
+         *width = glyph->pixel_width;
+         *height = glyph->ascent + glyph->descent;
+#ifdef HAVE_WINDOW_SYSTEM
+         if (glyph->type == IMAGE_GLYPH)
+           {
+             struct image *img;
+             img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id);
+             if (img != NULL)
+               *object = img->spec;
+             y0 -= row->ascent - glyph->ascent;
+           }
+#endif
        }
       else
-       /* Add extra (default width) columns if clicked after EOL. */
-       *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w);
+       {
+         /* Add extra (default width) columns if clicked after EOL. */
+         *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w);
+         *width = 0;
+         *height = row->height;
+       }
     }
   else
-    *x = 0;
+    {
+      *x = 0;
+      x0 = 0;
+      *width = *height = 0;
+    }
+
+  *dx = x0;
+  *dy = y0;
 
   return string;
 }
@@ -5782,15 +5943,18 @@ mode_line_string (w, x, y, part, charpos)
    the string returned.  */
 
 Lisp_Object
-marginal_area_string (w, x, y, part, charpos)
+marginal_area_string (w, part, x, y, charpos, object, dx, dy, width, height)
      struct window *w;
-     int *x, *y;
      enum window_part part;
+     int *x, *y;
      int *charpos;
+     Lisp_Object *object;
+     int *dx, *dy;
+     int *width, *height;
 {
   struct glyph_row *row = w->current_matrix->rows;
   struct glyph *glyph, *end;
-  int x0, i, wy = *y;
+  int x0, y0, i, wy = *y;
   int area;
   Lisp_Object string = Qnil;
 
@@ -5804,6 +5968,7 @@ marginal_area_string (w, x, y, part, charpos)
   for (i = 0; row->enabled_p && i < w->current_matrix->nrows; ++i, ++row)
     if (wy >= row->y && wy < MATRIX_ROW_BOTTOM_Y (row))
       break;
+  y0 = *y - row->y;
   *y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix);
 
   if (row->enabled_p)
@@ -5812,31 +5977,56 @@ marginal_area_string (w, x, y, part, charpos)
         it's the one we were looking for.  */
       if (area == RIGHT_MARGIN_AREA)
        x0 = ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-              ? WINDOW_LEFT_FRINGE_WIDTH (w) 
+              ? WINDOW_LEFT_FRINGE_WIDTH (w)
               : WINDOW_TOTAL_FRINGE_WIDTH (w))
              + window_box_width (w, LEFT_MARGIN_AREA)
              + window_box_width (w, TEXT_AREA));
       else
        x0 = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-             ? WINDOW_LEFT_FRINGE_WIDTH (w) 
+             ? WINDOW_LEFT_FRINGE_WIDTH (w)
              : 0);
 
       glyph = row->glyphs[area];
       end = glyph + row->used[area];
-      for (x0 = *x - x0; glyph < end && x0 > glyph->pixel_width; ++glyph)
+      for (x0 = *x - x0; glyph < end && x0 >= glyph->pixel_width; ++glyph)
        x0 -= glyph->pixel_width;
       *x = glyph - row->glyphs[area];
       if (glyph < end)
        {
          string = glyph->object;
          *charpos = glyph->charpos;
+         *width = glyph->pixel_width;
+         *height = glyph->ascent + glyph->descent;
+#ifdef HAVE_WINDOW_SYSTEM
+         if (glyph->type == IMAGE_GLYPH)
+           {
+             struct image *img;
+             img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id);
+             if (img != NULL)
+               *object = img->spec;
+             y0 -= row->ascent - glyph->ascent;
+             x0 += glyph->slice.x;
+             y0 += glyph->slice.y;
+           }
+#endif
        }
       else
-       /* Add extra (default width) columns if clicked after EOL. */
-       *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w);
+       {
+         /* Add extra (default width) columns if clicked after EOL. */
+         *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w);
+         *width = 0;
+         *height = row->height;
+       }
     }
   else
-    *x = 0;
+    {
+      x0 = 0;
+      *x = 0;
+      *width = *height = 0;
+    }
+
+  *dx = x0;
+  *dy = y0;
 
   return string;
 }
@@ -5858,6 +6048,9 @@ window_change_signal (signalnum) /* If we don't have an argument, */
 #endif
   int old_errno = errno;
 
+  signal (SIGWINCH, window_change_signal);
+  SIGNAL_THREAD_CHECK (signalnum);
+
   get_frame_size (&width, &height);
 
   /* The frame size change obviously applies to a termcap-controlled
@@ -5880,7 +6073,6 @@ window_change_signal (signalnum) /* If we don't have an argument, */
       }
   }
 
-  signal (SIGWINCH, window_change_signal);
   errno = old_errno;
 }
 #endif /* SIGWINCH */
@@ -6177,7 +6369,7 @@ Emacs was built without floating point support.
 
 #ifndef EMACS_HAS_USECS
   if (sec == 0 && usec != 0)
-    error ("millisecond `sleep-for' not supported on %s", SYSTEM_TYPE);
+    error ("Millisecond `sleep-for' not supported on %s", SYSTEM_TYPE);
 #endif
 
   /* Assure that 0 <= usec < 1000000.  */
@@ -6195,52 +6387,13 @@ Emacs was built without floating point support.
   if (sec < 0 || (sec == 0 && usec == 0))
     return Qnil;
 
-  {
-    Lisp_Object zero;
-
-    XSETFASTINT (zero, 0);
-    wait_reading_process_input (sec, usec, zero, 0);
-  }
-
-  /* We should always have wait_reading_process_input; we have a dummy
-     implementation for systems which don't support subprocesses.  */
-#if 0
-  /* No wait_reading_process_input */
-  immediate_quit = 1;
-  QUIT;
-
-#ifdef VMS
-  sys_sleep (sec);
-#else /* not VMS */
-/* The reason this is done this way
-    (rather than defined (H_S) && defined (H_T))
-   is because the VMS preprocessor doesn't grok `defined'.  */
-#ifdef HAVE_SELECT
-  EMACS_GET_TIME (end_time);
-  EMACS_SET_SECS_USECS (timeout, sec, usec);
-  EMACS_ADD_TIME (end_time, end_time, timeout);
-
-  while (1)
-    {
-      EMACS_GET_TIME (timeout);
-      EMACS_SUB_TIME (timeout, end_time, timeout);
-      if (EMACS_TIME_NEG_P (timeout)
-         || !select (1, 0, 0, 0, &timeout))
-       break;
-    }
-#else /* not HAVE_SELECT */
-  sleep (sec);
-#endif /* HAVE_SELECT */
-#endif /* not VMS */
-
-  immediate_quit = 0;
-#endif /* no subprocesses */
+  wait_reading_process_output (sec, usec, 0, 0, Qnil, NULL, 0);
 
   return Qnil;
 }
 
 
-/* This is just like wait_reading_process_input, except that
+/* This is just like wait_reading_process_output, except that
    it does the redisplay.
 
    It's also much like Fsit_for, except that it can be used for
@@ -6250,11 +6403,9 @@ Lisp_Object
 sit_for (sec, usec, reading, display, initial_display)
      int sec, usec, reading, display, initial_display;
 {
-  Lisp_Object read_kbd;
-
   swallow_events (display);
 
-  if (detect_input_pending_run_timers (display) || !NILP (Vexecuting_macro))
+  if (detect_input_pending_run_timers (display) || !NILP (Vexecuting_kbd_macro))
     return Qnil;
 
   if (initial_display)
@@ -6267,8 +6418,8 @@ sit_for (sec, usec, reading, display, initial_display)
   gobble_input (0);
 #endif
 
-  XSETINT (read_kbd, reading ? -1 : 1);
-  wait_reading_process_input (sec, usec, read_kbd, display);
+  wait_reading_process_output (sec, usec, reading ? -1 : 1, display,
+                              Qnil, NULL, 0);
 
   return detect_input_pending () ? Qnil : Qt;
 }
@@ -6318,7 +6469,7 @@ usage: (sit-for SECONDS &optional NODISP OLD-NODISP) */)
 
 #ifndef EMACS_HAS_USECS
   if (usec != 0 && sec == 0)
-    error ("millisecond `sit-for' not supported on %s", SYSTEM_TYPE);
+    error ("Millisecond `sit-for' not supported on %s", SYSTEM_TYPE);
 #endif
 
   return sit_for (sec, usec, 0, NILP (nodisp), NILP (nodisp));
@@ -6332,68 +6483,106 @@ usage: (sit-for SECONDS &optional NODISP OLD-NODISP) */)
 
 /* A vector of size >= 2 * NFRAMES + 3 * NBUFFERS + 1, containing the
    session's frames, frame names, buffers, buffer-read-only flags, and
-   buffer-modified-flags, and a trailing sentinel (so we don't need to
-   add length checks).  */
+   buffer-modified-flags.  */
 
 static Lisp_Object frame_and_buffer_state;
 
 
 DEFUN ("frame-or-buffer-changed-p", Fframe_or_buffer_changed_p,
-       Sframe_or_buffer_changed_p, 0, 0, 0,
+       Sframe_or_buffer_changed_p, 0, 1, 0,
        doc: /* Return non-nil if the frame and buffer state appears to have changed.
-The state variable is an internal vector containing all frames and buffers,
+VARIABLE is a variable name whose value is either nil or a state vector
+that will be updated to contain all frames and buffers,
 aside from buffers whose names start with space,
-along with the buffers' read-only and modified flags, which allows a fast
-check to see whether the menu bars might need to be recomputed.
+along with the buffers' read-only and modified flags.  This allows a fast
+check to see whether buffer menus might need to be recomputed.
 If this function returns non-nil, it updates the internal vector to reflect
-the current state.  */)
-     ()
+the current state.
+
+If VARIABLE is nil, an internal variable is used.  Users should not
+pass nil for VARIABLE.  */)
+     (variable)
+     Lisp_Object variable;
 {
-  Lisp_Object tail, frame, buf;
-  Lisp_Object *vecp;
+  Lisp_Object state, tail, frame, buf;
+  Lisp_Object *vecp, *end;
   int n;
 
-  vecp = XVECTOR (frame_and_buffer_state)->contents;
+  if (! NILP (variable))
+    {
+      CHECK_SYMBOL (variable);
+      state = Fsymbol_value (variable);
+      if (! VECTORP (state))
+       goto changed;
+    }
+  else
+    state = frame_and_buffer_state;
+
+  vecp = XVECTOR (state)->contents;
+  end = vecp + XVECTOR (state)->size;
+
   FOR_EACH_FRAME (tail, frame)
     {
+      if (vecp == end)
+       goto changed;
       if (!EQ (*vecp++, frame))
        goto changed;
+      if (vecp == end)
+       goto changed;
       if (!EQ (*vecp++, XFRAME (frame)->name))
        goto changed;
     }
-  /* Check that the buffer info matches.
-     No need to test for the end of the vector
-     because the last element of the vector is lambda
-     and that will always cause a mismatch.  */
+  /* Check that the buffer info matches.  */
   for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
     {
       buf = XCDR (XCAR (tail));
       /* Ignore buffers that aren't included in buffer lists.  */
       if (SREF (XBUFFER (buf)->name, 0) == ' ')
        continue;
+      if (vecp == end)
+       goto changed;
       if (!EQ (*vecp++, buf))
        goto changed;
+      if (vecp == end)
+       goto changed;
       if (!EQ (*vecp++, XBUFFER (buf)->read_only))
        goto changed;
+      if (vecp == end)
+       goto changed;
       if (!EQ (*vecp++, Fbuffer_modified_p (buf)))
        goto changed;
     }
+  if (vecp == end)
+    goto changed;
   /* Detect deletion of a buffer at the end of the list.  */
   if (EQ (*vecp, Qlambda))
     return Qnil;
+
+  /* Come here if we decide the data has changed.  */
  changed:
-  /* Start with 1 so there is room for at least one lambda at the end.  */
+  /* Count the size we will need.
+     Start with 1 so there is room for at least one lambda at the end.  */
   n = 1;
   FOR_EACH_FRAME (tail, frame)
     n += 2;
   for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
     n += 3;
-  /* Reallocate the vector if it's grown, or if it's shrunk a lot.  */
-  if (n > XVECTOR (frame_and_buffer_state)->size
-      || n + 20 < XVECTOR (frame_and_buffer_state)->size / 2)
+  /* Reallocate the vector if data has grown to need it,
+     or if it has shrunk a lot.  */
+  if (! VECTORP (state)
+      || n > XVECTOR (state)->size
+      || n + 20 < XVECTOR (state)->size / 2)
     /* Add 20 extra so we grow it less often.  */
-    frame_and_buffer_state = Fmake_vector (make_number (n + 20), Qlambda);
-  vecp = XVECTOR (frame_and_buffer_state)->contents;
+    {
+      state = Fmake_vector (make_number (n + 20), Qlambda);
+      if (! NILP (variable))
+       Fset (variable, state);
+      else
+       frame_and_buffer_state = state;
+    }
+
+  /* Record the new data in the (possibly reallocated) vector.  */
+  vecp = XVECTOR (state)->contents;
   FOR_EACH_FRAME (tail, frame)
     {
       *vecp++ = frame;
@@ -6411,12 +6600,12 @@ the current state.  */)
     }
   /* Fill up the vector with lambdas (always at least one).  */
   *vecp++ = Qlambda;
-  while  (vecp - XVECTOR (frame_and_buffer_state)->contents
-         < XVECTOR (frame_and_buffer_state)->size)
+  while (vecp - XVECTOR (state)->contents
+        < XVECTOR (state)->size)
     *vecp++ = Qlambda;
   /* Make sure we didn't overflow the vector.  */
-  if (vecp - XVECTOR (frame_and_buffer_state)->contents
-      > XVECTOR (frame_and_buffer_state)->size)
+  if (vecp - XVECTOR (state)->contents
+      > XVECTOR (state)->size)
     abort ();
   return Qt;
 }
@@ -6463,7 +6652,7 @@ init_display ()
      try to use X, and die with an error message if that doesn't work.  */
 
 #ifdef HAVE_X_WINDOWS
-  if (! display_arg)
+  if (! inhibit_window_system && ! display_arg)
     {
       char *display;
 #ifdef VMS
@@ -6473,6 +6662,13 @@ init_display ()
 #endif
 
       display_arg = (display != 0 && *display != 0);
+
+      if (display_arg && !x_display_ok (display))
+       {
+         fprintf (stderr, "Display %s unavailable, simulating -nw\n",
+                  display);
+         inhibit_window_system = 1;
+       }
     }
 
   if (!inhibit_window_system && display_arg