X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/ed8226ea4141cb16a8392e2106ecf428fa56f1e0..e5803d84f59034cb37a36f21bd7b3bc370437c8e:/src/dispnew.c diff --git a/src/dispnew.c b/src/dispnew.c index 987562b0be..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,03,04 - 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) @@ -1519,7 +1544,7 @@ row_equal_p (w, a, b, mouse_face_p) || 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_p != b->overlay_arrow_p + || 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) @@ -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 @@ -1911,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; @@ -1982,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 @@ -2010,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 @@ -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,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 @@ -2777,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)); @@ -2784,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 @@ -2802,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. @@ -3164,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) @@ -3287,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; } @@ -3786,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 @@ -3864,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); @@ -3918,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); @@ -3928,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. */ @@ -4000,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) @@ -4024,6 +4115,8 @@ redraw_overlapping_rows (w, yb) } } +#endif /* HAVE_WINDOW_SYSTEM */ + #ifdef GLYPH_DEBUG @@ -4060,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. */ @@ -4110,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 @@ -4148,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); @@ -4180,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); @@ -4279,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); @@ -4310,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); @@ -4432,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)) { @@ -4529,7 +4653,7 @@ update_window_line (w, vpos, mouse_face_overwritten_p) || desired_row->y != current_row->y || desired_row->visible_height != current_row->visible_height || desired_row->cursor_in_fringe_p != current_row->cursor_in_fringe_p - || desired_row->overlay_arrow_p != current_row->overlay_arrow_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->exact_window_width_line_p != current_row->exact_window_width_line_p @@ -5039,7 +5163,7 @@ scrolling_window (w, header_line_p) || 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_p != from->overlay_arrow_p)) + || 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; @@ -5093,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) @@ -5148,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); } @@ -5730,6 +5874,9 @@ buffer_posn_from_coords (w, x, y, pos, object, dx, dy, width, height) struct text_pos startp; Lisp_Object string; struct glyph_row *row; +#ifdef HAVE_WINDOW_SYSTEM + struct image *img = 0; +#endif int x0, x1; current_buffer = XBUFFER (w->buffer); @@ -5755,25 +5902,35 @@ buffer_posn_from_coords (w, x, y, pos, object, dx, dy, width, height) #ifdef HAVE_WINDOW_SYSTEM if (it.what == IT_IMAGE) { - struct image *img; if ((img = IMAGE_FROM_ID (it.f, it.image_id)) != NULL && !NILP (img->spec)) *object = img->spec; } #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]) { struct glyph *glyph = row->glyphs[TEXT_AREA] + it.hpos; - *width = glyph->pixel_width; - *height = glyph->ascent + glyph->descent; #ifdef HAVE_WINDOW_SYSTEM - if (glyph->type == IMAGE_GLYPH) - *dy -= row->ascent - glyph->ascent; + 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 { @@ -5830,7 +5987,7 @@ mode_line_string (w, part, x, y, charpos, object, dx, dy, width, height) it's the one we were looking for. */ glyph = row->glyphs[TEXT_AREA]; end = glyph + row->used[TEXT_AREA]; - for (x0 = *x; glyph < end && x0 > glyph->pixel_width; ++glyph) + for (x0 = *x; glyph < end && x0 >= glyph->pixel_width; ++glyph) x0 -= glyph->pixel_width; *x = glyph - row->glyphs[TEXT_AREA]; if (glyph < end) @@ -5922,7 +6079,7 @@ marginal_area_string (w, part, x, y, charpos, object, dx, dy, width, height) glyph = row->glyphs[area]; end = glyph + row->used[area]; - for (x0 = *x - x0; glyph < end && x0 > glyph->pixel_width; ++glyph) + for (x0 = *x - x0; glyph < end && x0 >= glyph->pixel_width; ++glyph) x0 -= glyph->pixel_width; *x = glyph - row->glyphs[area]; if (glyph < end) @@ -5939,6 +6096,8 @@ marginal_area_string (w, part, x, y, charpos, object, dx, dy, width, height) if (img != NULL) *object = img->spec; y0 -= row->ascent - glyph->ascent; + x0 += glyph->slice.x; + y0 += glyph->slice.y; } #endif } @@ -5980,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 @@ -6002,7 +6164,6 @@ window_change_signal (signalnum) /* If we don't have an argument, */ } } - signal (SIGWINCH, window_change_signal); errno = old_errno; } #endif /* SIGWINCH */ @@ -6299,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. */ @@ -6317,133 +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 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; } @@ -6454,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; @@ -6533,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; } @@ -6585,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 @@ -6595,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 @@ -6656,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); } @@ -6788,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); @@ -6858,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