Merge from emacs--devo--0
[bpt/emacs.git] / src / dispnew.c
index b001db8..97cd210 100644 (file)
@@ -1,7 +1,7 @@
 /* Updating of data structures for redisplay.
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
                  1997, 1998, 1999, 2000, 2001, 2002, 2003,
-                 2004, 2005 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -192,6 +192,28 @@ struct window *frame_row_to_window P_ ((struct window *, int));
 
 int redisplay_dont_pause;
 
+/* Define PERIODIC_PREEMPTION_CHECKING to 1, if micro-second timers
+   are supported, so we can check for input during redisplay at
+   regular intervals.  */
+#ifdef EMACS_HAS_USECS
+#define PERIODIC_PREEMPTION_CHECKING 1
+#else
+#define PERIODIC_PREEMPTION_CHECKING 0
+#endif
+
+#if PERIODIC_PREEMPTION_CHECKING
+
+/* If a number (float), check for user input every N seconds.  */
+
+Lisp_Object Vredisplay_preemption_period;
+
+/* Redisplay preemption timers.  */
+
+static EMACS_TIME preemption_period;
+static EMACS_TIME preemption_next_check;
+
+#endif
+
 /* Nonzero upon entry to redisplay means do not assume anything about
    current contents of actual terminal frame; clear and redraw it.  */
 
@@ -355,8 +377,7 @@ static unsigned history_tick;
 
 static void add_frame_display_history P_ ((struct frame *, int));
 static void add_window_display_history P_ ((struct window *, char *, int));
-
-
+\f
 /* Add to the redisplay history how window W has been displayed.
    MSG is a trace containing the information how W's glyph matrix
    has been constructed.  PAUSED_P non-zero means that the update
@@ -1776,11 +1797,9 @@ check_matrix_invariants (w)
 
    X and Y are column/row within the frame glyph matrix where
    sub-matrices for the window tree rooted at WINDOW must be
-   allocated.  CH_DIM contains the dimensions of the smallest
-   character that could be used during display.  DIM_ONLY_P non-zero
-   means that the caller of this function is only interested in the
-   result matrix dimension, and matrix adjustments should not be
-   performed.
+   allocated.  DIM_ONLY_P non-zero means that the caller of this
+   function is only interested in the result matrix dimension, and
+   matrix adjustments should not be performed.
 
    The function returns the total width/height of the sub-matrices of
    the window tree.  If called on a frame root window, the computation
@@ -2028,8 +2047,7 @@ required_matrix_width (w)
 
 
 /* Allocate window matrices for window-based redisplay.  W is the
-   window whose matrices must be allocated/reallocated.  CH_DIM is the
-   size of the smallest character that could potentially be used on W.  */
+   window whose matrices must be allocated/reallocated.  */
 
 static void
 allocate_matrices_for_window_redisplay (w)
@@ -2365,6 +2383,7 @@ adjust_frame_glyphs_for_window_redisplay (f)
   /* Allocate/reallocate window matrices.  */
   allocate_matrices_for_window_redisplay (XWINDOW (FRAME_ROOT_WINDOW (f)));
 
+#ifdef HAVE_X_WINDOWS
   /* Allocate/ reallocate matrices of the dummy window used to display
      the menu bar under X when no X toolkit support is available.  */
 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK)
@@ -2388,7 +2407,8 @@ adjust_frame_glyphs_for_window_redisplay (f)
     XSETFASTINT (w->total_cols, FRAME_TOTAL_COLS (f));
     allocate_matrices_for_window_redisplay (w);
   }
-#endif /* not USE_X_TOOLKIT */
+#endif /* not USE_X_TOOLKIT && not USE_GTK */
+#endif /* HAVE_X_WINDOWS */
 
 #ifndef USE_GTK
   /* Allocate/ reallocate matrices of the tool bar window.  If we
@@ -3807,6 +3827,32 @@ update_frame (f, force_p, inhibit_hairy_id_p)
   int paused_p;
   struct window *root_window = XWINDOW (f->root_window);
 
+  if (redisplay_dont_pause)
+    force_p = 1;
+#if PERIODIC_PREEMPTION_CHECKING
+  else if (NILP (Vredisplay_preemption_period))
+    force_p = 1;
+  else if (!force_p && NUMBERP (Vredisplay_preemption_period))
+    {
+      EMACS_TIME tm;
+      double p = XFLOATINT (Vredisplay_preemption_period);
+      int sec, usec;
+
+      if (detect_input_pending_ignore_squeezables ())
+       {
+         paused_p = 1;
+         goto do_pause;
+       }
+
+      sec = (int) p;
+      usec = (p - sec) * 1000000;
+
+      EMACS_GET_TIME (tm);
+      EMACS_SET_SECS_USECS (preemption_period, sec, usec);
+      EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
+    }
+#endif
+
   if (FRAME_WINDOW_P (f))
     {
       /* We are working on window matrix basis.  All windows whose
@@ -3885,6 +3931,7 @@ update_frame (f, force_p, inhibit_hairy_id_p)
 #endif
     }
 
+ do_pause:
   /* Reset flags indicating that a window should be updated.  */
   set_window_update_flags (root_window, 0);
 
