XEmacs 21.2.32 "Kastor & Polydeukes".
[chise/xemacs-chise.git.1] / src / redisplay.c
index 17de60e..6fe354b 100644 (file)
@@ -364,8 +364,7 @@ int frame_changed;
 int glyphs_changed;
 int glyphs_changed_set;
 
 int glyphs_changed;
 int glyphs_changed_set;
 
-/* non-zero if any displayed subwindow is in need of updating
-   somewhere. */
+/* non-zero if any subwindow has been deleted. */
 int subwindows_changed;
 int subwindows_changed_set;
 
 int subwindows_changed;
 int subwindows_changed_set;
 
@@ -419,9 +418,9 @@ int windows_structure_changed;
 Lisp_Object Vbar_cursor;
 Lisp_Object Qbar_cursor;
 
 Lisp_Object Vbar_cursor;
 Lisp_Object Qbar_cursor;
 
-int visible_bell;      /* If true and the terminal will support it
-                          then the frame will flash instead of
-                          beeping when an error occurs */
+Lisp_Object Vvisible_bell;     /* If true and the terminal will support it
+                                  then the frame will flash instead of
+                                  beeping when an error occurs */
 
 /* Nonzero means no need to redraw the entire frame on resuming
    a suspended Emacs.  This is useful on terminals with multiple pages,
 
 /* Nonzero means no need to redraw the entire frame on resuming
    a suspended Emacs.  This is useful on terminals with multiple pages,
@@ -471,6 +470,8 @@ Lisp_Object Vtext_cursor_visible_p;
 
 int column_number_start_at_one;
 
 
 int column_number_start_at_one;
 
+Lisp_Object Qtop_bottom;
+
 #define WINDOW_SCROLLED(w) \
 (w->hscroll > 0 || w->left_xoffset)
 
 #define WINDOW_SCROLLED(w) \
 (w->hscroll > 0 || w->left_xoffset)
 
@@ -859,7 +860,7 @@ add_emchar_rune (pos_data *data)
          Lisp_Object font_instance =
            ensure_face_cachel_contains_charset (cachel, data->window,
                                                 charset);
          Lisp_Object font_instance =
            ensure_face_cachel_contains_charset (cachel, data->window,
                                                 charset);
-         struct Lisp_Font_Instance *fi;
+         Lisp_Font_Instance *fi;
 
          if (EQ (font_instance, Vthe_null_font_instance))
            {
 
          if (EQ (font_instance, Vthe_null_font_instance))
            {
@@ -1341,7 +1342,7 @@ add_disp_table_entry_runes (pos_data *data, Lisp_Object entry)
   prop_block_dynarr *prop = NULL;
   if (VECTORP (entry))
     {
   prop_block_dynarr *prop = NULL;
   if (VECTORP (entry))
     {
-      struct Lisp_Vector *de = XVECTOR (entry);
+      Lisp_Vector *de = XVECTOR (entry);
       EMACS_INT len = vector_length (de);
       int elt;
 
       EMACS_INT len = vector_length (de);
       int elt;
 
@@ -1524,6 +1525,18 @@ add_glyph_rune (pos_data *data, struct glyph_block *gb, int pos_type,
 {
   struct window *w = XWINDOW (data->window);
 
 {
   struct window *w = XWINDOW (data->window);
 
+  /* If window faces changed, and glyph instance is text, then
+     glyph sizes might have changed too */
+  invalidate_glyph_geometry_maybe (gb->glyph, w);
+
+  /* This makes sure the glyph is in the cachels.
+
+     #### We do this to make sure the glyph is in the glyph cachels,
+     so that the dirty flag can be reset after redisplay has
+     finished. We should do this some other way, maybe by iterating
+     over the window cache of subwindows. */
+  get_glyph_cachel_index (w, gb->glyph);
+
   /* A nil extent indicates a special glyph (ex. truncator). */
   if (NILP (gb->extent)
       || (pos_type == BEGIN_GLYPHS &&
   /* A nil extent indicates a special glyph (ex. truncator). */
   if (NILP (gb->extent)
       || (pos_type == BEGIN_GLYPHS &&
@@ -3622,10 +3635,6 @@ generate_modeline (struct window *w, struct display_line *dl, int type)
       /* The modeline is at the bottom of the gutters. */
       dl->ypos = WINDOW_BOTTOM (w);
 
       /* The modeline is at the bottom of the gutters. */
       dl->ypos = WINDOW_BOTTOM (w);
 
-      /* adjust for the bottom gutter */
-      if (window_is_lowest (w))
-       dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f);
-
       rb.findex = MODELINE_INDEX;
       rb.xpos = dl->bounds.left_out;
       rb.width = dl->bounds.right_out - dl->bounds.left_out;
       rb.findex = MODELINE_INDEX;
       rb.xpos = dl->bounds.left_out;
       rb.width = dl->bounds.right_out - dl->bounds.left_out;
@@ -3679,18 +3688,15 @@ generate_modeline (struct window *w, struct display_line *dl, int type)
      set this until we've generated the modeline in order to account
      for any embedded faces. */
   dl->ypos = WINDOW_BOTTOM (w) - dl->descent - ypos_adj;
      set this until we've generated the modeline in order to account
      for any embedded faces. */
   dl->ypos = WINDOW_BOTTOM (w) - dl->descent - ypos_adj;
-  /* adjust for the bottom gutter */
-  if (window_is_lowest (w))
-    dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f);
 }
 
 static Charcount
 }
 
 static Charcount
