Even more compile stuff.
[bpt/emacs.git] / src / xdisp.c
index a00b529..18ae7e8 100644 (file)
@@ -94,6 +94,8 @@ Lisp_Object Voverlay_arrow_string;
 /* Values of those variables at last redisplay.  */
 static Lisp_Object last_arrow_position, last_arrow_string;
 
+Lisp_Object Qmenu_bar_update_hook;
+
 /* Nonzero if overlay arrow has been displayed once in this window.  */
 static int overlay_arrow_seen;
 
@@ -237,6 +239,8 @@ message2 (m, len)
       echo_area_display ();
       update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
       do_pending_window_change ();
+      if (frame_up_to_date_hook != 0 && ! gc_in_progress)
+       (*frame_up_to_date_hook) (XFRAME (XWINDOW (minibuf_window)->frame));
     }
 }
 
@@ -448,25 +452,8 @@ prepare_menu_bars ()
       frame_garbaged = 0;
     }
 
-  if (clip_changed || windows_or_buffers_changed)
-    update_mode_lines++;
-
-  /* Detect case that we need to write a star in the mode line.  */
-  if (XFASTINT (w->last_modified) < MODIFF
-      && XFASTINT (w->last_modified) <= current_buffer->save_modified)
-    {
-      w->update_mode_line = Qt;
-      if (buffer_shared > 1)
-       update_mode_lines++;
-    }
-
-  all_windows = update_mode_lines || buffer_shared > 1;
-
-  /* If specs for an arrow have changed, do thorough redisplay
-     to ensure we remove any arrow that should no longer exist.  */
-  if (! EQ (Voverlay_arrow_position, last_arrow_position)
-      || ! EQ (Voverlay_arrow_string, last_arrow_string))
-    all_windows = 1, clip_changed = 1;
+  all_windows = (update_mode_lines || buffer_shared > 1
+                || clip_changed || windows_or_buffers_changed);
 
   /* Update the menu bar item lists, if appropriate.
      This has to be done before any actual redisplay
@@ -476,15 +463,10 @@ prepare_menu_bars ()
       Lisp_Object tail, frame;
 
       FOR_EACH_FRAME (tail, frame)
-       {
-         FRAME_PTR f = XFRAME (frame);
-
-         if (FRAME_VISIBLE_P (f))
-           update_menu_bars (FRAME_ROOT_WINDOW (f));
-       }
+       update_menu_bar (XFRAME (frame));
     }
-  else if (FRAME_VISIBLE_P (selected_frame))
-    update_menu_bar (selected_window);
+  else
+    update_menu_bar (selected_frame);
 }
 \f
 /* Do a frame update, taking possible shortcuts into account.
@@ -591,8 +573,8 @@ redisplay ()
       && current_buffer == XBUFFER (w->buffer)
       && NILP (w->force_start)
       /* Point must be on the line that we have info recorded about */
-      && point >= tlbufpos
-      && point <= Z - tlendpos
+      && PT >= tlbufpos
+      && PT <= Z - tlendpos
       /* All text outside that line, including its final newline,
         must be unchanged */
       && (XFASTINT (w->last_modified) >= MODIFF
@@ -656,7 +638,7 @@ redisplay ()
          else
            goto cancel;
        }