@@ -3939,6 +3986,26 @@ update_single_window (w, force_p)
       /* Record that this is not a frame-based redisplay.  */
       set_frame_matrix_frame (NULL);
 
+      if (redisplay_dont_pause)
+       force_p = 1;
+#if PERIODIC_PREEMPTION_CHECKING
+      else if (NILP (Vredisplay_preemption_period))
+       force_p = 1;
+      else if (!force_p && NUMBERP (Vredisplay_preemption_period))
+       {
+         EMACS_TIME tm;
+         double p = XFLOATINT (Vredisplay_preemption_period);
+         int sec, usec;
+
+         sec = (int) p;
+         usec = (p - sec) * 1000000;
+
+         EMACS_GET_TIME (tm);
+         EMACS_SET_SECS_USECS (preemption_period, sec, usec);
+         EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
+       }
+#endif
+
       /* Update W.  */
       update_begin (f);
       update_window (w, force_p);
@@ -3949,6 +4016,7 @@ update_single_window (w, force_p)
     }
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
 
 /* Redraw lines from the current matrix of window W that are
    overlapped by other rows.  YB is bottom-most y-position in W.  */
@@ -4021,23 +4089,33 @@ redraw_overlapping_rows (w, yb)
 
       if (row->overlapping_p && i > 0 && bottom_y < yb)
        {
-         if (row->used[LEFT_MARGIN_AREA])
-           rif->fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
-
-         if (row->used[TEXT_AREA])
-           rif->fix_overlapping_area (w, row, TEXT_AREA);
-
-         if (row->used[RIGHT_MARGIN_AREA])
-           rif->fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
-
-         /* Record in neighbour rows that ROW overwrites part of their
-            display.  */
-         if (row->phys_ascent > row->ascent && i > 0)
-           MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p = 1;
-         if ((row->phys_height - row->phys_ascent
-              > row->height - row->ascent)
-             && bottom_y < yb)
-           MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p = 1;
+         int overlaps = 0;
+
+         if (MATRIX_ROW_OVERLAPS_PRED_P (row)
+             && !MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p)
+           overlaps |= OVERLAPS_PRED;
+         if (MATRIX_ROW_OVERLAPS_SUCC_P (row)
+             && !MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p)
+           overlaps |= OVERLAPS_SUCC;
+
+         if (overlaps)
+           {
+             if (row->used[LEFT_MARGIN_AREA])
+               rif->fix_overlapping_area (w, row, LEFT_MARGIN_AREA, overlaps);
+
+             if (row->used[TEXT_AREA])
+               rif->fix_overlapping_area (w, row, TEXT_AREA, overlaps);
+
+             if (row->used[RIGHT_MARGIN_AREA])
+               rif->fix_overlapping_area (w, row, RIGHT_MARGIN_AREA, overlaps);
+
+             /* Record in neighbour rows that ROW overwrites part of
+                their display.  */
+             if (overlaps & OVERLAPS_PRED)
+               MATRIX_ROW (w->current_matrix, i - 1)->overlapped_p = 1;
+             if (overlaps & OVERLAPS_SUCC)
+               MATRIX_ROW (w->current_matrix, i + 1)->overlapped_p = 1;
+           }
        }
 
       if (bottom_y >= yb)
@@ -4045,6 +4123,8 @@ redraw_overlapping_rows (w, yb)
     }
 }
 
+#endif /* HAVE_WINDOW_SYSTEM */
+
 
 #ifdef GLYPH_DEBUG
 