-add_string_to_fstring_db_runes (pos_data *data, CONST Bufbyte *str,
+add_string_to_fstring_db_runes (pos_data *data, const Bufbyte *str,
                                 Charcount pos, Charcount min_pos, Charcount max_pos)
 {
   /* This function has been Mule-ized. */
   Charcount end;
                                 Charcount pos, Charcount min_pos, Charcount max_pos)
 {
   /* This function has been Mule-ized. */
   Charcount end;
-  CONST Bufbyte *cur_pos = str;
+  const Bufbyte *cur_pos = str;
   struct display_block *db = data->db;
 
   data->blank_width = space_width (XWINDOW (data->window));
   struct display_block *db = data->db;
 
   data->blank_width = space_width (XWINDOW (data->window));
@@ -3698,13 +3704,13 @@ add_string_to_fstring_db_runes (pos_data *data, CONST Bufbyte *str,
     add_blank_rune (data, NULL, 0);
 
   end = (Dynarr_length (db->runes) +
     add_blank_rune (data, NULL, 0);
 
   end = (Dynarr_length (db->runes) +
-         bytecount_to_charcount (str, strlen ((CONST char *) str)));
+         bytecount_to_charcount (str, strlen ((const char *) str)));
   if (max_pos != -1)
     end = min (max_pos, end);
 
   while (pos < end && *cur_pos)
     {
   if (max_pos != -1)
     end = min (max_pos, end);
 
   while (pos < end && *cur_pos)
     {
-      CONST Bufbyte *old_cur_pos = cur_pos;
+      const Bufbyte *old_cur_pos = cur_pos;
       int succeeded;
 
       data->ch = charptr_emchar (cur_pos);
       int succeeded;
 
       data->ch = charptr_emchar (cur_pos);
@@ -3816,7 +3822,7 @@ tail_recurse:
                {
                  Charcount tmp_max = (max_pos == -1 ? pos + size - *offset :
                                       min (pos + size - *offset, max_pos));
                {
                  Charcount tmp_max = (max_pos == -1 ? pos + size - *offset :
                                       min (pos + size - *offset, max_pos));
-                 CONST Bufbyte *tmp_last = charptr_n_addr (last, *offset);
+                 const Bufbyte *tmp_last = charptr_n_addr (last, *offset);
 
                  pos = add_string_to_fstring_db_runes (data, tmp_last,
                                                        pos, pos, tmp_max);
 
                  pos = add_string_to_fstring_db_runes (data, tmp_last,
                                                        pos, pos, tmp_max);
@@ -3873,7 +3879,7 @@ tail_recurse:
 
                   while (num_to_add--)
                     pos = add_string_to_fstring_db_runes
 
                   while (num_to_add--)
                     pos = add_string_to_fstring_db_runes
-                      (data, (CONST Bufbyte *) "-", pos, pos, max_pos);
+                      (data, (const Bufbyte *) "-", pos, pos, max_pos);
                 }
               else if (*this != 0)
                 {
                 }
               else if (*this != 0)
                 {
@@ -3892,9 +3898,9 @@ tail_recurse:
                    *offset -= size;
                  else
                    {
                    *offset -= size;
                  else
                    {
-                     CONST Bufbyte *tmp_str = charptr_n_addr (str, *offset);
+                     const Bufbyte *tmp_str = charptr_n_addr (str, *offset);
 
 
-                     /* ### NOTE: I don't understand why a tmp_max is not
+                     /* #### NOTE: I don't understand why a tmp_max is not
                         computed and used here as in the plain string case
                         above. -- dv */
                      pos = add_string_to_fstring_db_runes (data, tmp_str,
                         computed and used here as in the plain string case
                         above. -- dv */
                      pos = add_string_to_fstring_db_runes (data, tmp_str,
@@ -3938,9 +3944,9 @@ tail_recurse:
                *offset -= size;
              else
                {
                *offset -= size;
              else
                {
-                 CONST Bufbyte *tmp_str = charptr_n_addr (str, *offset);
+                 const Bufbyte *tmp_str = charptr_n_addr (str, *offset);
 
 
-                 /* ### NOTE: I don't understand why a tmp_max is not
+                 /* #### NOTE: I don't understand why a tmp_max is not
                     computed and used here as in the plain string case
                     above. -- dv */
                  pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
                     computed and used here as in the plain string case
                     above. -- dv */
                  pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
@@ -4132,10 +4138,10 @@ tail_recurse:
          *offset -= size;
        else
          {
          *offset -= size;
        else
          {
-           CONST Bufbyte *tmp_str =
-             charptr_n_addr ((CONST Bufbyte *) str, *offset);
+           const Bufbyte *tmp_str =
+             charptr_n_addr ((const Bufbyte *) str, *offset);
 
 
-           /* ### NOTE: I don't understand why a tmp_max is not computed and
+           /* #### NOTE: I don't understand why a tmp_max is not computed and
               used here as in the plain string case above. -- dv */
            pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
                                                  min_pos, max_pos);
               used here as in the plain string case above. -- dv */
            pos = add_string_to_fstring_db_runes (data, tmp_str, pos,
                                                  min_pos, max_pos);
@@ -4146,7 +4152,7 @@ tail_recurse:
 
   if (min_pos > pos)
     {
 
   if (min_pos > pos)
     {
-      add_string_to_fstring_db_runes (data, (CONST Bufbyte *) "", pos,
+      add_string_to_fstring_db_runes (data, (const Bufbyte *) "", pos,
                                      min_pos, -1);
     }
 
                                      min_pos, -1);
     }
 
@@ -4281,7 +4287,7 @@ create_string_text_block (struct window *w, Lisp_Object disp_string,
      against this case. */
   struct buffer *b = BUFFERP (w->buffer) ? XBUFFER (w->buffer) : 0;
   struct device *d = XDEVICE (f->device);
      against this case. */
   struct buffer *b = BUFFERP (w->buffer) ? XBUFFER (w->buffer) : 0;
   struct device *d = XDEVICE (f->device);
-  struct Lisp_String* s = XSTRING (disp_string);
+  Lisp_String* s = XSTRING (disp_string);
 
   /* we're working with these a lot so precalculate them */
   Bytecount slen = XSTRING_LENGTH (disp_string);
 
   /* we're working with these a lot so precalculate them */
   Bytecount slen = XSTRING_LENGTH (disp_string);
@@ -4762,7 +4768,7 @@ done:
 
          if (truncate_win && data.bi_bufpos == bi_string_zv)
            {
 
          if (truncate_win && data.bi_bufpos == bi_string_zv)
            {
-             CONST Bufbyte* endb = charptr_n_addr (string_data (s), bi_string_zv);
+             const Bufbyte* endb = charptr_n_addr (string_data (s), bi_string_zv);
              DEC_CHARPTR (endb);
              if (charptr_emchar (endb) != '\n')
                {
              DEC_CHARPTR (endb);
              if (charptr_emchar (endb) != '\n')
                {
@@ -5147,6 +5153,9 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
   else
     prop = 0;
 
   else
     prop = 0;
 
+  /* Make sure this is set always */
+  /* Note the conversion at end */
+  w->window_end_pos[type] = start_pos;
   while (ypos < yend)
     {
       struct display_line dl;
   while (ypos < yend)
     {
       struct display_line dl;
@@ -5250,10 +5259,14 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
     Dynarr_free (prop);
 
   /* #### More not quite right, but close enough. */
     Dynarr_free (prop);
 
   /* #### More not quite right, but close enough. */
-  /* #### Ben sez: apparently window_end_pos[] is measured
+  /* Ben sez: apparently window_end_pos[] is measured
      as the number of characters between the window end and the
      end of the buffer?  This seems rather weirdo.  What's
      as the number of characters between the window end and the
      end of the buffer?  This seems rather weirdo.  What's
-     the justification for this? */
+     the justification for this?
+
+     JV sez: Because BUF_Z (b) would be a good initial value, however
+     that can change. This representation allows initalizing with 0.
+  */
   w->window_end_pos[type] = BUF_Z (b) - w->window_end_pos[type];
 
   if (need_modeline)
   w->window_end_pos[type] = BUF_Z (b) - w->window_end_pos[type];
 
   if (need_modeline)
@@ -5931,7 +5944,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
      the cache purely because glyphs have changed - this is now
      handled by the dirty flag.*/
   if ((!echo_active && b != window_display_buffer (w))
      the cache purely because glyphs have changed - this is now
      handled by the dirty flag.*/
   if ((!echo_active && b != window_display_buffer (w))
-      || !Dynarr_length (w->glyph_cachels))
+      || !Dynarr_length (w->glyph_cachels) || f->faces_changed)
     reset_glyph_cachels (w);
   else
     mark_glyph_cachels_as_not_updated (w);
     reset_glyph_cachels (w);
   else
     mark_glyph_cachels_as_not_updated (w);
@@ -6017,7 +6030,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
          && !f->faces_changed
          && !f->glyphs_changed
          && !f->subwindows_changed
          && !f->faces_changed
          && !f->glyphs_changed
          && !f->subwindows_changed
-         && !f->subwindows_state_changed
+         /*      && !f->subwindows_state_changed*/
          && !f->point_changed
          && !f->windows_structure_changed)
        {
          && !f->point_changed
          && !f->windows_structure_changed)
        {
@@ -6039,7 +6052,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
              && !f->faces_changed
              && !f->glyphs_changed
              && !f->subwindows_changed
              && !f->faces_changed
              && !f->glyphs_changed
              && !f->subwindows_changed
-             && !f->subwindows_state_changed
+             /*              && !f->subwindows_state_changed*/
              && !f->windows_structure_changed)
            {
              if (point_visible (w, pointm, CURRENT_DISP)
              && !f->windows_structure_changed)
            {
              if (point_visible (w, pointm, CURRENT_DISP)
@@ -6098,7 +6111,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
           && !f->faces_changed
           && !f->glyphs_changed
           && !f->subwindows_changed
           && !f->faces_changed
           && !f->glyphs_changed
           && !f->subwindows_changed
-          && !f->subwindows_state_changed
+          /*      && !f->subwindows_state_changed*/
           && !f->windows_structure_changed
           && !f->frame_changed
           && !truncation_changed
           && !f->windows_structure_changed
           && !f->frame_changed
           && !truncation_changed
@@ -6280,7 +6293,7 @@ call_redisplay_end_triggers (struct window *w, void *closure)
 
 /* Ensure that all windows on the given frame are correctly displayed. */
 
 
 /* Ensure that all windows on the given frame are correctly displayed. */
 
-static int
+int
 redisplay_frame (struct frame *f, int preemption_check)
 {
   struct device *d = XDEVICE (f->device);
 redisplay_frame (struct frame *f, int preemption_check)
 {
   struct device *d = XDEVICE (f->device);
@@ -6322,30 +6335,26 @@ redisplay_frame (struct frame *f, int preemption_check)
      being handled. */
   update_frame_menubars (f);
 #endif /* HAVE_MENUBARS */
      being handled. */
   update_frame_menubars (f);
 #endif /* HAVE_MENUBARS */
-  /* widgets are similar to menus in that they can call lisp to
-     determine activation etc. Therefore update them before we get
-     into redisplay. This is primarily for connected widgets such as
-     radio buttons. */
-  update_frame_subwindows (f);
 #ifdef HAVE_TOOLBARS
   /* Update the toolbars. */
   update_frame_toolbars (f);
 #endif /* HAVE_TOOLBARS */
 #ifdef HAVE_TOOLBARS
   /* Update the toolbars. */
   update_frame_toolbars (f);
 #endif /* HAVE_TOOLBARS */
+  /* Gutter update proper has to be done inside display when no frame
+     size changes can occur, thus we separately update the gutter
+     geometry here if it needs it. */
+  update_frame_gutter_geometry (f);
 
   /* If we clear the frame we have to force its contents to be redrawn. */
   if (f->clear)
     f->frame_changed = 1;
 
 
   /* If we clear the frame we have to force its contents to be redrawn. */
   if (f->clear)
     f->frame_changed = 1;
 
-  /* invalidate the subwindow cache. We use subwindows_changed here to
+  /* Invalidate the subwindow cache. We use subwindows_changed here to
      cause subwindows to get instantiated. This is because
      subwindows_state_changed is less strict - dealing with things
      like the clicked state of button. We have to do this before
      redisplaying the gutters as subwindows get unmapped in the
      process.*/
      cause subwindows to get instantiated. This is because
      subwindows_state_changed is less strict - dealing with things
      like the clicked state of button. We have to do this before
      redisplaying the gutters as subwindows get unmapped in the
      process.*/
-  if (!Dynarr_length (f->subwindow_cachels)
-      || f->subwindows_changed
-      || f->faces_changed
-      || f->frame_changed)
+  if (f->frame_changed || f->subwindows_changed)
     {
       reset_subwindow_cachels (f);
       /* we have to do this so the gutter gets regenerated. */
     {
       reset_subwindow_cachels (f);
       /* we have to do this so the gutter gets regenerated. */
@@ -6353,9 +6362,6 @@ redisplay_frame (struct frame *f, int preemption_check)
     }
   else
     mark_subwindow_cachels_as_not_updated (f);
     }
   else
     mark_subwindow_cachels_as_not_updated (f);
-  /* We can now update the gutters, safe in the knowledge that our
-     efforts won't get undone. */
-  update_frame_gutters (f);
 
   hold_frame_size_changes ();
 
 
   hold_frame_size_changes ();
 
@@ -6383,6 +6389,16 @@ redisplay_frame (struct frame *f, int preemption_check)
      #### If a frame-size change does occur we should probably
      actually be preempting redisplay. */
 
      #### If a frame-size change does occur we should probably
      actually be preempting redisplay. */
 
+  /* We can now update the gutters, safe in the knowledge that our
+     efforts won't get undone. */
+
+  /* This can call lisp, but redisplay is protected by binding
+     inhibit_quit.  More importantly the code involving display lines
+     *assumes* that GC will not happen and so does not GCPRO
+     anything. Since we use this code the whole time with the gutters
+     we cannot allow GC to happen when manipulating the gutters. */
+  update_frame_gutters (f);
+
   /* Erase the frame before outputting its contents. */
   if (f->clear)
     {
   /* Erase the frame before outputting its contents. */
   if (f->clear)
     {
@@ -6422,16 +6438,27 @@ redisplay_frame (struct frame *f, int preemption_check)
   return 0;
 }
 
   return 0;
 }
 
-/* Ensure that all frames on the given device are correctly displayed. */
+/* Ensure that all frames on the given device are correctly displayed.
+   If AUTOMATIC is non-zero, and the device implementation indicates
+   no automatic redisplay, as printers do, then the device is not
+   redisplayed. AUTOMATIC is set to zero when called from lisp
+   functions (redraw-device) and (redisplay-device), and to non-zero
+   when called from "lazy" redisplay();
+*/
 
 static int
 
 static int
-redisplay_device (struct device *d)
+redisplay_device (struct device *d, int automatic)
 {
   Lisp_Object frame, frmcons;
   int preempted = 0;
   int size_change_failed = 0;
   struct frame *f;
 
 {
   Lisp_Object frame, frmcons;
   int preempted = 0;
   int size_change_failed = 0;
   struct frame *f;
 
+  if (automatic
+      && (MAYBE_INT_DEVMETH (d, device_implementation_flags, ())
+         & XDEVIMPF_NO_AUTO_REDISPLAY))
+    return 0;
+
   if (DEVICE_STREAM_P (d)) /* nothing to do */
     return 0;
 
   if (DEVICE_STREAM_P (d)) /* nothing to do */
     return 0;
 
@@ -6546,7 +6573,7 @@ redisplay_without_hooks (void)
 
       if (CLASS_REDISPLAY_FLAGS_CHANGEDP (d))
        {
 
       if (CLASS_REDISPLAY_FLAGS_CHANGEDP (d))
        {
-         preempted = redisplay_device (d);
+         preempted = redisplay_device (d, 1);
 
          if (preempted)
            {
 
          if (preempted)
            {
@@ -6660,7 +6687,7 @@ static void
 decode_mode_spec (struct window *w, Emchar spec, int type)
 {
   Lisp_Object obj = Qnil;
 decode_mode_spec (struct window *w, Emchar spec, int type)
 {
   Lisp_Object obj = Qnil;
-  CONST char *str = NULL;
+  const char *str = NULL;
   struct buffer *b = XBUFFER (w->buffer);
 
   Dynarr_reset (mode_spec_bufbyte_string);
   struct buffer *b = XBUFFER (w->buffer);
 
   Dynarr_reset (mode_spec_bufbyte_string);
@@ -6689,7 +6716,7 @@ decode_mode_spec (struct window *w, Emchar spec, int type)
        long_to_string (buf, col);
 
        Dynarr_add_many (mode_spec_bufbyte_string,
        long_to_string (buf, col);
 
        Dynarr_add_many (mode_spec_bufbyte_string,
-                        (CONST Bufbyte *) buf, strlen (buf));
+                        (const Bufbyte *) buf, strlen (buf));
 
        goto decode_mode_spec_done;
       }
 
        goto decode_mode_spec_done;
       }
@@ -7026,7 +7053,9 @@ mark_glyph_block_dynarr (glyph_block_dynarr *gba)
     }
 }
 
     }
 }
 
-static void
+/* See the comment in image_instantiate_cache_result as to why marking
+   the glyph will also mark the image_instance. */
+void
 mark_redisplay_structs (display_line_dynarr *dla)
 {
   display_line *dl = Dynarr_atp (dla, 0);
 mark_redisplay_structs (display_line_dynarr *dla)
 {
   display_line *dl = Dynarr_atp (dla, 0);
@@ -7086,6 +7115,7 @@ mark_redisplay (void)
       struct frame *f = XFRAME (XCAR (frmcons));
       update_frame_window_mirror (f);
       mark_window_mirror (f->root_mirror);
       struct frame *f = XFRAME (XCAR (frmcons));
       update_frame_window_mirror (f);
       mark_window_mirror (f->root_mirror);
+      mark_gutters (f);
     }
 }
 \f
     }
 }
 \f
@@ -7522,11 +7552,18 @@ point_would_be_visible (struct window *w, Bufpos startp, Bufpos point)
    displayed.  The end of the last line is also know as the window end
    position.
 
    displayed.  The end of the last line is also know as the window end
    position.
 
+   WARNING: It is possible that rediplay failed to layout any lines for the
+   windows. Under normal circumstances this is rare. However it seems that it
+   does occur in the following situation: A mouse event has come in and we
+   need to compute its location in a window. That code (in
+   pixel_to_glyph_translation) already can handle 0 as an error return value.
+
    #### With a little work this could probably be reworked as just a
    call to start_with_line_at_pixpos. */
 
 static Bufpos
    #### With a little work this could probably be reworked as just a
    call to start_with_line_at_pixpos. */
 
 static Bufpos
-start_end_of_last_line (struct window *w, Bufpos startp, int end)
+start_end_of_last_line (struct window *w, Bufpos startp, int end,
+                        int may_error)
 {
   struct buffer *b = XBUFFER (w->buffer);
   line_start_cache_dynarr *cache = w->line_start_cache;
 {
   struct buffer *b = XBUFFER (w->buffer);
   line_start_cache_dynarr *cache = w->line_start_cache;
@@ -7546,7 +7583,7 @@ start_end_of_last_line (struct window *w, Bufpos startp, int end)
 
   start_elt = point_in_line_start_cache (w, cur_start, 0);
   if (start_elt == -1)
 
   start_elt = point_in_line_start_cache (w, cur_start, 0);
   if (start_elt == -1)
-    abort ();  /* this had better never happen */
+      return may_error ? 0 : startp;
 
   while (1)
     {
 
   while (1)
     {
@@ -7610,7 +7647,7 @@ start_end_of_last_line (struct window *w, Bufpos startp, int end)
 Bufpos
 start_of_last_line (struct window *w, Bufpos startp)
 {
 Bufpos
 start_of_last_line (struct window *w, Bufpos startp)
 {
-  return start_end_of_last_line (w, startp, 0);
+  return start_end_of_last_line (w, startp, 0 , 0);
 }
 
 /* For the given window W, if display starts at STARTP, what will be
 }
 
 /* For the given window W, if display starts at STARTP, what will be
@@ -7620,9 +7657,16 @@ start_of_last_line (struct window *w, Bufpos startp)
 Bufpos
 end_of_last_line (struct window *w, Bufpos startp)
 {
 Bufpos
 end_of_last_line (struct window *w, Bufpos startp)
 {
-  return start_end_of_last_line (w, startp, 1);
+  return start_end_of_last_line (w, startp, 1, 0);
+}
+
+static Bufpos
+end_of_last_line_may_error (struct window *w, Bufpos startp)
+{
+  return start_end_of_last_line (w, startp, 1, 1);
 }
 
 }
 
+
 /* For window W, what does the starting position have to be so that
    the line containing POINT will cover pixel position PIXPOS. */
 
 /* For window W, what does the starting position have to be so that
    the line containing POINT will cover pixel position PIXPOS. */
 
@@ -8776,7 +8820,7 @@ pixel_to_glyph_translation (struct frame *f, int x_coord, int y_coord,
   if (!MARKERP ((*w)->start[CURRENT_DISP]))
     *closest = 0;
   else
   if (!MARKERP ((*w)->start[CURRENT_DISP]))
     *closest = 0;
   else
-    *closest = end_of_last_line (*w,
+    *closest = end_of_last_line_may_error (*w,
                                 marker_position ((*w)->start[CURRENT_DISP]));
   *col = 0;
   UPDATE_CACHE_RETURN;
                                 marker_position ((*w)->start[CURRENT_DISP]));
   *col = 0;
   UPDATE_CACHE_RETURN;
@@ -8864,6 +8908,9 @@ input and is guaranteed to proceed to completion.
   f->clear = 1;
   redisplay_frame (f, 1);
 
   f->clear = 1;
   redisplay_frame (f, 1);
 
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
   return unbind_to (count, Qnil);
 }
 
@@ -8891,6 +8938,15 @@ input and is guaranteed to proceed to completion.
 
   redisplay_frame (f, 1);
 
 
   redisplay_frame (f, 1);
 
+  /* If we don't reset the global redisplay flafs here, subsequent
+     changes to the display will not get registered by redisplay
+     because it thinks it already has registered changes. If you
+     really knew what you were doing you could confuse redisplay by
+     calling Fredisplay_frame while updating another frame. We assume
+     that if you know what you are doing you will not be that
+     stupid. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
   return unbind_to (count, Qnil);
 }
 
@@ -8918,7 +8974,10 @@ input and is guaranteed to proceed to completion.
     {
       XFRAME (XCAR (frmcons))->clear = 1;
     }
     {
       XFRAME (XCAR (frmcons))->clear = 1;
     }
-  redisplay_device (d);
+  redisplay_device (d, 0);
+
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
 
   return unbind_to (count, Qnil);
 }
 
   return unbind_to (count, Qnil);
 }
@@ -8945,7 +9004,10 @@ input and is guaranteed to proceed to completion.
       disable_preemption++;
     }
 
       disable_preemption++;
     }
 
-  redisplay_device (d);
+  redisplay_device (d, 0);
+
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
 
   return unbind_to (count, Qnil);
 }
 
   return unbind_to (count, Qnil);
 }
@@ -9125,12 +9187,18 @@ init_redisplay (void)
   if (!initialized)
 #endif
     {
   if (!initialized)
 #endif
     {
-      cmotion_display_lines = Dynarr_new (display_line);
-      mode_spec_bufbyte_string = Dynarr_new (Bufbyte);
-      formatted_string_extent_dynarr = Dynarr_new (EXTENT);
-      formatted_string_extent_start_dynarr = Dynarr_new (Bytecount);
-      formatted_string_extent_end_dynarr = Dynarr_new (Bytecount);
-      internal_cache = Dynarr_new (line_start_cache);
+      if (!cmotion_display_lines)
+       cmotion_display_lines = Dynarr_new (display_line);
+      if (!mode_spec_bufbyte_string)
+       mode_spec_bufbyte_string = Dynarr_new (Bufbyte);
+      if (!formatted_string_extent_dynarr)
+       formatted_string_extent_dynarr = Dynarr_new (EXTENT);
+      if (!formatted_string_extent_start_dynarr)
+       formatted_string_extent_start_dynarr = Dynarr_new (Bytecount);
+      if (!formatted_string_extent_end_dynarr)
+       formatted_string_extent_end_dynarr = Dynarr_new (Bytecount);
+      if (!internal_cache)
+       internal_cache = Dynarr_new (line_start_cache);
     }
 
   /* window system is nil when in -batch mode */
     }
 
   /* window system is nil when in -batch mode */
@@ -9203,6 +9271,7 @@ syms_of_redisplay (void)
   defsymbol (&Qbar_cursor, "bar-cursor");
   defsymbol (&Qredisplay_end_trigger_functions,
             "redisplay-end-trigger-functions");
   defsymbol (&Qbar_cursor, "bar-cursor");
   defsymbol (&Qredisplay_end_trigger_functions,
             "redisplay-end-trigger-functions");
+  defsymbol (&Qtop_bottom, "top-bottom");
 
   DEFSUBR (Fredisplay_echo_area);
   DEFSUBR (Fredraw_frame);
 
   DEFSUBR (Fredisplay_echo_area);
   DEFSUBR (Fredraw_frame);
@@ -9291,10 +9360,19 @@ If this is zero, point is always centered after it moves off screen.
                     redisplay_variable_changed);
   truncate_partial_width_windows = 1;
 
                     redisplay_variable_changed);
   truncate_partial_width_windows = 1;
 
-  DEFVAR_BOOL ("visible-bell", &visible_bell /*
-*Non-nil means try to flash the frame to represent a bell.
+  DEFVAR_LISP ("visible-bell", &Vvisible_bell /*
+*Non-nil substitutes a visual signal for the audible bell.
+
+Default behavior is to flash the whole screen.  On some platforms,
+special effects are available using the following values:
+
+'display       Flash the whole screen (ie, the default behavior).
+'top-bottom    Flash only the top and bottom lines of the selected frame.
+
+When effects are unavailable on a platform, the visual bell is the
+default, whole screen.  (Currently only X supports any special effects.)
 */ );
 */ );
-  visible_bell = 0;
+  Vvisible_bell = Qnil;
 
   DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter /*
 *Non-nil means no need to redraw entire frame after suspending.
 
   DEFVAR_BOOL ("no-redraw-on-reenter", &no_redraw_on_reenter /*
 *Non-nil means no need to redraw entire frame after suspending.