Initial incomplete version of tty menus. tty_menu_activate not done yet.
[bpt/emacs.git] / src / dispnew.c
index 93a990c..0c97512 100644 (file)
@@ -1,5 +1,6 @@
 /* Updating of data structures for redisplay.
-   Copyright (C) 1985-1988, 1993-1995, 1997-2011 Free Software Foundation, Inc.
+
+Copyright (C) 1985-1988, 1993-1995, 1997-2012 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -62,7 +63,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <errno.h>
 
 /* Get number of chars of output now in the buffer of a stdio stream.
-   This ought to be built in in stdio, but it isn't.  Some s- files
+   This ought to be built in stdio, but it isn't.  Some s- files
    override this because their stdio internals differ.  */
 
 #ifdef __GNU_LIBRARY__
@@ -87,7 +88,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 #endif /* not __GNU_LIBRARY__ */
 
-#if defined (HAVE_TERM_H) && defined (GNU_LINUX) && defined (HAVE_LIBNCURSES)
+#if defined (HAVE_TERM_H) && defined (GNU_LINUX)
 #include <term.h>              /* for tgetent */
 #endif
 \f
@@ -331,11 +332,13 @@ DEFUN ("dump-redisplay-history", Fdump_redisplay_history,
 #endif /* GLYPH_DEBUG == 0 */
 
 
-#if defined PROFILING && !HAVE___EXECUTABLE_START
-/* FIXME: only used to find text start for profiling.  */
-
+#if (defined PROFILING \
+     && (defined __FreeBSD__ || defined GNU_LINUX || defined __MINGW32__) \
+     && !HAVE___EXECUTABLE_START)
+/* This function comes first in the Emacs executable and is used only
+   to estimate the text start for profiling.  */
 void
-safe_bcopy (const char *from, char *to, int size)
+__executable_start (void)
 {
   abort ();
 }
@@ -429,6 +432,14 @@ margin_glyphs_to_reserve (struct window *w, int total_glyphs, Lisp_Object margin
   return n;
 }
 
+#if XASSERTS
+/* Return non-zero if ROW's hash value is correct, zero if not.  */
+int
+verify_row_hash (struct glyph_row *row)
+{
+  return row->hash == row_hash (row);
+}
+#endif
 
 /* Adjust glyph matrix MATRIX on window W or on a frame to changed
    window sizes.
@@ -1063,37 +1074,59 @@ swap_glyphs_in_rows (struct glyph_row *a, struct glyph_row *b)
 
 #endif /* 0 */
 
