X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/82f4a138a7ece82dfe955da9d8443c7f6dbc47e0..506d2f9a542b2dcdc4dc918abd0524f29e22a2a6:/src/dispnew.c diff --git a/src/dispnew.c b/src/dispnew.c index 3975f9ad78..df92fc395d 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -1,7 +1,7 @@ /* Updating of data structures for redisplay. Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005 Free Software Foundation, Inc. + 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -192,6 +192,28 @@ struct window *frame_row_to_window P_ ((struct window *, int)); int redisplay_dont_pause; +/* Define PERIODIC_PREEMPTION_CHECKING to 1, if micro-second timers + are supported, so we can check for input during redisplay at + regular intervals. */ +#ifdef EMACS_HAS_USECS +#define PERIODIC_PREEMPTION_CHECKING 1 +#else +#define PERIODIC_PREEMPTION_CHECKING 0 +#endif + +#if PERIODIC_PREEMPTION_CHECKING + +/* If a number (float), check for user input every N seconds. */ + +Lisp_Object Vredisplay_preemption_period; + +/* Redisplay preemption timers. */ + +static EMACS_TIME preemption_period; +static EMACS_TIME preemption_next_check; + +#endif + /* Nonzero upon entry to redisplay means do not assume anything about current contents of actual terminal frame; clear and redraw it. */ @@ -355,8 +377,7 @@ static unsigned history_tick; static void add_frame_display_history P_ ((struct frame *, int)); static void add_window_display_history P_ ((struct window *, char *, int)); - - + /* 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 @@ -3821,6 +3842,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 @@ -3899,6 +3942,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); @@ -3953,6 +3997,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); @@ -3963,6 +4023,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. */ @@ -4035,23 +4096,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) @@ -4059,6 +4130,8 @@ redraw_overlapping_rows (w, yb) } } +#endif /* HAVE_WINDOW_SYSTEM */ + #ifdef GLYPH_DEBUG @@ -4095,7 +4168,9 @@ update_window (w, force_p) { struct glyph_matrix *desired_matrix = w->desired_matrix; int paused_p; +#if !PERIODIC_PREEMPTION_CHECKING int preempt_count = baud_rate / 2400 + 1; +#endif extern int input_pending; extern Lisp_Object do_mouse_tracking; #if GLYPH_DEBUG @@ -4107,8 +4182,13 @@ update_window (w, force_p) /* 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. */ @@ -4143,7 +4223,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 @@ -4181,9 +4260,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); @@ -4213,17 +4306,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); @@ -4343,10 +4437,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); @@ -4465,7 +4563,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)) { @@ -5126,11 +5227,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) @@ -5181,8 +5287,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); } @@ -6383,13 +6504,22 @@ Lisp_Object sit_for (sec, usec, reading, display, initial_display) int sec, usec, reading, display, initial_display; { + int preempt = (sec >= 0) || (sec == 0 && usec >= 0); + swallow_events (display); - if (detect_input_pending_run_timers (display) || !NILP (Vexecuting_kbd_macro)) + if ((detect_input_pending_run_timers (display) && preempt) + || !NILP (Vexecuting_kbd_macro)) return Qnil; if (initial_display) - redisplay_preserve_echo_area (2); + { + int count = SPECPDL_INDEX (); + if (!preempt) + specbind (Qredisplay_dont_pause, Qt); + redisplay_preserve_echo_area (2); + unbind_to (count, Qnil); + } if (sec == 0 && usec == 0) return Qt; @@ -6415,6 +6545,8 @@ 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. +Redisplay will occur even when input is available if SECONDS is negative. + An obsolete but still supported form is \(sit-for SECONDS &optional MILLISECONDS NODISP) Where the optional arg MILLISECONDS specifies an additional wait period, @@ -6632,7 +6764,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 @@ -6642,6 +6774,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 @@ -6905,7 +7044,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