@@ -4081,7 +4161,9 @@ update_window (w, force_p)
 {
   struct glyph_matrix *desired_matrix = w->desired_matrix;
   int paused_p;
+#if !PERIODIC_PREEMPTION_CHECKING
   int preempt_count = baud_rate / 2400 + 1;
+#endif
   extern int input_pending;
   extern Lisp_Object do_mouse_tracking;
 #if GLYPH_DEBUG
@@ -4091,10 +4173,10 @@ update_window (w, force_p)
 #endif
 
   /* Check pending input the first time so that we can quickly return.  */
-  if (redisplay_dont_pause)
-    force_p = 1;
-  else
+#if !PERIODIC_PREEMPTION_CHECKING
+  if (!force_p)
     detect_input_pending_ignore_squeezables ();
+#endif
 
   /* If forced to complete the update, or if no input is pending, do
      the update.  */
@@ -4129,7 +4211,6 @@ update_window (w, force_p)
          update_window_line (w, MATRIX_ROW_VPOS (mode_line_row,
                                                  desired_matrix),
                              &mouse_face_overwritten_p);
-         changed_p = 1;
        }
 
       /* Find first enabled row.  Optimizations in redisplay_internal
@@ -4167,9 +4248,23 @@ update_window (w, force_p)
               detect_input_pending.  If it's done too often,
               scrolling large windows with repeated scroll-up
               commands will too quickly pause redisplay.  */
+#if PERIODIC_PREEMPTION_CHECKING
+           if (!force_p)
+             {
+               EMACS_TIME tm, dif;
+               EMACS_GET_TIME (tm);
+               EMACS_SUB_TIME (dif, preemption_next_check, tm);
+               if (EMACS_TIME_NEG_P (dif))
+                 {
+                   EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
+                   if (detect_input_pending_ignore_squeezables ())
+                     break;
+                 }
+             }
+#else
            if (!force_p && ++n_updated % preempt_count == 0)
              detect_input_pending_ignore_squeezables ();
-
+#endif
            changed_p |= update_window_line (w, vpos,
                                             &mouse_face_overwritten_p);
 
@@ -4199,17 +4294,18 @@ update_window (w, force_p)
        {
          header_line_row->y = 0;
          update_window_line (w, 0, &mouse_face_overwritten_p);
-         changed_p = 1;
        }
 
       /* Fix the appearance of overlapping/overlapped rows.  */
       if (!paused_p && !w->pseudo_window_p)
        {
+#ifdef HAVE_WINDOW_SYSTEM
          if (changed_p && rif->fix_overlapping_area)
            {
              redraw_overlapped_rows (w, yb);
              redraw_overlapping_rows (w, yb);
            }
+#endif
 
          /* Make cursor visible at cursor position of W.  */
          set_window_cursor_after_update (w);
@@ -4298,7 +4394,14 @@ update_text_area (w, vpos)
       || desired_row->phys_height != current_row->phys_height
       || desired_row->visible_height != current_row->visible_height
       || current_row->overlapped_p
-      || current_row->mouse_face_p
+      /* This next line is necessary for correctly redrawing
+        mouse-face areas after scrolling and other operations.
+        However, it causes excessive flickering when mouse is moved
+        across the mode line.  Luckily, turning it off for the mode
+        line doesn't seem to hurt anything. -- cyd.
+         But it is still needed for the header line. -- kfs.  */
+      || (current_row->mouse_face_p
+         && !(current_row->mode_line_p && vpos > 0))
       || current_row->x != desired_row->x)
     {
       rif->cursor_to (vpos, 0, desired_row->y, desired_row->x);
@@ -4329,10 +4432,14 @@ update_text_area (w, vpos)
       int overlapping_glyphs_p = current_row->contains_overlapping_glyphs_p;
       int desired_stop_pos = desired_row->used[TEXT_AREA];
 
-      /* If the desired row extends its face to the text area end,
+      /* If the desired row extends its face to the text area end, and
+        unless the current row also does so at the same position,
         make sure we write at least one glyph, so that the face
         extension actually takes place.  */
-      if (MATRIX_ROW_EXTENDS_FACE_P (desired_row))
+      if (MATRIX_ROW_EXTENDS_FACE_P (desired_row)
+         && (desired_stop_pos < current_row->used[TEXT_AREA]
+             || (desired_stop_pos == current_row->used[TEXT_AREA]
+                 && !MATRIX_ROW_EXTENDS_FACE_P (current_row))))
        --desired_stop_pos;
 
       stop = min (current_row->used[TEXT_AREA], desired_stop_pos);
@@ -4451,7 +4558,10 @@ update_text_area (w, vpos)
             has to be cleared, if and only if we did a write_glyphs
             above.  This is made sure by setting desired_stop_pos
             appropriately above.  */
-         xassert (i < desired_row->used[TEXT_AREA]);
+         xassert (i < desired_row->used[TEXT_AREA]
+                  || ((desired_row->used[TEXT_AREA]
+                       == current_row->used[TEXT_AREA])
+                      && MATRIX_ROW_EXTENDS_FACE_P (current_row)));
        }
       else if (MATRIX_ROW_EXTENDS_FACE_P (current_row))
        {
@@ -5110,13 +5220,13 @@ update_frame_1 (f, force_p, inhibit_id_p)
   if (preempt_count <= 0)
     preempt_count = 1;
 
-  if (redisplay_dont_pause)
-    force_p = 1;
-  else if (!force_p && detect_input_pending_ignore_squeezables ())
+#if !PERIODIC_PREEMPTION_CHECKING
+  if (!force_p && detect_input_pending_ignore_squeezables ())
     {
       pause = 1;
       goto do_pause;
     }
+#endif
 
   /* If we cannot insert/delete lines, it's no use trying it.  */
   if (!line_ins_del_ok)
@@ -5167,8 +5277,23 @@ update_frame_1 (f, force_p, inhibit_id_p)
                }
            }
 