-/* Exchange pointers to glyph memory between glyph rows A and B.  */
+/* Exchange pointers to glyph memory between glyph rows A and B.  Also
+   exchange the used[] array and the hash values of the rows, because
+   these should all go together for the row's hash value to be
+   correct.  */
 
 static inline void
 swap_glyph_pointers (struct glyph_row *a, struct glyph_row *b)
 {
   int i;
+  unsigned hash_tem = a->hash;
+
   for (i = 0; i < LAST_AREA + 1; ++i)
     {
       struct glyph *temp = a->glyphs[i];
+
       a->glyphs[i] = b->glyphs[i];
       b->glyphs[i] = temp;
+      if (i < LAST_AREA)
+       {
+         short used_tem = a->used[i];
+
+         a->used[i] = b->used[i];
+         b->used[i] = used_tem;
+       }
     }
+  a->hash = b->hash;
+  b->hash = hash_tem;
 }
 
 
 /* Copy glyph row structure FROM to glyph row structure TO, except
-   that glyph pointers in the structures are left unchanged.  */
+   that glyph pointers, the `used' counts, and the hash values in the
+   structures are left unchanged.  */
 
 static inline void
 copy_row_except_pointers (struct glyph_row *to, struct glyph_row *from)
 {
   struct glyph *pointers[1 + LAST_AREA];
+  short used[LAST_AREA];
+  unsigned hashval;
 
   /* Save glyph pointers of TO.  */
   memcpy (pointers, to->glyphs, sizeof to->glyphs);
+  memcpy (used, to->used, sizeof to->used);
+  hashval = to->hash;
 
   /* Do a structure assignment.  */
   *to = *from;
 
   /* Restore original pointers of TO.  */
   memcpy (to->glyphs, pointers, sizeof to->glyphs);
+  memcpy (to->used, used, sizeof to->used);
+  to->hash = hashval;
 }
 
 
@@ -1271,6 +1304,9 @@ line_draw_cost (struct glyph_matrix *matrix, int vpos)
 static inline int
 row_equal_p (struct glyph_row *a, struct glyph_row *b, int mouse_face_p)
 {
+  xassert (verify_row_hash (a));
+  xassert (verify_row_hash (b));
+
   if (a == b)
     return 1;
   else if (a->hash != b->hash)
@@ -3301,6 +3337,39 @@ update_frame (struct frame *f, int force_p, int inhibit_hairy_id_p)
   return paused_p;
 }
 
+/* Update a TTY frame F that has a menu dropped down over some of its
+   glyphs.  This is like the second part of update_frame, but it
+   doesn't call build_frame_matrix, because we already have the
+   desired matrix prepared, and don't want it to be overwritten by the
+   text of the normal display.  */
+void
+update_frame_with_menu (struct frame *f)
+{
+  struct window *root_window = XWINDOW (f->root_window);
+
+  xassert (FRAME_TERMCAP_P (f));
+
+  /* We are working on frame matrix basis.  Set the frame on whose
+     frame matrix we operate.  */
+  set_frame_matrix_frame (f);
+
+  /* Update the display  */
+  update_begin (f);
+  paused_p = update_frame_1 (f, 1, 1);
+  update_end (f);
+
+  if (FRAME_TTY (f)->termscript)
+    fflush (FRAME_TTY (f)->termscript);
+  fflush (FRAME_TTY (f)->output);
+  /* Check window matrices for lost pointers.  */
+#if GLYPH_DEBUG
+  check_window_matrix_pointers (root_window);
+  add_frame_display_history (f, paused_p);
+#endif
+
+  /* Reset flags indicating that a window should be updated.  */
+  set_window_update_flags (root_window, 0);
+}
 
 \f
 /************************************************************************
@@ -3467,7 +3536,7 @@ redraw_overlapping_rows (struct window *w, int yb)
              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
+             /* Record in neighbor rows that ROW overwrites part of
                 their display.  */
              if (overlaps & OVERLAPS_PRED)
                MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p = 1;
@@ -3545,12 +3614,11 @@ update_window (struct window *w, int force_p)
 
       rif->update_window_begin_hook (w);
       yb = window_text_bottom_y (w);
-
-      /* If window has a header line, update it before everything else.
-        Adjust y-positions of other rows by the header line height.  */
       row = desired_matrix->rows;
       end = row + desired_matrix->nrows - 1;
 
+      /* Take note of the header line, if there is one.  We will
+        update it below, after updating all of the window's lines.  */
       if (row->mode_line_p)
        {
          header_line_row = row;
@@ -3595,6 +3663,8 @@ update_window (struct window *w, int force_p)
 
       /* Update the rest of the lines.  */
       for (; row < end && (force_p || !input_pending); ++row)
+       /* scrolling_window resets the enabled_p flag of the rows it
+          reuses from current_matrix.  */
        if (row->enabled_p)
          {
            int vpos = MATRIX_ROW_VPOS (row, desired_matrix);
@@ -4209,6 +4279,7 @@ add_row_entry (struct glyph_row *row)
   ptrdiff_t i = row->hash % row_table_size;
 
   entry = row_table[i];
+  xassert (entry || verify_row_hash (row));
   while (entry && !row_equal_p (entry->row, row, 1))
     entry = entry->next;
 
@@ -4333,10 +4404,10 @@ scrolling_window (struct window *w, int header_line_p)
   j = last_old;
   while (i - 1 > first_new
          && j - 1 > first_old
-         && 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
+         && MATRIX_ROW (current_matrix, j - 1)->enabled_p
+        && (MATRIX_ROW (current_matrix, j - 1)->y
+            == MATRIX_ROW (desired_matrix, i - 1)->y)
+        && !MATRIX_ROW (desired_matrix, i - 1)->redraw_fringe_bitmaps_p
          && row_equal_p (MATRIX_ROW (desired_matrix, i - 1),
                          MATRIX_ROW (current_matrix, j - 1), 1))
     --i, --j;
@@ -4519,18 +4590,69 @@ scrolling_window (struct window *w, int header_line_p)
          {
            rif->clear_window_mouse_face (w);
            rif->scroll_run_hook (w, r);
+         }
 
-           /* Invalidate runs that copy from where we copied to.  */
-           for (j = i + 1; j < nruns; ++j)
+       /* Truncate runs that copy to where we copied to, and
+          invalidate runs that copy from where we copied to.  */
+       for (j = nruns - 1; j > i; --j)
+         {
+           struct run *p = runs[j];
+           int truncated_p = 0;
+
+           if (p->nrows > 0
+               && p->desired_y < r->desired_y + r->height
+               && p->desired_y + p->height > r->desired_y)
              {
-               struct run *p = runs[j];
+               if (p->desired_y < r->desired_y)
+                 {
+                   p->nrows = r->desired_vpos - p->desired_vpos;
+                   p->height = r->desired_y - p->desired_y;
+                   truncated_p = 1;
+                 }
+               else
+                 {
+                   int nrows_copied = (r->desired_vpos + r->nrows
+                                       - p->desired_vpos);
+
+                   if (p->nrows <= nrows_copied)
+                     p->nrows = 0;
+                   else
+                     {
+                       int height_copied = (r->desired_y + r->height
+                                            - p->desired_y);
+
+                       p->current_vpos += nrows_copied;
+                       p->desired_vpos += nrows_copied;
+                       p->nrows -= nrows_copied;
+                       p->current_y += height_copied;
+                       p->desired_y += height_copied;
+                       p->height -= height_copied;
+                       truncated_p = 1;
+                     }
+                 }
+             }
 
-               if ((p->current_y >= r->desired_y
+           if (r->current_y != r->desired_y
+               /* The condition below is equivalent to
+                  ((p->current_y >= r->desired_y
                     && p->current_y < r->desired_y + r->height)
-                   || (p->current_y + p->height >= r->desired_y
+                   || (p->current_y + p->height > r->desired_y
                        && (p->current_y + p->height
-                           < r->desired_y + r->height)))
-                 p->nrows = 0;
+                           <= r->desired_y + r->height)))
+                  because we have 0 < p->height <= r->height.  */
+               && p->current_y < r->desired_y + r->height
+               && p->current_y + p->height > r->desired_y)
+             p->nrows = 0;
+
+           /* Reorder runs by copied pixel lines if truncated.  */
+           if (truncated_p && p->nrows > 0)
+             {
+               int k = nruns - 1;
+
+               while (runs[k]->nrows == 0 || runs[k]->height < p->height)
+                 k--;
+               memmove (runs + j, runs + j + 1, (k - j) * sizeof (*runs));
+               runs[k] = p;
              }
          }
 
@@ -4545,7 +4667,14 @@ scrolling_window (struct window *w, int header_line_p)
            to_overlapped_p = to->overlapped_p;
            from->redraw_fringe_bitmaps_p = from->fringe_bitmap_periodic_p;
            assign_row (to, from);
-           to->enabled_p = 1, from->enabled_p = 0;
+           /* The above `assign_row' actually does swap, so if we had
+              an overlap in the copy destination of two runs, then
+              the second run would assign a previously disabled bogus
+              row.  But thanks to the truncation code in the
+              preceding for-loop, we no longer have such an overlap,
+              and thus the assigned row should always be enabled.  */
+           xassert (to->enabled_p);
+           from->enabled_p = 0;
            to->overlapped_p = to_overlapped_p;
          }
       }