-      else if (point == XFASTINT (w->last_point))
+      else if (PT == XFASTINT (w->last_point))
        {
          if (!must_finish)
            {
@@ -672,10 +654,10 @@ redisplay ()
        {
          pos = *compute_motion (tlbufpos, 0,
                                 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
-                                point, 2, - (1 << (SHORTBITS - 1)),
+                                PT, 2, - (1 << (SHORTBITS - 1)),
                                 window_internal_width (w) - 1,
                                 XINT (w->hscroll),
-                                pos_tab_offset (w, tlbufpos));
+                                pos_tab_offset (w, tlbufpos), w);
          if (pos.vpos < 1)
            {
              FRAME_CURSOR_X (selected_frame)
@@ -834,7 +816,7 @@ update:
        {
          w->update_mode_line = Qnil;
          XFASTINT (w->last_modified) = BUF_MODIFF (b);
-         w->window_end_valid = Qt;
+         w->window_end_valid = w->buffer;
          last_arrow_position = Voverlay_arrow_position;
          last_arrow_string = Voverlay_arrow_string;
          if (do_verify_charstarts)
@@ -908,7 +890,7 @@ mark_window_display_accurate (window, flag)
                               : Qnil);
        }
 
-      w->window_end_valid = Qt;
+      w->window_end_valid = w->buffer;
       w->update_mode_line = Qnil;
 
       if (!NILP (w->vchild))
@@ -930,55 +912,30 @@ mark_window_display_accurate (window, flag)
     }
 }
 \f
-/* Update the menu bar item lists for WINDOW
-   and its subwindows and siblings.
+/* Update the menu bar item list for frame F.
    This has to be done before we start to fill in any display lines,
    because it can call eval.  */
 
 static void