-         if ((i - 1) % preempt_count == 0)
+#if PERIODIC_PREEMPTION_CHECKING
+         if (!force_p)
+           {
+             EMACS_TIME tm, dif;
+             EMACS_GET_TIME (tm);
+             EMACS_SUB_TIME (dif, preemption_next_check, tm);
+             if (EMACS_TIME_NEG_P (dif))
+               {
+                 EMACS_ADD_TIME (preemption_next_check, tm, preemption_period);
+                 if (detect_input_pending_ignore_squeezables ())
+                   break;
+               }
+           }
+#else
+         if (!force_p && (i - 1) % preempt_count == 0)
            detect_input_pending_ignore_squeezables ();
+#endif
 
          update_frame_line (f, i);
        }
@@ -6360,85 +6485,86 @@ Emacs was built without floating point support.
 
 
 /* This is just like wait_reading_process_output, except that
-   it does the redisplay.
+   it does redisplay.
 
-   It's also much like Fsit_for, except that it can be used for
-   waiting for input as well.  */
+   TIMEOUT is number of seconds to wait (float or integer),
+   or t to wait forever.
+   READING is 1 if reading input.
+   If DO_DISPLAY is >0 display process output while waiting.
+   If DO_DISPLAY is >1 perform an initial redisplay before waiting.
+*/
 
 Lisp_Object
-sit_for (sec, usec, reading, display, initial_display)
-     int sec, usec, reading, display, initial_display;
+sit_for (timeout, reading, do_display)
+     Lisp_Object timeout;
+     int reading, do_display;
 {
-  swallow_events (display);
+  int sec, usec;
+
+  swallow_events (do_display);
 
-  if (detect_input_pending_run_timers (display) || !NILP (Vexecuting_kbd_macro))
+  if ((detect_input_pending_run_timers (do_display))
+      || !NILP (Vexecuting_kbd_macro))
     return Qnil;
 
-  if (initial_display)
+  if (do_display >= 2)
     redisplay_preserve_echo_area (2);
 
-  if (sec == 0 && usec == 0)
+  if (INTEGERP (timeout))
+    {
+      sec = XINT (timeout);
+      usec = 0;
+    }
+  else if (FLOATP (timeout))
+    {
+      double seconds = XFLOAT_DATA (timeout);
+      sec = (int) seconds;
+      usec = (int) ((seconds - sec) * 1000000);
+    }
+  else if (EQ (timeout, Qt))
+    {
+      sec = 0;
+      usec = 0;
+    }
+  else
+    wrong_type_argument (Qnumberp, timeout);
+
+  if (sec == 0 && usec == 0 && !EQ (timeout, Qt))
     return Qt;
 
 #ifdef SIGIO
   gobble_input (0);
 #endif
 
-  wait_reading_process_output (sec, usec, reading ? -1 : 1, display,
+  wait_reading_process_output (sec, usec, reading ? -1 : 1, do_display,
                               Qnil, NULL, 0);
 
   return detect_input_pending () ? Qnil : Qt;
 }
 
 
-DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 3, 0,
-       doc: /* Perform redisplay, then wait for SECONDS seconds or until input is available.
-SECONDS may be a floating-point value, meaning that you can wait for a
-fraction of a second.
-\(Not all operating systems support waiting for a fraction of a second.)
-Optional arg NODISP non-nil means don't redisplay, just wait for input.
-Redisplay is preempted as always if input arrives, and does not happen
-if input is available before it starts.
-Value is t if waited the full time with no input arriving.
-
-An obsolete but still supported form is
-\(sit-for SECONDS &optional MILLISECONDS NODISP)
-Where the optional arg MILLISECONDS specifies an additional wait period,
-in milliseconds; this was useful when Emacs was built without
-floating point support.
-usage: (sit-for SECONDS &optional NODISP OLD-NODISP) */)
-
-/* The `old-nodisp' stuff is there so that the arglist has the correct
-   length.  Otherwise, `defdvice' will redefine it with fewer args.  */
-     (seconds, milliseconds, nodisp)
-     Lisp_Object seconds, milliseconds, nodisp;
+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.  */)
+     (force)
+  Lisp_Object force;
 {
-  int sec, usec;
-
-  if (NILP (nodisp) && !NUMBERP (milliseconds))
-    { /* New style.  */
-      nodisp = milliseconds;
-      milliseconds = Qnil;
-    }
+  int count;
 
-  if (NILP (milliseconds))
-    XSETINT (milliseconds, 0);
-  else
-    CHECK_NUMBER (milliseconds);
-  usec = XINT (milliseconds) * 1000;
-
-  {
-    double duration = extract_float (seconds);
-    sec = (int) duration;
-    usec += (duration - sec) * 1000000;
-  }
-
-#ifndef EMACS_HAS_USECS
-  if (usec != 0 && sec == 0)
-    error ("Millisecond `sit-for' not supported on %s", SYSTEM_TYPE);
-#endif
+  swallow_events (1);
+  if ((detect_input_pending_run_timers (1)
+       && NILP (force) && !redisplay_dont_pause)
+      || !NILP (Vexecuting_kbd_macro))
+    return Qnil;
 
-  return sit_for (sec, usec, 0, NILP (nodisp), NILP (nodisp));
+  count = SPECPDL_INDEX ();
+  if (!NILP (force) && !redisplay_dont_pause)
+    specbind (Qredisplay_dont_pause, Qt);
+  redisplay_preserve_echo_area (2);
+  unbind_to (count, Qnil);
+  return Qt;
 }
 
 