@@ -5671,19 +5800,22 @@ change_frame_size_1 (register struct frame *f, int newheight, int newwidth, int
   if (newwidth == 0)
     newwidth  = FRAME_COLS  (f);
 
-  /* Compute width of windows in F.
-     This is the width of the frame without vertical scroll bars.  */
-  new_frame_total_cols = FRAME_TOTAL_COLS_ARG (f, newwidth);
-
+  /* Compute width of windows in F.  */
   /* Round up to the smallest acceptable size.  */
   check_frame_size (f, &newheight, &newwidth);
 
+  /* This is the width of the frame with vertical scroll bars and fringe
+     columns.  Do this after rounding - see discussion of bug#9723.  */
+  new_frame_total_cols = FRAME_TOTAL_COLS_ARG (f, newwidth);
+
   /* If we're not changing the frame size, quit now.  */
-  /* Frame width may be unchanged but the text portion may change, for example,
-     fullscreen and remove/add scroll bar.  */
+  /* Frame width may be unchanged but the text portion may change, for
+     example, fullscreen and remove/add scroll bar.  */
   if (newheight == FRAME_LINES (f)
-      && newwidth == FRAME_COLS  (f) // text portion unchanged
-      && new_frame_total_cols == FRAME_TOTAL_COLS (f)) // frame width unchanged
+      /* Text portion unchanged?  */
+      && newwidth == FRAME_COLS  (f)
+      /* Frame width unchanged?  */
+      && new_frame_total_cols == FRAME_TOTAL_COLS (f))
     return;
 
   BLOCK_INPUT;