-update_menu_bars (window)
-     Lisp_Object window;
-{
-  for (; !NILP (window); window = XWINDOW (window)->next)
-    update_menu_bar (window);
-}
-
-/* Update the menu bar item list for window WINDOW and its subwindows.  */
-
-static void
-update_menu_bar (window)
-     Lisp_Object window;
+update_menu_bar (f)
+     FRAME_PTR f;
 {
-  register struct window *w = XWINDOW (window);
   struct buffer *old = current_buffer;
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
-
-  /* If this is a combination window, do its children; that's all.  */
-
-  if (!NILP (w->vchild))
-    {
-      update_menu_bars (w->vchild);
-      return;
-    }
-  if (!NILP (w->hchild))
-    {
-      update_menu_bars (w->hchild);
-      return;
-    }
-  if (NILP (w->buffer))
-    abort ();
+  Lisp_Object window;
+  register struct window *w;
+  window = FRAME_SELECTED_WINDOW (f);
+  w = XWINDOW (window);
   
   if (update_mode_lines)
     w->update_mode_line = Qt;
 
-  /* When we reach a frame's selected window, redo the frame's menu bar.  */
-  if (!NILP (w->update_mode_line)
+  if (
 #ifdef USE_X_TOOLKIT
-      && FRAME_EXTERNAL_MENU_BAR (f) 
+      FRAME_EXTERNAL_MENU_BAR (f) 
 #else
-      && FRAME_MENU_BAR_LINES (f) > 0
+      FRAME_MENU_BAR_LINES (f) > 0
 #endif
-      && EQ (FRAME_SELECTED_WINDOW (f), window))
+      )
     {
       /* If the user has switched buffers or windows, we need to
         recompute to reflect the new bindings.  But we'll
@@ -988,12 +945,13 @@ update_menu_bar (window)
         the rest of the redisplay algorithm is about the same as
         windows_or_buffers_changed anyway.  */
       if (windows_or_buffers_changed
-         || update_mode_lines
+         || !NILP (w->update_mode_line)
          || (XFASTINT (w->last_modified) < MODIFF
              && (XFASTINT (w->last_modified)
                  <= XBUFFER (w->buffer)->save_modified)))
        {
          struct buffer *prev = current_buffer;
+         call1 (Vrun_hooks, Qmenu_bar_update_hook);
          current_buffer = XBUFFER (w->buffer);
          FRAME_MENU_BAR_ITEMS (f) = menu_bar_items (FRAME_MENU_BAR_ITEMS (f));
          current_buffer = prev;
@@ -1026,13 +984,13 @@ redisplay_window (window, just_this_one)
   register struct window *w = XWINDOW (window);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
   int height;
-  register int lpoint = point;
+  register int lpoint = PT;
   struct buffer *old = current_buffer;
   register int width = window_internal_width (w) - 1;
   register int startp;
   register int hscroll = XINT (w->hscroll);
   struct position pos;
-  int opoint = point;
+  int opoint = PT;
   int tem;
   int window_needs_modeline;
 
@@ -1086,7 +1044,7 @@ redisplay_window (window, just_this_one)
   /* Otherwise set up data on this window; select its buffer and point value */
 
   current_buffer = XBUFFER (w->buffer);
-  opoint = point;
+  opoint = PT;
 
   /* Count number of windows showing the selected buffer.  */
 
@@ -1100,15 +1058,15 @@ redisplay_window (window, just_this_one)
   if (!EQ (window, selected_window))
     {
       SET_PT (marker_position (w->pointm));
-      if (point < BEGV)
+      if (PT < BEGV)
        {
          SET_PT (BEGV);
-         Fset_marker (w->pointm, make_number (point), Qnil);
+         Fset_marker (w->pointm, make_number (PT), Qnil);
        }
-      else if (point > (ZV - 1))
+      else if (PT > (ZV - 1))
        {
          SET_PT (ZV);
-         Fset_marker (w->pointm, make_number (point), Qnil);
+         Fset_marker (w->pointm, make_number (PT), Qnil);
        }
     }
 
@@ -1141,14 +1099,14 @@ redisplay_window (window, just_this_one)
                                (hscroll ? 1 - hscroll : 0),
                                ZV, height / 2,
                                - (1 << (SHORTBITS - 1)),
-                               width, hscroll, pos_tab_offset (w, startp));
+                               width, hscroll, pos_tab_offset (w, startp), w);
          SET_PT (pos.bufpos);
          if (w != XWINDOW (selected_window))
-           Fset_marker (w->pointm, make_number (point), Qnil);
+           Fset_marker (w->pointm, make_number (PT), Qnil);
          else
            {
              if (current_buffer == old)
-               lpoint = point;
+               lpoint = PT;
              FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
@@ -1167,7 +1125,7 @@ redisplay_window (window, just_this_one)
      in redisplay handles the same cases.  */
 
   if (XFASTINT (w->last_modified) >= MODIFF
-      && point >= startp && !clip_changed
+      && PT >= startp && !clip_changed
       && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
       /* Can't use this case if highlighting a region.  */
       && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
@@ -1175,8 +1133,8 @@ redisplay_window (window, just_this_one)
       && !EQ (window, minibuf_window))
     {
       pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
-                           point, height + 1, 10000, width, hscroll,
-                           pos_tab_offset (w, startp));
+                           PT, height + 1, 10000, width, hscroll,
+                           pos_tab_offset (w, startp), w);
 
       if (pos.vpos < height)
        {
@@ -1208,7 +1166,7 @@ redisplay_window (window, just_this_one)
       goto recenter;
     }
   else if (just_this_one && !MINI_WINDOW_P (w)
-          && point >= startp
+          && PT >= startp
           && XFASTINT (w->last_modified)
           /* or else vmotion on first line won't work.  */
           && ! NILP (w->start_at_line_beg)
@@ -1258,7 +1216,7 @@ redisplay_window (window, just_this_one)
 
   if (scroll_step && !clip_changed)
     {
-      if (point > startp)
+      if (PT > startp)
        {
          pos = *vmotion (Z - XFASTINT (w->window_end_pos),
                          scroll_step, width, hscroll, window);
@@ -1266,10 +1224,10 @@ redisplay_window (window, just_this_one)
            goto scroll_fail;
        }
 
-      pos = *vmotion (startp, point < startp ? - scroll_step : scroll_step,
+      pos = *vmotion (startp, PT < startp ? - scroll_step : scroll_step,
                      width, hscroll, window);
 
-      if (point >= pos.bufpos)
+      if (PT >= pos.bufpos)
        {
          try_window (window, pos.bufpos);
          if (cursor_vpos >= 0)
@@ -1291,7 +1249,7 @@ recenter:
   /* Forget any previously recorded base line for line number display.  */
   w->base_line_number = Qnil;
 
-  pos = *vmotion (point, - (height / 2), width, hscroll, window);
+  pos = *vmotion (PT, - (height / 2), width, hscroll, window);
   try_window (window, pos.bufpos);
 
   startp = marker_position (w->start);
@@ -1465,10 +1423,10 @@ try_window_id (window)
   /* Find position before which nothing is changed.  */
   bp = *compute_motion (start, 0, lmargin,
                        min (ZV, beg_unchanged + BEG), height + 1, 0,
-                       width, hscroll, pos_tab_offset (w, start));
+                       width, hscroll, pos_tab_offset (w, start), w);
   if (bp.vpos >= height)
     {
-      if (point < bp.bufpos && !bp.contin)
+      if (PT < bp.bufpos && !bp.contin)
        {
          /* All changes are below the frame, and point is on the frame.
             We don't need to change the frame at all.
@@ -1476,7 +1434,7 @@ try_window_id (window)
             any change in buffer size.  */
          bp = *compute_motion (start, 0, lmargin,
                                Z, height, 0,
-                               width, hscroll, pos_tab_offset (w, start));
+                               width, hscroll, pos_tab_offset (w, start), w);
          XFASTINT (w->window_end_vpos) = height;
          XFASTINT (w->window_end_pos) = Z - bp.bufpos;
          return 1;
@@ -1524,7 +1482,7 @@ try_window_id (window)
   /* Compute the cursor position after that newline.  */
   ep = *compute_motion (pos, vpos, val.hpos, tem,
                        height, - (1 << (SHORTBITS - 1)),
-                       width, hscroll, pos_tab_offset (w, bp.bufpos));
+                       width, hscroll, pos_tab_offset (w, bp.bufpos), w);
 
   /* If changes reach past the text available on the frame,
      just display rest of frame.  */
@@ -1555,7 +1513,7 @@ try_window_id (window)
       epto = pos_tab_offset (w, ep.bufpos);
       xp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
                            Z - XFASTINT (w->window_end_pos),
-                           10000, 0, width, hscroll, epto);
+                           10000, 0, width, hscroll, epto, w);
       scroll_amount = xp.vpos - XFASTINT (w->window_end_vpos);
 
       /* Is everything on frame below the changes whitespace?
@@ -1572,21 +1530,22 @@ try_window_id (window)
       XFASTINT (w->window_end_vpos) += scroll_amount;
 
       /* Before doing any scrolling, verify that point will be on frame. */
-      if (point > ep.bufpos && !(point <= xp.bufpos && xp.bufpos < height))
+      if (PT > ep.bufpos && !(PT <= xp.bufpos && xp.bufpos < height))
        {
-         if (point <= xp.bufpos)
+         if (PT <= xp.bufpos)
            {
              pp = *compute_motion (ep.bufpos, ep.vpos, ep.hpos,
-                                   point, height, - (1 << (SHORTBITS - 1)),
-                                   width, hscroll, epto);
+                                   PT, height, - (1 << (SHORTBITS - 1)),
+                                   width, hscroll, epto, w);
            }
          else
            {
              pp = *compute_motion (xp.bufpos, xp.vpos, xp.hpos,
-                                   point, height, - (1 << (SHORTBITS - 1)),
-                                   width, hscroll, pos_tab_offset (w, xp.bufpos));
+                                   PT, height, - (1 << (SHORTBITS - 1)),
+                                   width, hscroll,
+                                   pos_tab_offset (w, xp.bufpos), w);
            }
-         if (pp.bufpos < point || pp.vpos == height)
+         if (pp.bufpos < PT || pp.vpos == height)
            return 0;
          cursor_vpos = pp.vpos + top;
          cursor_hpos = pp.hpos + XFASTINT (w->left);
@@ -1633,7 +1592,24 @@ try_window_id (window)
          tem = scroll_frame_lines (f, bp.vpos + top - scroll_amount,
                                    top + height - max (0, scroll_amount),
                                    scroll_amount, bp.bufpos);
-         if (!tem) stop_vpos = height;
+         if (!tem)
+           stop_vpos = height;
+         else
+           {
+             /* scroll_frame_lines did not properly adjust subsequent
+                lines' charstarts in the case where the text of the
+                screen line at bp.vpos has changed.
+                (This can happen in a deletion that ends in mid-line.)
+                To adjust properly, we need to make things constent at
+                the position ep.
+                So do a second adjust to make that happen.
+                Note that stop_vpos >= ep.vpos, so it is sufficient
+                to update the charstarts for lines at ep.vpos and below.  */
+             int oldstart
+               = FRAME_CURRENT_GLYPHS (f)->charstarts[ep.vpos + top][0];
+             adjust_window_charstarts (w, ep.vpos + top - 1,
+                                       ep.bufpos - oldstart);
+           }
        }
       else if (scroll_amount)
        {
@@ -1737,7 +1713,7 @@ try_window_id (window)
       /* Here is a case where display_text_line sets cursor_vpos wrong.
         Make it be fixed up, below.  */
       if (xp.bufpos == ZV
-         && xp.bufpos == point)
+         && xp.bufpos == PT)
        cursor_vpos = -1;
     }
 