@@ -6618,7 +6744,7 @@ init_display ()
      try to use X, and die with an error message if that doesn't work.  */
 
 #ifdef HAVE_X_WINDOWS
-  if (! display_arg)
+  if (! inhibit_window_system && ! display_arg)
     {
       char *display;
 #ifdef VMS
@@ -6628,6 +6754,13 @@ init_display ()
 #endif
 
       display_arg = (display != 0 && *display != 0);
+
+      if (display_arg && !x_display_ok (display))
+       {
+         fprintf (stderr, "Display %s unavailable, simulating -nw\n",
+                  display);
+         inhibit_window_system = 1;
+       }
     }
 
   if (!inhibit_window_system && display_arg
@@ -6689,9 +6822,15 @@ init_display ()
 For types defined in VMS, use  set term /device=TYPE.\n\
 For types not defined in VMS, use  define emacs_term \"TYPE\".\n\
 \(The quotation marks are necessary since terminal types are lower case.)\n");
-#else
-      fprintf (stderr, "Please set the environment variable TERM; see tset(1).\n");
-#endif
+#else /* not VMS */
+
+#ifdef HAVE_WINDOW_SYSTEM
+      if (! inhibit_window_system)
+       fprintf (stderr, "Please set the environment variable DISPLAY or TERM (see `tset').\n");
+      else
+#endif /* HAVE_WINDOW_SYSTEM */
+       fprintf (stderr, "Please set the environment variable TERM; see `tset'.\n");
+#endif /* not VMS */
       exit (1);
     }
 
@@ -6821,7 +6960,7 @@ syms_of_display ()
   defsubr (&Sframe_or_buffer_changed_p);
   defsubr (&Sopen_termscript);
   defsubr (&Sding);
-  defsubr (&Ssit_for);
+  defsubr (&Sredisplay);
   defsubr (&Ssleep_for);
   defsubr (&Ssend_string_to_terminal);
   defsubr (&Sinternal_show_cursor);
@@ -6891,7 +7030,14 @@ See `buffer-display-table' for more information.  */);
               doc: /* *Non-nil means update isn't paused when input is detected.  */);
   redisplay_dont_pause = 0;
 
-  /* Initialize `window-system', unless init_display already decided it.  */
+#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.  */);
+  Vredisplay_preemption_period = make_float (0.10);
+#endif
+
 #ifdef CANNOT_DUMP
   if (noninteractive)
 #endif