X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/f84d8a709ac1d19d7ca31f43ba3442d90fe55f07..e5803d84f59034cb37a36f21bd7b3bc370437c8e:/src/dispnew.c diff --git a/src/dispnew.c b/src/dispnew.c index 3cfd97ea3e..d2c63687dd 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1,6 +1,7 @@ /* Updating of data structures for redisplay. - Copyright (C) 1985,86,87,88,93,94,95,97,98,1999,2000,01,02,2003 - 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 @@ -625,20 +647,23 @@ adjust_glyph_matrix (w, matrix, x, y, dim) int left = -1, right = -1; int window_width = -1, window_height; - /* See if W had a header line that has disappeared now, or vice versa. */ + /* See if W had a header line that has disappeared now, or vice versa. + Get W's size. */ if (w) { + window_box (w, -1, 0, 0, &window_width, &window_height); + header_line_p = WINDOW_WANTS_HEADER_LINE_P (w); header_line_changed_p = header_line_p != matrix->header_line_p; } matrix->header_line_p = header_line_p; - /* Do nothing if MATRIX' size, position, vscroll, and marginal areas + /* If POOL is null, MATRIX is a window matrix for window-based redisplay. + Do nothing if MATRIX' size, position, vscroll, and marginal areas haven't changed. This optimization is important because preserving the matrix means preventing redisplay. */ if (matrix->pool == NULL) { - window_box (w, -1, 0, 0, &window_width, &window_height); left = margin_glyphs_to_reserve (w, dim.width, w->left_margin_cols); right = margin_glyphs_to_reserve (w, dim.width, w->right_margin_cols); xassert (left >= 0 && right >= 0); @@ -723,7 +748,8 @@ adjust_glyph_matrix (w, matrix, x, y, dim) else { /* If MATRIX->pool is null, MATRIX is responsible for managing - its own memory. Allocate glyph memory from the heap. */ + its own memory. It is a window matrix for window-based redisplay. + Allocate glyph memory from the heap. */ if (dim.width > matrix->matrix_w || new_rows || header_line_changed_p @@ -1180,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) @@ -1509,12 +1538,14 @@ row_equal_p (w, a, b, mouse_face_p) return 0; } - if (a->truncated_on_left_p != b->truncated_on_left_p - || a->fill_line_p != b->fill_line_p - || a->truncated_on_right_p != b->truncated_on_right_p - || a->overlay_arrow_p != b->overlay_arrow_p - || a->continued_p != b->continued_p - || a->indicate_empty_line_p != b->indicate_empty_line_p + if (a->fill_line_p != b->fill_line_p + || a->cursor_in_fringe_p != b->cursor_in_fringe_p + || a->left_fringe_bitmap != b->left_fringe_bitmap + || a->left_fringe_face_id != b->left_fringe_face_id + || a->right_fringe_bitmap != b->right_fringe_bitmap + || a->right_fringe_face_id != b->right_fringe_face_id + || a->overlay_arrow_bitmap != b->overlay_arrow_bitmap + || a->exact_window_width_line_p != b->exact_window_width_line_p || a->overlapped_p != b->overlapped_p || (MATRIX_ROW_CONTINUATION_LINE_P (a) != MATRIX_ROW_CONTINUATION_LINE_P (b)) @@ -1766,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 @@ -1905,10 +1934,10 @@ allocate_matrices_for_frame_redisplay (window, x, y, dim_only_p, || dim.width != w->desired_matrix->matrix_w || dim.height != w->desired_matrix->matrix_h || (margin_glyphs_to_reserve (w, dim.width, - w->right_margin_cols) + w->left_margin_cols) != w->desired_matrix->left_margin_glyphs) || (margin_glyphs_to_reserve (w, dim.width, - w->left_margin_cols) + w->right_margin_cols) != w->desired_matrix->right_margin_glyphs)) *window_change_flags |= CHANGED_LEAF_MATRIX; @@ -1976,7 +2005,7 @@ required_matrix_height (w) int ch_height = FRAME_SMALLEST_FONT_HEIGHT (f); int window_pixel_height = window_box_height (w) + abs (w->vscroll); return (((window_pixel_height + ch_height - 1) - / ch_height) + / ch_height) * w->nrows_scale_factor /* One partially visible line at the top and bottom of the window. */ + 2 @@ -2004,7 +2033,7 @@ required_matrix_width (w) /* Compute number of glyphs needed in a glyph row. */ return (((window_pixel_width + ch_width - 1) - / ch_width) + / ch_width) * w->ncols_scale_factor /* 2 partially visible columns in the text area. */ + 2 /* One partially visible column at the right @@ -2018,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) @@ -2252,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; @@ -2261,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. */ @@ -2353,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) @@ -2392,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 @@ -2713,9 +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 + = ((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 @@ -2771,6 +2793,7 @@ build_frame_matrix_from_leaf_window (frame_matrix, w) SET_CHAR_GLYPH_FROM_GLYPH (*border, right_border_glyph); } +#if GLYPH_DEBUG /* Window row window_y must be a slice of frame row frame_y. */ xassert (glyph_row_slice_p (window_row, frame_row)); @@ -2778,7 +2801,6 @@ build_frame_matrix_from_leaf_window (frame_matrix, w) /* If rows are in sync, we don't have to copy glyphs because frame and window share glyphs. */ -#if GLYPH_DEBUG strcpy (w->current_matrix->method, w->desired_matrix->method); add_window_display_history (w, w->current_matrix->method, 0); #endif @@ -2796,6 +2818,27 @@ build_frame_matrix_from_leaf_window (frame_matrix, w) } } +/* Given a user-specified glyph, possibly including a Lisp-level face + ID, return a glyph that has a realized face ID. + This is used for glyphs displayed specially and not part of the text; + for instance, vertical separators, truncation markers, etc. */ + +GLYPH +spec_glyph_lookup_face (w, glyph) + struct window *w; + GLYPH glyph; +{ + int lface_id = FAST_GLYPH_FACE (glyph); + /* Convert the glyph's specified face to a realized (cache) face. */ + if (lface_id > 0) + { + int face_id = merge_faces (XFRAME (w->frame), + Qt, lface_id, DEFAULT_FACE_ID); + glyph + = FAST_MAKE_GLYPH (FAST_GLYPH_CHAR (glyph), face_id); + } + return glyph; +} /* Add spaces to a glyph row ROW in a window matrix. @@ -3158,15 +3201,21 @@ mirror_line_dance (w, unchanged_at_top, nlines, copy_from, retained_p) struct glyph_matrix *m2; int m2_from; - w2 = frame_row_to_window (root, frame_to); - m2 = w2->current_matrix; - m2_from = frame_from - m2->matrix_y; - copy_row_except_pointers (m->rows + window_to, - m2->rows + m2_from); - - /* If frame line is empty, window line is empty, too. */ - if (!retained_p[copy_from[i]]) - m->rows[window_to].enabled_p = 0; + w2 = frame_row_to_window (root, frame_from); + /* ttn@surf.glug.org: when enabling menu bar using `emacs + -nw', FROM_FRAME sometimes has no associated window. + This check avoids a segfault if W2 is null. */ + if (w2) + { + m2 = w2->current_matrix; + m2_from = frame_from - m2->matrix_y; + copy_row_except_pointers (m->rows + window_to, + m2->rows + m2_from); + + /* If frame line is empty, window line is empty, too. */ + if (!retained_p[copy_from[i]]) + m->rows[window_to].enabled_p = 0; + } sync_p = 1; } else if (from_inside_window_p) @@ -3281,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; } @@ -3446,6 +3493,7 @@ direct_output_for_insert (g) /* Can't do it in a continued line because continuation lines would change. */ (glyph_row->continued_p + || glyph_row->exact_window_width_line_p /* Can't use this method if the line overlaps others or is overlapped by others because these other lines would have to be redisplayed. */ @@ -3651,6 +3699,10 @@ direct_output_for_insert (g) cursor_to (y, x); } +#ifdef HAVE_WINDOW_SYSTEM + update_window_fringes (w, 0); +#endif + if (rif) rif->update_window_end_hook (w, 1, 0); update_end (f); @@ -3775,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 @@ -3818,10 +3892,15 @@ update_frame (f, force_p, inhibit_hairy_id_p) paused_p = update_window_tree (root_window, force_p); update_end (f); -#if 0 /* This flush is a performance bottleneck under X, - and it doesn't seem to be necessary anyway. */ - rif->flush_display (f); -#endif + /* This flush is a performance bottleneck under X, + and it doesn't seem to be necessary anyway (in general). + It is necessary when resizing the window with the mouse, or + at least the fringes are not redrawn in a timely manner. ++kfs */ + if (f->force_flush_display_p) + { + rif->flush_display (f); + f->force_flush_display_p = 0; + } } else { @@ -3848,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); @@ -3902,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); @@ -3912,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. */ @@ -3984,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) @@ -4008,6 +4115,8 @@ redraw_overlapping_rows (w, yb) } } +#endif /* HAVE_WINDOW_SYSTEM */ + #ifdef GLYPH_DEBUG @@ -4044,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)); -#endif - /* 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 - detect_input_pending (); +#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. */ @@ -4094,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 @@ -4114,19 +4227,11 @@ update_window (w, force_p) goto set_cursor; } else if (rc > 0) - /* We've scrolled the display. */ - force_p = 1; - changed_p = 1; - } - - /* Update the header line after scrolling because a new header - line would otherwise overwrite lines at the top of the window - that can be scrolled. */ - if (header_line_row && header_line_row->enabled_p) - { - header_line_row->y = 0; - update_window_line (w, 0, &mouse_face_overwritten_p); - changed_p = 1; + { + /* We've scrolled the display. */ + force_p = 1; + changed_p = 1; + } } /* Update the rest of the lines. */ @@ -4140,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 (); - + detect_input_pending_ignore_squeezables (); +#endif changed_p |= update_window_line (w, vpos, &mouse_face_overwritten_p); @@ -4165,14 +4284,25 @@ update_window (w, force_p) set_cursor: + /* Update the header line after scrolling because a new header + line would otherwise overwrite lines at the top of the window + that can be scrolled. */ + if (header_line_row && header_line_row->enabled_p) + { + header_line_row->y = 0; + update_window_line (w, 0, &mouse_face_overwritten_p); + } + /* 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); @@ -4188,6 +4318,10 @@ update_window (w, force_p) strcpy (w->current_matrix->method, w->desired_matrix->method); #endif +#ifdef HAVE_WINDOW_SYSTEM + update_window_fringes (w, 0); +#endif + /* End the update of window W. Don't set the cursor if we paused updating the display because in this case, set_window_cursor_after_update hasn't been called, and @@ -4257,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); @@ -4288,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); @@ -4410,14 +4553,17 @@ 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)) { /* If old row extends to the end of the text area, clear. */ if (i >= desired_row->used[TEXT_AREA]) rif->cursor_to (vpos, i, desired_row->y, - desired_row->x + desired_row->pixel_width); + desired_row->pixel_width); rif->clear_end_of_line (-1); changed_p = 1; } @@ -4429,7 +4575,7 @@ update_text_area (w, vpos) if (i >= desired_row->used[TEXT_AREA]) rif->cursor_to (vpos, i, desired_row->y, - desired_row->x + desired_row->pixel_width); + desired_row->pixel_width); /* If cursor is displayed at the end of the line, make sure it's cleared. Nowadays we don't have a phys_cursor_glyph @@ -4443,7 +4589,7 @@ update_text_area (w, vpos) x = -1; } else - x = current_row->x + current_row->pixel_width; + x = current_row->pixel_width; rif->clear_end_of_line (x); changed_p = 1; } @@ -4506,13 +4652,11 @@ update_window_line (w, vpos, mouse_face_overwritten_p) if (!current_row->enabled_p || desired_row->y != current_row->y || desired_row->visible_height != current_row->visible_height - || desired_row->overlay_arrow_p != current_row->overlay_arrow_p - || desired_row->truncated_on_left_p != current_row->truncated_on_left_p - || desired_row->truncated_on_right_p != current_row->truncated_on_right_p - || desired_row->continued_p != current_row->continued_p + || desired_row->cursor_in_fringe_p != current_row->cursor_in_fringe_p + || desired_row->overlay_arrow_bitmap != current_row->overlay_arrow_bitmap + || current_row->redraw_fringe_bitmaps_p || desired_row->mode_line_p != current_row->mode_line_p - || (desired_row->indicate_empty_line_p - != current_row->indicate_empty_line_p) + || desired_row->exact_window_width_line_p != current_row->exact_window_width_line_p || (MATRIX_ROW_CONTINUATION_LINE_P (desired_row) != MATRIX_ROW_CONTINUATION_LINE_P (current_row))) rif->after_update_window_line_hook (desired_row); @@ -4765,6 +4909,7 @@ scrolling_window (w, header_line_p) if (c->enabled_p && d->enabled_p + && !d->redraw_fringe_bitmaps_p && c->y == d->y && MATRIX_ROW_BOTTOM_Y (c) <= yb && MATRIX_ROW_BOTTOM_Y (d) <= yb @@ -4820,6 +4965,7 @@ scrolling_window (w, header_line_p) && 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 && row_equal_p (w, MATRIX_ROW (desired_matrix, i - 1), MATRIX_ROW (current_matrix, j - 1), 1)) @@ -5012,6 +5158,13 @@ scrolling_window (w, header_line_p) to = MATRIX_ROW (current_matrix, r->desired_vpos + j); from = MATRIX_ROW (desired_matrix, r->desired_vpos + j); to_overlapped_p = to->overlapped_p; + if (!from->mode_line_p && !w->pseudo_window_p + && (to->left_fringe_bitmap != from->left_fringe_bitmap + || to->right_fringe_bitmap != from->right_fringe_bitmap + || to->left_fringe_face_id != from->left_fringe_face_id + || to->right_fringe_face_id != from->right_fringe_face_id + || to->overlay_arrow_bitmap != from->overlay_arrow_bitmap)) + from->redraw_fringe_bitmaps_p = 1; assign_row (to, from); to->enabled_p = 1, from->enabled_p = 0; to->overlapped_p = to_overlapped_p; @@ -5022,8 +5175,8 @@ scrolling_window (w, header_line_p) for (i = 0; i < row_entry_idx; ++i) row_table[row_entry_pool[i].bucket] = NULL; - /* Value is non-zero to indicate that we scrolled the display. */ - return 1; + /* Value is > 0 to indicate that we scrolled the display. */ + return nruns; } @@ -5064,11 +5217,16 @@ update_frame_1 (f, force_p, inhibit_id_p) if (redisplay_dont_pause) force_p = 1; - else if (!force_p && detect_input_pending ()) +#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) @@ -5119,8 +5277,23 @@ update_frame_1 (f, force_p, inhibit_id_p) } } - if ((i - 1) % preempt_count == 0) - detect_input_pending (); +#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); } @@ -5683,21 +5856,28 @@ update_frame_line (f, vpos) ***********************************************************************/ /* Determine what's under window-relative pixel position (*X, *Y). - Return in *OBJECT the object (string or buffer) that's there. - Return in *POS the position in that object. Adjust *X and *Y - to character boundaries. */ + Return the object (string or buffer) that's there. + Return in *POS the position in that object. + Adjust *X and *Y to character positions. */ -void -buffer_posn_from_coords (w, x, y, object, pos) +Lisp_Object +buffer_posn_from_coords (w, x, y, pos, object, dx, dy, width, height) struct window *w; int *x, *y; - Lisp_Object *object; struct display_pos *pos; + Lisp_Object *object; + int *dx, *dy; + int *width, *height; { struct it it; struct buffer *old_current_buffer = current_buffer; struct text_pos startp; - int left_area_width; + Lisp_Object string; + struct glyph_row *row; +#ifdef HAVE_WINDOW_SYSTEM + struct image *img = 0; +#endif + int x0, x1; current_buffer = XBUFFER (w->buffer); SET_TEXT_POS_FROM_MARKER (startp, w->start); @@ -5705,40 +5885,101 @@ buffer_posn_from_coords (w, x, y, object, pos) BYTEPOS (startp) = min (ZV_BYTE, max (BEGV_BYTE, BYTEPOS (startp))); start_display (&it, w, startp); - left_area_width = WINDOW_LEFT_MARGIN_WIDTH (w); - move_it_to (&it, -1, *x + it.first_visible_x - left_area_width, *y, -1, + x0 = *x - WINDOW_LEFT_MARGIN_WIDTH (w); + move_it_to (&it, -1, x0 + it.first_visible_x, *y, -1, MOVE_TO_X | MOVE_TO_Y); - *x = it.current_x - it.first_visible_x + left_area_width; - *y = it.current_y; current_buffer = old_current_buffer; - *object = STRINGP (it.string) ? it.string : w->buffer; + *dx = x0 + it.first_visible_x - it.current_x; + *dy = *y - it.current_y; + + string = w->buffer; + if (STRINGP (it.string)) + string = it.string; *pos = it.current; + +#ifdef HAVE_WINDOW_SYSTEM + if (it.what == IT_IMAGE) + { + if ((img = IMAGE_FROM_ID (it.f, it.image_id)) != NULL + && !NILP (img->spec)) + *object = img->spec; + } +#endif + + 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]) + { + struct glyph *glyph = row->glyphs[TEXT_AREA] + it.hpos; +#ifdef HAVE_WINDOW_SYSTEM + if (img) + { + *dy -= row->ascent - glyph->ascent; + *dx += glyph->slice.x; + *dy += glyph->slice.y; + /* Image slices positions are still relative to the entire image */ + *width = img->width; + *height = img->height; + } + else +#endif + { + *width = glyph->pixel_width; + *height = glyph->ascent + glyph->descent; + } + } + else + { + *width = 0; + *height = row->height; + } + } + else + { + *width = *height = 0; + } + + /* Add extra (default width) columns if clicked after EOL. */ + x1 = max(0, it.current_x + it.pixel_width - it.first_visible_x); + if (x0 > x1) + it.hpos += (x0 - x1) / WINDOW_FRAME_COLUMN_WIDTH (w); + + *x = it.hpos; + *y = it.vpos; + + return string; } /* Value is the string under window-relative coordinates X/Y in the - mode or header line of window W, or nil if none. MODE_LINE_P non-zero - means look at the mode line. *CHARPOS is set to the position in - the string returned. */ + mode line or header line (PART says which) of window W, or nil if none. + *CHARPOS is set to the position in the string returned. */ Lisp_Object -mode_line_string (w, x, y, part, charpos) +mode_line_string (w, part, x, y, charpos, object, dx, dy, width, height) struct window *w; - int x, y; enum window_part part; + int *x, *y; int *charpos; + Lisp_Object *object; + int *dx, *dy; + int *width, *height; { struct glyph_row *row; struct glyph *glyph, *end; - int x0; + int x0, y0; Lisp_Object string = Qnil; if (part == ON_MODE_LINE) row = MATRIX_MODE_LINE_ROW (w->current_matrix); else row = MATRIX_HEADER_LINE_ROW (w->current_matrix); + y0 = *y - row->y; + *y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix); if (row->mode_line_p && row->enabled_p) { @@ -5746,14 +5987,43 @@ mode_line_string (w, x, y, part, charpos) it's the one we were looking for. */ glyph = row->glyphs[TEXT_AREA]; end = glyph + row->used[TEXT_AREA]; - for (x0 = 0; glyph < end; x0 += glyph->pixel_width, ++glyph) - if (x >= x0 && x < x0 + glyph->pixel_width) - { - string = glyph->object; - *charpos = glyph->charpos; - break; - } + for (x0 = *x; glyph < end && x0 >= glyph->pixel_width; ++glyph) + x0 -= glyph->pixel_width; + *x = glyph - row->glyphs[TEXT_AREA]; + if (glyph < end) + { + string = glyph->object; + *charpos = glyph->charpos; + *width = glyph->pixel_width; + *height = glyph->ascent + glyph->descent; +#ifdef HAVE_WINDOW_SYSTEM + if (glyph->type == IMAGE_GLYPH) + { + struct image *img; + img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id); + if (img != NULL) + *object = img->spec; + y0 -= row->ascent - glyph->ascent; + } +#endif + } + else + { + /* Add extra (default width) columns if clicked after EOL. */ + *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w); + *width = 0; + *height = row->height; + } } + else + { + *x = 0; + x0 = 0; + *width = *height = 0; + } + + *dx = x0; + *dy = y0; return string; } @@ -5764,15 +6034,18 @@ mode_line_string (w, x, y, part, charpos) the string returned. */ Lisp_Object -marginal_area_string (w, x, y, part, charpos) +marginal_area_string (w, part, x, y, charpos, object, dx, dy, width, height) struct window *w; - int x, y; enum window_part part; + int *x, *y; int *charpos; + Lisp_Object *object; + int *dx, *dy; + int *width, *height; { struct glyph_row *row = w->current_matrix->rows; struct glyph *glyph, *end; - int x0, i, wy = y; + int x0, y0, i, wy = *y; int area; Lisp_Object string = Qnil; @@ -5786,34 +6059,66 @@ marginal_area_string (w, x, y, part, charpos) for (i = 0; row->enabled_p && i < w->current_matrix->nrows; ++i, ++row) if (wy >= row->y && wy < MATRIX_ROW_BOTTOM_Y (row)) break; + y0 = *y - row->y; + *y = row - MATRIX_FIRST_TEXT_ROW (w->current_matrix); if (row->enabled_p) { /* Find the glyph under X. If we find one with a string object, it's the one we were looking for. */ - glyph = row->glyphs[area]; - end = glyph + row->used[area]; - if (area == RIGHT_MARGIN_AREA) x0 = ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? WINDOW_LEFT_FRINGE_WIDTH (w) + ? WINDOW_LEFT_FRINGE_WIDTH (w) : WINDOW_TOTAL_FRINGE_WIDTH (w)) + window_box_width (w, LEFT_MARGIN_AREA) + window_box_width (w, TEXT_AREA)); else x0 = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? WINDOW_LEFT_FRINGE_WIDTH (w) + ? WINDOW_LEFT_FRINGE_WIDTH (w) : 0); - for (; glyph < end; x0 += glyph->pixel_width, ++glyph) - if (x >= x0 && x < x0 + glyph->pixel_width) - { - string = glyph->object; - *charpos = glyph->charpos; - break; - } + glyph = row->glyphs[area]; + end = glyph + row->used[area]; + for (x0 = *x - x0; glyph < end && x0 >= glyph->pixel_width; ++glyph) + x0 -= glyph->pixel_width; + *x = glyph - row->glyphs[area]; + if (glyph < end) + { + string = glyph->object; + *charpos = glyph->charpos; + *width = glyph->pixel_width; + *height = glyph->ascent + glyph->descent; +#ifdef HAVE_WINDOW_SYSTEM + if (glyph->type == IMAGE_GLYPH) + { + struct image *img; + img = IMAGE_FROM_ID (WINDOW_XFRAME (w), glyph->u.img_id); + if (img != NULL) + *object = img->spec; + y0 -= row->ascent - glyph->ascent; + x0 += glyph->slice.x; + y0 += glyph->slice.y; + } +#endif + } + else + { + /* Add extra (default width) columns if clicked after EOL. */ + *x += x0 / WINDOW_FRAME_COLUMN_WIDTH (w); + *width = 0; + *height = row->height; + } + } + else + { + x0 = 0; + *x = 0; + *width = *height = 0; } + *dx = x0; + *dy = y0; + return string; } @@ -5834,6 +6139,9 @@ window_change_signal (signalnum) /* If we don't have an argument, */ #endif int old_errno = errno; + signal (SIGWINCH, window_change_signal); + SIGNAL_THREAD_CHECK (signalnum); + get_frame_size (&width, &height); /* The frame size change obviously applies to a termcap-controlled @@ -5856,7 +6164,6 @@ window_change_signal (signalnum) /* If we don't have an argument, */ } } - signal (SIGWINCH, window_change_signal); errno = old_errno; } #endif /* SIGWINCH */ @@ -6153,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. */ @@ -6171,130 +6478,93 @@ Emacs was built without floating point support. if (sec < 0 || (sec == 0 && usec == 0)) return Qnil; - { - Lisp_Object zero; - - XSETFASTINT (zero, 0); - wait_reading_process_input (sec, usec, zero, 0); - } - - /* We should always have wait_reading_process_input; we have a dummy - implementation for systems which don't support subprocesses. */ -#if 0 - /* No wait_reading_process_input */ - immediate_quit = 1; - QUIT; - -#ifdef VMS - sys_sleep (sec); -#else /* not VMS */ -/* The reason this is done this way - (rather than defined (H_S) && defined (H_T)) - is because the VMS preprocessor doesn't grok `defined'. */ -#ifdef HAVE_SELECT - EMACS_GET_TIME (end_time); - EMACS_SET_SECS_USECS (timeout, sec, usec); - EMACS_ADD_TIME (end_time, end_time, timeout); - - while (1) - { - EMACS_GET_TIME (timeout); - EMACS_SUB_TIME (timeout, end_time, timeout); - if (EMACS_TIME_NEG_P (timeout) - || !select (1, 0, 0, 0, &timeout)) - break; - } -#else /* not HAVE_SELECT */ - sleep (sec); -#endif /* HAVE_SELECT */ -#endif /* not VMS */ - - immediate_quit = 0; -#endif /* no subprocesses */ + wait_reading_process_output (sec, usec, 0, 0, Qnil, NULL, 0); return Qnil; } -/* This is just like wait_reading_process_input, except that - it does the redisplay. +/* This is just like wait_reading_process_output, except that + 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; { - Lisp_Object read_kbd; + int sec, usec; - swallow_events (display); + swallow_events (do_display); - if (detect_input_pending_run_timers (display) || !NILP (Vexecuting_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 - XSETINT (read_kbd, reading ? -1 : 1); - wait_reading_process_input (sec, usec, read_kbd, 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) */) - (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; - - { - double duration = extract_float (seconds); - sec = (int) duration; - usec += (duration - sec) * 1000000; - } + int count; -#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; } @@ -6305,68 +6575,106 @@ usage: (sit-for SECONDS &optional 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; @@ -6384,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; } @@ -6436,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 @@ -6446,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 @@ -6507,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); } @@ -6639,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); @@ -6709,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 @@ -6718,3 +7046,6 @@ See `buffer-display-table' for more information. */); Vwindow_system_version = Qnil; } } + +/* arch-tag: 8d812b1f-04a2-4195-a9c4-381f8457a413 + (do not change this comment) */