@@ -1766,8 +1742,8 @@ try_window_id (window)
   /* If point was not in a line that was displayed, find it */
   if (cursor_vpos < 0)
     {
-      val = *compute_motion (start, 0, lmargin, point, 10000, 10000,
-                            width, hscroll, pos_tab_offset (w, start));
+      val = *compute_motion (start, 0, lmargin, PT, 10000, 10000,
+                            width, hscroll, pos_tab_offset (w, start), w);
       /* Admit failure if point is off frame now */
       if (val.vpos >= height)
        {
@@ -1786,7 +1762,7 @@ try_window_id (window)
     {
       val = *compute_motion (start, 0, lmargin, ZV,
                             height, - (1 << (SHORTBITS - 1)),
-                            width, hscroll, pos_tab_offset (w, start));
+                            width, hscroll, pos_tab_offset (w, start), w);
       if (val.vpos != XFASTINT (w->window_end_vpos))
        abort ();
       if (XFASTINT (w->window_end_pos)
@@ -1883,7 +1859,7 @@ copy_part_of_rope (f, to, s, from, len, face)
   if (! FRAME_TERMCAP_P (f))
     while (n--)
       {
-       int glyph = XFASTINT (*fp);
+       int glyph = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
        int facecode;
 
        if (FAST_GLYPH_FACE (glyph) == 0)
@@ -1908,7 +1884,7 @@ copy_part_of_rope (f, to, s, from, len, face)
 #endif
     while (n--)
       {
-       if (to >= s) *to = XFASTINT (*fp);
+       if (to >= s) *to = (INTEGERP (*fp) ? XFASTINT (*fp) : 0);
        ++to;
        ++fp;
       }
@@ -1919,16 +1895,18 @@ copy_part_of_rope (f, to, s, from, len, face)
    with a displayable computed face code.  */
 
 static GLYPH
-fix_glyph (f, glyph, current_face)
+fix_glyph (f, glyph, cface)
      FRAME_PTR f;
      GLYPH glyph;
-     int current_face;
+     int cface;
 {
 #ifdef HAVE_X_WINDOWS
-  if (! FRAME_TERMCAP_P (f) && FAST_GLYPH_FACE (glyph) != 0)
-    return FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph),
-                           compute_glyph_face (f, FAST_GLYPH_FACE (glyph),
-                                               current_face));
+  if (! FRAME_TERMCAP_P (f))
+    {
+      if (FAST_GLYPH_FACE (glyph) != 0)
+       cface = compute_glyph_face (f, FAST_GLYPH_FACE (glyph), cface);
+      glyph = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), cface);
+    }
 #endif
   return glyph;
 }
