X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/5f81871efe4ff488329685bbf65ab81db9c92768..e5803d84f59034cb37a36f21bd7b3bc370437c8e:/src/dispnew.c diff --git a/src/dispnew.c b/src/dispnew.c index 727547d089..d2c63687dd 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1,6 +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. + Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, + 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,8 +17,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include #include @@ -191,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. */ @@ -354,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)); - - + /* 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 @@ -1184,6 +1206,9 @@ increment_row_positions (row, delta, delta_bytes) MATRIX_ROW_END_CHARPOS (row) += delta; MATRIX_ROW_END_BYTEPOS (row) += delta_bytes; + if (!row->enabled_p) + return; + /* Increment positions in glyphs. */ for (area = 0; area < LAST_AREA; ++area) for (i = 0; i < row->used[area]; ++i) @@ -1772,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 @@ -2024,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) @@ -2258,7 +2280,6 @@ static void adjust_frame_glyphs_for_frame_redisplay (f) struct frame *f; { - struct dim ch_dim; struct dim matrix_dim; int pool_changed_p; int window_change_flags; @@ -2267,10 +2288,6 @@ adjust_frame_glyphs_for_frame_redisplay (f) if (!FRAME_LIVE_P (f)) return; - /* Determine the smallest character in any font for F. On - console windows, all characters have dimension (1, 1). */ - ch_dim.width = ch_dim.height = 1; - top_window_y = FRAME_TOP_MARGIN (f); /* Allocate glyph pool structures if not already done. */ @@ -2359,22 +2376,14 @@ static void adjust_frame_glyphs_for_window_redisplay (f) struct frame *f; { - struct dim ch_dim; struct window *w; xassert (FRAME_WINDOW_P (f) && FRAME_LIVE_P (f)); - /* Get minimum sizes. */ -#ifdef HAVE_WINDOW_SYSTEM - ch_dim.width = FRAME_SMALLEST_CHAR_WIDTH (f); - ch_dim.height = FRAME_SMALLEST_FONT_HEIGHT (f); -#else - ch_dim.width = ch_dim.height = 1; -#endif - /* 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) @@ -2398,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 @@ -2719,10 +2729,15 @@ build_frame_matrix_from_leaf_window (frame_matrix, w) if (!WINDOW_RIGHTMOST_P (w)) { struct Lisp_Char_Table *dp = window_display_table (w); - right_border_glyph = (dp && INTEGERP (DISP_BORDER_GLYPH (dp)) - ? XINT (DISP_BORDER_GLYPH (dp)) - : '|'); - right_border_glyph = spec_glyph_lookup_face (w, right_border_glyph); + + right_border_glyph + = ((dp && INTEGERP (DISP_BORDER_GLYPH (dp))) + ? spec_glyph_lookup_face (w, XINT (DISP_BORDER_GLYPH (dp))) + : '|'); + + if (FAST_GLYPH_FACE (right_border_glyph) <= 0) + right_border_glyph + = FAST_MAKE_GLYPH (right_border_glyph, VERTICAL_BORDER_FACE_ID); } } else @@ -3315,9 +3330,7 @@ window_to_frame_hpos (w, hpos) struct window *w; int hpos; { - struct frame *f = XFRAME (w->frame); - - xassert (!FRAME_WINDOW_P (f)); + xassert (!FRAME_WINDOW_P (XFRAME (w->frame))); hpos += WINDOW_LEFT_EDGE_COL (w); return hpos; } @@ -3814,6 +3827,28 @@ update_frame (f, force_p, inhibit_hairy_id_p) int paused_p; struct window *root_window = XWINDOW (f->root_window); +#if PERIODIC_PREEMPTION_CHECKING + 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 @@ -3892,6 +3927,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); @@ -3946,6 +3982,22 @@ update_single_window (w, force_p) /* Record that this is not a frame-based redisplay. */ set_frame_matrix_frame (NULL); +#if PERIODIC_PREEMPTION_CHECKING + 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); @@ -3956,6 +4008,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. */ @@ -4028,23 +4081,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) @@ -4052,6 +4115,8 @@ redraw_overlapping_rows (w, yb) } } +#endif /* HAVE_WINDOW_SYSTEM */ + #ifdef GLYPH_DEBUG @@ -4088,22 +4153,27 @@ 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 - struct frame *f = XFRAME (WINDOW_FRAME (w)); - /* Check that W's frame doesn't have glyph matrices. */ - xassert (FRAME_WINDOW_P (f)); + xassert (FRAME_WINDOW_P (XFRAME (WINDOW_FRAME (w)))); xassert (updating_frame != NULL); #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 + else if (NILP (Vredisplay_preemption_period)) + force_p = 1; +#else + else if (!force_p) detect_input_pending_ignore_squeezables (); +#endif /* If forced to complete the update, or if no input is pending, do the update. */ @@ -4138,7 +4208,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 @@ -4176,9 +4245,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); @@ -4208,17 +4291,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); @@ -4307,7 +4391,12 @@ 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 +#if 0 + /* This causes excessive flickering when mouse is moved across + the mode line. Luckily everything seems to work just fine + without doing this. KFS 2006-09-17. */ || current_row->mouse_face_p +#endif || current_row->x != desired_row->x) { rif->cursor_to (vpos, 0, desired_row->y, desired_row->x); @@ -4338,10 +4427,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); @@ -4460,7 +4553,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)) { @@ -5121,11 +5217,16 @@ update_frame_1 (f, force_p, inhibit_id_p) if (redisplay_dont_pause) force_p = 1; +#if PERIODIC_PREEMPTION_CHECKING + else if (NILP (Vredisplay_preemption_period)) + force_p = 1; +#else else 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) @@ -5176,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); } @@ -5792,8 +5908,9 @@ buffer_posn_from_coords (w, x, y, pos, object, dx, dy, width, height) } #endif - row = MATRIX_ROW (w->current_matrix, it.vpos); - if (row->enabled_p) + if (it.vpos < w->current_matrix->nrows + && (row = MATRIX_ROW (w->current_matrix, it.vpos), + row->enabled_p)) { if (it.hpos < row->used[TEXT_AREA]) { @@ -6343,7 +6460,7 @@ Emacs was built without floating point support. #ifndef EMACS_HAS_USECS if (sec == 0 && usec != 0) - error ("millisecond `sleep-for' not supported on %s", SYSTEM_TYPE); + error ("Millisecond `sleep-for' not supported on %s", SYSTEM_TYPE); #endif /* Assure that 0 <= usec < 1000000. */ @@ -6368,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; - } - - if (NILP (milliseconds)) - XSETINT (milliseconds, 0); - else - CHECK_NUMBER (milliseconds); - usec = XINT (milliseconds) * 1000; + int count; - { - 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; } @@ -6457,68 +6575,106 @@ usage: (sit-for SECONDS &optional NODISP OLD-NODISP) */) /* A vector of size >= 2 * NFRAMES + 3 * NBUFFERS + 1, containing the session's frames, frame names, buffers, buffer-read-only flags, and - buffer-modified-flags, and a trailing sentinel (so we don't need to - add length checks). */ + buffer-modified-flags. */ static Lisp_Object frame_and_buffer_state; DEFUN ("frame-or-buffer-changed-p", Fframe_or_buffer_changed_p, - Sframe_or_buffer_changed_p, 0, 0, 0, + Sframe_or_buffer_changed_p, 0, 1, 0, doc: /* Return non-nil if the frame and buffer state appears to have changed. -The state variable is an internal vector containing all frames and buffers, +VARIABLE is a variable name whose value is either nil or a state vector +that will be updated to contain all frames and buffers, aside from buffers whose names start with space, -along with the buffers' read-only and modified flags, which allows a fast -check to see whether the menu bars might need to be recomputed. +along with the buffers' read-only and modified flags. This allows a fast +check to see whether buffer menus might need to be recomputed. If this function returns non-nil, it updates the internal vector to reflect -the current state. */) - () +the current state. + +If VARIABLE is nil, an internal variable is used. Users should not +pass nil for VARIABLE. */) + (variable) + Lisp_Object variable; { - Lisp_Object tail, frame, buf; - Lisp_Object *vecp; + Lisp_Object state, tail, frame, buf; + Lisp_Object *vecp, *end; int n; - vecp = XVECTOR (frame_and_buffer_state)->contents; + if (! NILP (variable)) + { + CHECK_SYMBOL (variable); + state = Fsymbol_value (variable); + if (! VECTORP (state)) + goto changed; + } + else + state = frame_and_buffer_state; + + vecp = XVECTOR (state)->contents; + end = vecp + XVECTOR (state)->size; + FOR_EACH_FRAME (tail, frame) { + if (vecp == end) + goto changed; if (!EQ (*vecp++, frame)) goto changed; + if (vecp == end) + goto changed; if (!EQ (*vecp++, XFRAME (frame)->name)) goto changed; } - /* Check that the buffer info matches. - No need to test for the end of the vector - because the last element of the vector is lambda - and that will always cause a mismatch. */ + /* Check that the buffer info matches. */ for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail)) { buf = XCDR (XCAR (tail)); /* Ignore buffers that aren't included in buffer lists. */ if (SREF (XBUFFER (buf)->name, 0) == ' ') continue; + if (vecp == end) + goto changed; if (!EQ (*vecp++, buf)) goto changed; + if (vecp == end) + goto changed; if (!EQ (*vecp++, XBUFFER (buf)->read_only)) goto changed; + if (vecp == end) + goto changed; if (!EQ (*vecp++, Fbuffer_modified_p (buf))) goto changed; } + if (vecp == end) + goto changed; /* Detect deletion of a buffer at the end of the list. */ if (EQ (*vecp, Qlambda)) return Qnil; + + /* Come here if we decide the data has changed. */ changed: - /* Start with 1 so there is room for at least one lambda at the end. */ + /* Count the size we will need. + Start with 1 so there is room for at least one lambda at the end. */ n = 1; FOR_EACH_FRAME (tail, frame) n += 2; for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail)) n += 3; - /* Reallocate the vector if it's grown, or if it's shrunk a lot. */ - if (n > XVECTOR (frame_and_buffer_state)->size - || n + 20 < XVECTOR (frame_and_buffer_state)->size / 2) + /* Reallocate the vector if data has grown to need it, + or if it has shrunk a lot. */ + if (! VECTORP (state) + || n > XVECTOR (state)->size + || n + 20 < XVECTOR (state)->size / 2) /* Add 20 extra so we grow it less often. */ - frame_and_buffer_state = Fmake_vector (make_number (n + 20), Qlambda); - vecp = XVECTOR (frame_and_buffer_state)->contents; + { + state = Fmake_vector (make_number (n + 20), Qlambda); + if (! NILP (variable)) + Fset (variable, state); + else + frame_and_buffer_state = state; + } + + /* Record the new data in the (possibly reallocated) vector. */ + vecp = XVECTOR (state)->contents; FOR_EACH_FRAME (tail, frame) { *vecp++ = frame; @@ -6536,12 +6692,12 @@ the current state. */) } /* Fill up the vector with lambdas (always at least one). */ *vecp++ = Qlambda; - while (vecp - XVECTOR (frame_and_buffer_state)->contents - < XVECTOR (frame_and_buffer_state)->size) + while (vecp - XVECTOR (state)->contents + < XVECTOR (state)->size) *vecp++ = Qlambda; /* Make sure we didn't overflow the vector. */ - if (vecp - XVECTOR (frame_and_buffer_state)->contents - > XVECTOR (frame_and_buffer_state)->size) + if (vecp - XVECTOR (state)->contents + > XVECTOR (state)->size) abort (); return Qt; } @@ -6588,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 @@ -6598,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 @@ -6659,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); } @@ -6791,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); @@ -6861,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