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;
 
-/* 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;
 
@@ -419,9 +418,9 @@ int windows_structure_changed;
 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,
@@ -471,6 +470,8 @@ Lisp_Object Vtext_cursor_visible_p;
 
 int column_number_start_at_one;
 
+Lisp_Object Qtop_bottom;
+
 #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);
-         struct Lisp_Font_Instance *fi;
+         Lisp_Font_Instance *fi;
 
          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))
     {
-      struct Lisp_Vector *de = XVECTOR (entry);
+      Lisp_Vector *de = XVECTOR (entry);
       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);
 
+  /* 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 &&
@@ -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);
 
-      /* 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;
@@ -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;
-  /* adjust for the bottom gutter */
-  if (window_is_lowest (w))
-    dl->ypos -= FRAME_BOTTOM_GUTTER_BOUNDS (f);
 }
 
 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;
-  CONST Bufbyte *cur_pos = str;
+  const Bufbyte *cur_pos = str;
   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) +
-         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)
     {
-      CONST Bufbyte *old_cur_pos = cur_pos;
+      const Bufbyte *old_cur_pos = 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));
-                 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);
@@ -3873,7 +3879,7 @@ tail_recurse:
 
                   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)
                 {
@@ -3892,9 +3898,9 @@ tail_recurse:
                    *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,
@@ -3938,9 +3944,9 @@ tail_recurse:
                *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,
@@ -4132,10 +4138,10 @@ tail_recurse:
          *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);
@@ -4146,7 +4152,7 @@ tail_recurse:
 
   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);
     }
 
@@ -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);
-  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);
@@ -4762,7 +4768,7 @@ done:
 
          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')
                {
@@ -5147,6 +5153,9 @@ regenerate_window (struct window *w, Bufpos start_pos, Bufpos point, int type)
   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;
@@ -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. */
-  /* #### 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
-     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)
@@ -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))
-      || !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);
@@ -6017,7 +6030,7 @@ redisplay_window (Lisp_Object window, int skip_selected)
          && !f->faces_changed
          && !f->glyphs_changed
          && !f->subwindows_changed
-         && !f->subwindows_state_changed
+         /*      && !f->subwindows_state_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->subwindows_state_changed
+             /*              && !f->subwindows_state_changed*/
              && !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->subwindows_state_changed
+          /*      && !f->subwindows_state_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. */
 
-static int
+int
 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 */
-  /* 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 */
+  /* 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;
 
-  /* 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.*/
-  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. */
@@ -6353,9 +6362,6 @@ redisplay_frame (struct frame *f, int preemption_check)
     }
   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 ();
 
@@ -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. */
 
+  /* 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)
     {
@@ -6422,16 +6438,27 @@ redisplay_frame (struct frame *f, int preemption_check)
   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
-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;
 
+  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;
 
@@ -6546,7 +6573,7 @@ redisplay_without_hooks (void)
 
       if (CLASS_REDISPLAY_FLAGS_CHANGEDP (d))
        {
-         preempted = redisplay_device (d);
+         preempted = redisplay_device (d, 1);
 
          if (preempted)
            {
@@ -6660,7 +6687,7 @@ static void
 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);
@@ -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,
-                        (CONST Bufbyte *) buf, strlen (buf));
+                        (const Bufbyte *) buf, strlen (buf));
 
        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);
@@ -7086,6 +7115,7 @@ mark_redisplay (void)
       struct frame *f = XFRAME (XCAR (frmcons));
       update_frame_window_mirror (f);
       mark_window_mirror (f->root_mirror);
+      mark_gutters (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.
 
+   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
-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;
@@ -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)
-    abort ();  /* this had better never happen */
+      return may_error ? 0 : startp;
 
   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)
 {
-  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
@@ -7620,9 +7657,16 @@ start_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. */
 
@@ -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
-    *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;
@@ -8864,6 +8908,9 @@ input and is guaranteed to proceed to completion.
   f->clear = 1;
   redisplay_frame (f, 1);
 
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
+
   return unbind_to (count, Qnil);
 }
 
@@ -8891,6 +8938,15 @@ input and is guaranteed to proceed to completion.
 
   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);
 }
 
@@ -8918,7 +8974,10 @@ input and is guaranteed to proceed to completion.
     {
       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);
 }
@@ -8945,7 +9004,10 @@ input and is guaranteed to proceed to completion.
       disable_preemption++;
     }
 
-  redisplay_device (d);
+  redisplay_device (d, 0);
+
+  /* See the comment in Fredisplay_frame. */
+  RESET_CHANGED_SET_FLAGS;
 
   return unbind_to (count, Qnil);
 }
@@ -9125,12 +9187,18 @@ init_redisplay (void)
   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 */
@@ -9203,6 +9271,7 @@ syms_of_redisplay (void)
   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);
@@ -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;
 
-  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.