@@ -1964,7 +1942,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
   register int pause;
   register unsigned char *p;
   GLYPH *endp;
-  register GLYPH *startp;
+  register GLYPH *leftmargin;
   register GLYPH *p1prev = 0;
   register GLYPH *p1start;
   int *charstart;
@@ -1976,10 +1954,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
   int lastpos;
   int invis;
   int hscroll = XINT (w->hscroll);
-  int truncate = hscroll
-    || (truncate_partial_width_windows
-       && XFASTINT (w->width) < FRAME_WIDTH (f))
-    || !NILP (current_buffer->truncate_lines);
+  int truncate = (hscroll
+                 || (truncate_partial_width_windows
+                     && XFASTINT (w->width) < FRAME_WIDTH (f))
+                 || !NILP (current_buffer->truncate_lines));
 
   /* 1 if we should highlight the region.  */
   int highlight_region
@@ -2056,10 +2034,16 @@ display_text_line (w, start, vpos, hpos, taboffset)
       && vpos == XFASTINT (w->top))
     {
       if (minibuf_prompt)
-       hpos = display_string (w, vpos, minibuf_prompt, -1, hpos,
+       {
+         minibuf_prompt_width
+           = (display_string (w, vpos, minibuf_prompt, -1, hpos,
                               (!truncate ? continuer : truncator),
-                              1, -1, -1);
-      minibuf_prompt_width = hpos;
+                              1, -1, -1)
+              - hpos);
+         hpos += minibuf_prompt_width;
+       }
+      else
+       minibuf_prompt_width = 0;
     }
 
   desired_glyphs->bufp[vpos] = pos;