@@ -5985,10 +6117,14 @@ sit_for (Lisp_Object timeout, int reading, int do_display)
 
 
 DEFUN ("redisplay", Fredisplay, Sredisplay, 0, 1, 0,
-       doc: /* Perform redisplay if no input is available.
-If optional arg FORCE is non-nil or `redisplay-dont-pause' is non-nil,
-perform a full redisplay even if input is available.
-Return t if redisplay was performed, nil otherwise.  */)
+       doc: /* Perform redisplay.
+Optional arg FORCE, if non-nil, prevents redisplay from being
+preempted by arriving input, even if `redisplay-dont-pause' is nil.
+If `redisplay-dont-pause' is non-nil (the default), redisplay is never
+preempted by arriving input, so FORCE does nothing.
+
+Return t if redisplay was performed, nil if redisplay was preempted
+immediately by pending input.  */)
   (Lisp_Object force)
 {
   ptrdiff_t count;
@@ -6212,7 +6348,7 @@ init_display (void)
 #ifdef HAVE_X11
       Vwindow_system_version = make_number (11);
 #endif
-#if defined (GNU_LINUX) && defined (HAVE_LIBNCURSES)
+#ifdef GNU_LINUX
       /* In some versions of ncurses,
         tputs crashes if we have not called tgetent.
         So call tgetent.  */
@@ -6438,21 +6574,21 @@ syms_of_display (void)
   DEFSYM (Qredisplay_dont_pause, "redisplay-dont-pause");
 
   DEFVAR_INT ("baud-rate", baud_rate,
-             doc: /* *The output baud rate of the terminal.
+             doc: /* The output baud rate of the terminal.
 On most systems, changing this value will affect the amount of padding
 and the other strategic decisions made during redisplay.  */);
 
   DEFVAR_BOOL ("inverse-video", inverse_video,
-              doc: /* *Non-nil means invert the entire frame display.
+              doc: /* Non-nil means invert the entire frame display.
 This means everything is in inverse video which otherwise would not be.  */);
 
   DEFVAR_BOOL ("visible-bell", visible_bell,
-              doc: /* *Non-nil means try to flash the frame to represent a bell.
+              doc: /* Non-nil means try to flash the frame to represent a bell.
 
 See also `ring-bell-function'.  */);
 
   DEFVAR_BOOL ("no-redraw-on-reenter", no_redraw_on_reenter,
-              doc: /* *Non-nil means no need to redraw entire frame after suspending.
+              doc: /* Non-nil means no need to redraw entire frame after suspending.
 A non-nil value is useful if the terminal can automatically preserve
 Emacs's frame display when you reenter Emacs.
 It is up to you to set this variable if your terminal can do that.  */);
@@ -6507,14 +6643,15 @@ See `buffer-display-table' for more information.  */);
   Vstandard_display_table = Qnil;
 
   DEFVAR_BOOL ("redisplay-dont-pause", redisplay_dont_pause,
-              doc: /* *Non-nil means display update isn't paused when input is detected.  */);
+              doc: /* Non-nil means display update isn't paused when input is detected.  */);
   redisplay_dont_pause = 1;
 
 #if PERIODIC_PREEMPTION_CHECKING
   DEFVAR_LISP ("redisplay-preemption-period", Vredisplay_preemption_period,
-              doc: /* *The period in seconds between checking for input during redisplay.
-If input is detected, redisplay is pre-empted, and the input is processed.
-If nil, never pre-empt redisplay.  */);
+              doc: /* Period in seconds between checking for input during redisplay.
+This has an effect only if `redisplay-dont-pause' is nil; in that
+case, arriving input preempts redisplay until the input is processed.
+If the value is nil, redisplay is never preempted.  */);
   Vredisplay_preemption_period = make_float (0.10);
 #endif