diff options
| author | Eli Zaretskii | 2022-10-11 13:26:01 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2022-10-11 13:26:01 +0300 |
| commit | 4f114c0d95caa0e26de3d188cebe9e3cbcb2dee8 (patch) | |
| tree | bdc3a6ff63499502012a0957dd2f1bedd0f79405 /src/window.c | |
| parent | 163000fb5980a0a098d1c4620b88a4717702d779 (diff) | |
| download | emacs-4f114c0d95caa0e26de3d188cebe9e3cbcb2dee8.tar.gz emacs-4f114c0d95caa0e26de3d188cebe9e3cbcb2dee8.zip | |
Speed up scrolling when lines are very long and truncated
* src/window.c (window_scroll_for_long_lines): New function.
(window_scroll): Call 'window_scroll_for_long_lines' when lines
are very long and truncated on display. Also, disable
'fontification-functions' during scrolling in that case.
* src/xdisp.c (redisplay_window): When recentering the window's
display, go back to the centering position using a simplified
method, if lines in the buffer are very long and truncated on
display.
Diffstat (limited to 'src/window.c')
| -rw-r--r-- | src/window.c | 97 |
1 files changed, 92 insertions, 5 deletions
diff --git a/src/window.c b/src/window.c index da80fabe33f..4e8b352e164 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -52,6 +52,7 @@ static ptrdiff_t get_leaf_windows (struct window *, struct window **, | |||
| 52 | ptrdiff_t); | 52 | ptrdiff_t); |
| 53 | static void window_scroll_pixel_based (Lisp_Object, int, bool, bool); | 53 | static void window_scroll_pixel_based (Lisp_Object, int, bool, bool); |
| 54 | static void window_scroll_line_based (Lisp_Object, int, bool, bool); | 54 | static void window_scroll_line_based (Lisp_Object, int, bool, bool); |
| 55 | static void window_scroll_for_long_lines (struct window *, int, bool); | ||
| 55 | static void foreach_window (struct frame *, | 56 | static void foreach_window (struct frame *, |
| 56 | bool (* fn) (struct window *, void *), | 57 | bool (* fn) (struct window *, void *), |
| 57 | void *); | 58 | void *); |
| @@ -5536,19 +5537,40 @@ window_internal_height (struct window *w) | |||
| 5536 | static void | 5537 | static void |
| 5537 | window_scroll (Lisp_Object window, EMACS_INT n, bool whole, bool noerror) | 5538 | window_scroll (Lisp_Object window, EMACS_INT n, bool whole, bool noerror) |
| 5538 | { | 5539 | { |
| 5540 | struct window *w = XWINDOW (window); | ||
| 5541 | struct buffer *b = XBUFFER (w->contents); | ||
| 5542 | bool long_lines_truncated = | ||
| 5543 | b->long_line_optimizations_p && !NILP (BVAR (b, truncate_lines)); | ||
| 5539 | specpdl_ref count = SPECPDL_INDEX (); | 5544 | specpdl_ref count = SPECPDL_INDEX (); |
| 5540 | 5545 | ||
| 5541 | n = clip_to_bounds (INT_MIN, n, INT_MAX); | 5546 | n = clip_to_bounds (INT_MIN, n, INT_MAX); |
| 5542 | 5547 | ||
| 5543 | wset_redisplay (XWINDOW (window)); | 5548 | wset_redisplay (w); |
| 5544 | 5549 | ||
| 5545 | if (whole && fast_but_imprecise_scrolling) | 5550 | /* Does this window's buffer have very long and truncated lines? */ |
| 5551 | if (b->long_line_optimizations_p | ||
| 5552 | && !long_lines_truncated | ||
| 5553 | && !NILP (Vtruncate_partial_width_windows) | ||
| 5554 | && w->total_cols < FRAME_COLS (XFRAME (WINDOW_FRAME (w)))) | ||
| 5555 | { | ||
| 5556 | if (FIXNUMP (Vtruncate_partial_width_windows)) | ||
| 5557 | long_lines_truncated = | ||
| 5558 | w->total_cols < XFIXNAT (Vtruncate_partial_width_windows); | ||
| 5559 | else | ||
| 5560 | long_lines_truncated = true; | ||
| 5561 | } | ||
| 5562 | |||
| 5563 | if (whole && (fast_but_imprecise_scrolling || long_lines_truncated)) | ||
| 5546 | specbind (Qfontification_functions, Qnil); | 5564 | specbind (Qfontification_functions, Qnil); |
| 5547 | 5565 | ||
| 5548 | /* On GUI frames, use the pixel-based version which is much slower | 5566 | if (whole && long_lines_truncated) |
| 5549 | than the line-based one but can handle varying line heights. */ | 5567 | window_scroll_for_long_lines (w, n, noerror); |
| 5550 | if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame))) | 5568 | else if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame))) |
| 5551 | { | 5569 | { |
| 5570 | |||
| 5571 | /* On GUI frames, use the pixel-based version which is much | ||
| 5572 | slower than the line-based one, but can handle varying | ||
| 5573 | line heights. */ | ||
| 5552 | record_unwind_protect_void (unwind_display_working_on_window); | 5574 | record_unwind_protect_void (unwind_display_working_on_window); |
| 5553 | display_working_on_window_p = true; | 5575 | display_working_on_window_p = true; |
| 5554 | window_scroll_pixel_based (window, n, whole, noerror); | 5576 | window_scroll_pixel_based (window, n, whole, noerror); |
| @@ -5598,6 +5620,71 @@ sanitize_next_screen_context_lines (void) | |||
| 5598 | return clip_to_bounds (0, next_screen_context_lines, 1000000); | 5620 | return clip_to_bounds (0, next_screen_context_lines, 1000000); |
| 5599 | } | 5621 | } |
| 5600 | 5622 | ||
| 5623 | /* Implementation of window_scroll for very long and truncated lines. | ||
| 5624 | This is a simplified version, it only handles WHOLE window scrolls, | ||
| 5625 | and doesn't honor scroll-preserve-screen-position nor scroll-margin. */ | ||
| 5626 | static void | ||
| 5627 | window_scroll_for_long_lines (struct window *w, int n, bool noerror) | ||
| 5628 | { | ||
| 5629 | ptrdiff_t startpos = marker_position (w->start); | ||
| 5630 | ptrdiff_t startbyte = marker_byte_position (w->start); | ||
| 5631 | int nscls = sanitize_next_screen_context_lines (); | ||
| 5632 | register int ht = window_internal_height (w); | ||
| 5633 | |||
| 5634 | n *= max (1, ht - nscls); | ||
| 5635 | |||
| 5636 | /* If point is not visible in window, bring it inside window. */ | ||
| 5637 | struct position pos; | ||
| 5638 | int rtop, rbot, dummy_rowh, dummy_vpos, dummy_x, dummy_y; | ||
| 5639 | if (!(PT >= startpos | ||
| 5640 | && PT <= ZV | ||
| 5641 | && startpos <= ZV | ||
| 5642 | && pos_visible_p (w, PT, &dummy_x, &dummy_y, &rtop, &rbot, &dummy_rowh, | ||
| 5643 | &dummy_vpos) | ||
| 5644 | && !rtop && !rbot)) | ||
| 5645 | { | ||
| 5646 | pos = *vmotion (PT, PT_BYTE, - (ht / 2), w); | ||
| 5647 | startpos = pos.bufpos; | ||
| 5648 | startbyte = pos.bytepos; | ||
| 5649 | } | ||
| 5650 | SET_PT_BOTH (startpos, startbyte); | ||
| 5651 | |||
| 5652 | bool lose = n < 0 && PT == BEGV; | ||
| 5653 | pos = *vmotion (PT, PT_BYTE, n, w); | ||
| 5654 | if (lose) | ||
| 5655 | { | ||
| 5656 | if (noerror) | ||
| 5657 | return; | ||
| 5658 | else | ||
| 5659 | xsignal0 (Qbeginning_of_buffer); | ||
| 5660 | } | ||
| 5661 | |||
| 5662 | bool bolp = pos.bufpos == BEGV || FETCH_BYTE (pos.bytepos - 1) == '\n'; | ||
| 5663 | if (pos.bufpos < ZV) | ||
| 5664 | { | ||
| 5665 | set_marker_restricted_both (w->start, w->contents, | ||
| 5666 | pos.bufpos, pos.bytepos); | ||
| 5667 | w->start_at_line_beg = bolp; | ||
| 5668 | wset_update_mode_line (w); | ||
| 5669 | /* Set force_start so that redisplay_window will run | ||
| 5670 | the window-scroll-functions. */ | ||
| 5671 | w->force_start = true; | ||
| 5672 | SET_PT_BOTH (pos.bufpos, pos.bytepos); | ||
| 5673 | if (n > 0) | ||
| 5674 | pos = *vmotion (PT, PT_BYTE, ht / 2, w); | ||
| 5675 | else if (n < 0) | ||
| 5676 | pos = *vmotion (PT, PT_BYTE, - (ht / 2), w); | ||
| 5677 | SET_PT_BOTH (pos.bufpos, pos.bytepos); | ||
| 5678 | } | ||
| 5679 | else | ||
| 5680 | { | ||
| 5681 | if (noerror) | ||
| 5682 | return; | ||
| 5683 | else | ||
| 5684 | xsignal0 (Qend_of_buffer); | ||
| 5685 | } | ||
| 5686 | } | ||
| 5687 | |||
| 5601 | /* Implementation of window_scroll that works based on pixel line | 5688 | /* Implementation of window_scroll that works based on pixel line |
| 5602 | heights. See the comment of window_scroll for parameter | 5689 | heights. See the comment of window_scroll for parameter |
| 5603 | descriptions. */ | 5690 | descriptions. */ |