@@ -2067,10 +2051,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
   p1start = p1;
   charstart = desired_glyphs->charstarts[vpos] + hpos;
   /* In case we don't ever write anything into it...  */
-  *charstart = -1;
+  desired_glyphs->charstarts[vpos][XFASTINT (w->left)] = -1;
   end = ZV;
-  startp = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
-  endp = startp + width;
+  leftmargin = desired_glyphs->glyphs[vpos] + XFASTINT (w->left);
+  endp = leftmargin + width;
 
   /* Arrange the overlays nicely for our purposes.  Usually, we call
      display_text_line on only one line at a time, in which case this
@@ -2092,7 +2076,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
     {
       /* Record which glyph starts a character,
         and the character position of that character.  */
-      charstart[p1 - p1start] = pos;
+      if (p1 >= leftmargin)
+       charstart[p1 - p1start] = pos;
 
       if (p1 >= endp)
        break;
@@ -2106,10 +2091,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
            break;
 
          /* Did we reach point?  Record the cursor location.  */
-         if (pos == point && cursor_vpos < 0)
+         if (pos == PT && cursor_vpos < 0)
            {
              cursor_vpos = vpos;
-             cursor_hpos = p1 - startp;
+             cursor_hpos = p1 - leftmargin;
            }
 
 #ifdef USE_TEXT_PROPERTIES
@@ -2134,10 +2119,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
                next_invisible = end;
              if (! NILP (prop))
                {
-                 if (pos < point && next_invisible >= point)
+                 if (pos < PT && next_invisible >= PT)
                    {
                      cursor_vpos = vpos;
-                     cursor_hpos = p1 - startp;
+                     cursor_hpos = p1 - leftmargin;
                    }
                  pos = next_invisible;
                }
@@ -2167,8 +2152,8 @@ display_text_line (w, start, vpos, hpos, taboffset)
 
          /* Wouldn't you hate to read the next line to someone over
              the phone?  */
-         if (pos < point && point < pause)
-           pause = point;
+         if (pos < PT && PT < pause)
+           pause = PT;
          if (pos < GPT && GPT < pause)
            pause = GPT;
 
@@ -2178,14 +2163,14 @@ display_text_line (w, start, vpos, hpos, taboffset)
       if (c >= 040 && c < 0177
          && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
        {
-         if (p1 >= startp)
+         if (p1 >= leftmargin)
            *p1 = MAKE_GLYPH (f, c, current_face);
          p1++;
        }
       else if (c == '\n')
        {
          invis = 0;
-         while (pos < end
+         while (pos + 1 < end
                 && selective > 0
                 && indented_beyond_p (pos + 1, selective))
            {
@@ -2194,10 +2179,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
              if (FETCH_CHAR (pos - 1) == '\n')
                pos--;
            }
-         if (invis && selective_rlen > 0 && p1 >= startp)
+         if (invis && selective_rlen > 0 && p1 >= leftmargin)
            {
              p1 += selective_rlen;
-             if (p1 - startp > width)
+             if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
@@ -2215,11 +2200,11 @@ display_text_line (w, start, vpos, hpos, taboffset)
        {
          do
            {
-             if (p1 >= startp && p1 < endp)
+             if (p1 >= leftmargin && p1 < endp)
                *p1 = MAKE_GLYPH (f, ' ', current_face);
              p1++;
            }
-         while ((p1 - startp + taboffset + hscroll - (hscroll > 0))
+         while ((p1 - leftmargin + taboffset + hscroll - (hscroll > 0))
                 % tab_width);
        }
       else if (c == Ctl ('M') && selective == -1)
@@ -2230,7 +2215,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
          if (selective_rlen > 0)
            {
              p1 += selective_rlen;
-             if (p1 - startp > width)
+             if (p1 - leftmargin > width)
                p1 = endp;
              copy_part_of_rope (f, p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
@@ -2246,53 +2231,65 @@ display_text_line (w, start, vpos, hpos, taboffset)
        }
       else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
        {
-         p1 = copy_part_of_rope (f, p1, startp,
+         p1 = copy_part_of_rope (f, p1, leftmargin,
                                  XVECTOR (DISP_CHAR_VECTOR (dp, c))->contents,
                                  XVECTOR (DISP_CHAR_VECTOR (dp, c))->size,
                                  current_face);
        }
       else if (c < 0200 && ctl_arrow)
        {
-         if (p1 >= startp)
+         if (p1 >= leftmargin)
            *p1 = fix_glyph (f, (dp && XTYPE (DISP_CTRL_GLYPH (dp)) == Lisp_Int
                                 ? XINT (DISP_CTRL_GLYPH (dp)) : '^'),
                             current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, c ^ 0100, current_face);
          p1++;
        }
       else
        {
-         if (p1 >= startp)
+         if (p1 >= leftmargin)
            *p1 = fix_glyph (f, (dp && XTYPE (DISP_ESCAPE_GLYPH (dp)) == Lisp_Int
                                 ? XINT (DISP_ESCAPE_GLYPH (dp)) : '\\'),
                             current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, (c >> 6) + '0', current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, (7 & (c >> 3)) + '0', current_face);
          p1++;
-         if (p1 >= startp && p1 < endp)
+         if (p1 >= leftmargin && p1 < endp)
            *p1 = MAKE_GLYPH (f, (7 & c) + '0', current_face);
          p1++;
        }
 
-      /* For all the glyphs occupied by this character, except for the
-        first, store -1 in charstarts.  */
-      if (p1 != p1prev)
+      /* Do nothing here for a char that's entirely off the left edge.  */
+      if (p1 >= leftmargin)
        {
-         int *p2x = &charstart[p1prev - p1start] + 1;
-         int *p2 = &charstart[p1 - p1start];
-         while (p2x != p2)
-           *p2x++ = -1;
+         /* For all the glyphs occupied by this character, except for the
+            first, store -1 in charstarts.  */
+         if (p1 != p1prev)
+           {
+             int *p2x = &charstart[p1prev - p1start];
+             int *p2 = &charstart[p1 - p1start];
+
+             /* The window's left column should always
+                contain a character position.
+                And don't clobber anything to the left of that.  */
+             if (p1prev < leftmargin)
+               {
+                 p2x = charstart + (leftmargin - p1start);
+                 *p2x = pos;
+               }
+
+             /* This loop skips over the char p2x initially points to.  */
+             while (++p2x < p2)
+               *p2x = -1;
+           }
        }
-      else
-       /* If this character took up no space,
-          erase all mention of it from charstart.  */
-       charstart[p1 - p1start] = 0;
+
       pos++;
     }
 
@@ -2310,7 +2307,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* Add 1 in the endtest to compensate for the fact that ENDP was
      made from WIDTH, which is 1 less than the window's actual
      internal width.  */
-  for (i = p1 - p1start + 1; i < endp - p1start + 1; i++)
+  i = p1 - p1start + 1;
+  if (p1 < leftmargin)
+    i += leftmargin - p1;
+  for (; i < endp - p1start + 1; i++)
     charstart[i] = 0;
 
   /* Handle continuation in middle of a character */
@@ -2377,10 +2377,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* If point is at eol or in invisible text at eol,
      record its frame location now.  */
 
-  if (start <= point && point <= lastpos && cursor_vpos < 0)
+  if (start <= PT && PT <= lastpos && cursor_vpos < 0)
     {
       cursor_vpos = vpos;
-      cursor_hpos = p1 - startp;
+      cursor_hpos = p1 - leftmargin;
     }
 
   if (cursor_vpos == vpos)
@@ -2416,15 +2416,15 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* If hscroll and line not empty, insert truncation-at-left marker */
   if (hscroll && lastpos != start)
     {
-      *startp = fix_glyph (f, truncator, 0);
-      if (p1 <= startp)
-       p1 = startp + 1;
+      *leftmargin = fix_glyph (f, truncator, 0);
+      if (p1 <= leftmargin)
+       p1 = leftmargin + 1;
     }
 
   if (XFASTINT (w->width) + XFASTINT (w->left) != FRAME_WIDTH (f))
     {
       endp++;
-      if (p1 < startp) p1 = startp;
+      if (p1 < leftmargin) p1 = leftmargin;
       while (p1 < endp) *p1++ = SPACEGLYPH;
 
       /* Don't draw vertical bars if we're using scroll bars.  They're
@@ -2455,10 +2455,10 @@ display_text_line (w, start, vpos, hpos, taboffset)
       if (len > width)
        len = width;
       for (i = 0; i < len; i++)
-       startp[i] = p[i];
+       leftmargin[i] = p[i];
 
       /* Bug in SunOS 4.1.1 compiler requires this intermediate variable.  */
-      arrow_end = (startp - desired_glyphs->glyphs[vpos]) + len;
+      arrow_end = (leftmargin - desired_glyphs->glyphs[vpos]) + len;
       if (desired_glyphs->used[vpos] < arrow_end)
        desired_glyphs->used[vpos] = arrow_end;
 
@@ -2950,10 +2950,7 @@ decode_mode_spec (w, c, maxwidth)
 
     case 't':                  /* indicate TEXT or BINARY */
 #ifdef MSDOS
-      decode_mode_spec_buf[0]
-       = NILP (current_buffer->buffer_file_type) ? "T" : "B";
-      decode_mode_spec_buf[1] = 0;
-      return decode_mode_spec_buf;
+      return NILP (current_buffer->buffer_file_type) ? "T" : "B";
 #else /* not MSDOS */
       return "T";
 #endif /* not MSDOS */
@@ -3178,7 +3175,7 @@ display_string (w, vpos, string, length, hpos, truncate,
     end = desired_glyphs->glyphs[vpos] + maxcol;
 
   /* Store 0 in charstart for these columns.  */
-  for (i = hpos; i < end - p1start + hpos; i++)
+  for (i = (hpos >= 0 ? hpos : 0); i < end - p1start + hpos; i++)
     desired_glyphs->charstarts[vpos][i] = 0;
 
   if (maxcol >= 0 && mincol > maxcol)
@@ -3276,6 +3273,9 @@ display_string (w, vpos, string, length, hpos, truncate,
 void
 syms_of_xdisp ()
 {
+  staticpro (&Qmenu_bar_update_hook);
+  Qmenu_bar_update_hook = intern ("menu-bar-update-hook");
+
   staticpro (&last_arrow_position);
   staticpro (&last_arrow_string);
   last_arrow_position = Qnil;