From 24a212eb232e081c12f6b52429757657f0528e66 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 3 Jul 2012 23:15:31 -0700 Subject: [PATCH] Avoid weird behavior with large horizontal scrolls. Without this change, for example, large hscroll values would mess up Emacs's display on Fedora 15 x86, presumably due to overflows in int calculations in the display code. Also, if buffers had long lines, Emacs would freeze. * window.c (HSCROLL_MAX): Reduce to 100000, and make it visible to GDB. (set_window_hscroll): New function, containing the old guts of Fset_window_hscroll. Return the clipped value. (Fset_window_hscroll, Fscroll_left, Fscroll_right): Use it. This avoids the need to check against PTRDIFF_MAX. --- src/ChangeLog | 11 +++++++++++ src/window.c | 50 +++++++++++++++++++++++++------------------------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index fdcab515f4..e335c8de8d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,5 +1,16 @@ 2012-07-04 Paul Eggert + Avoid weird behavior with large horizontal scrolls. + Without this change, for example, large hscroll values would + mess up Emacs's display on Fedora 15 x86, presumably due to + overflows in int calculations in the display code. + Also, if buffers had long lines, Emacs would freeze. + * window.c (HSCROLL_MAX): Reduce to 100000, and make it visible to GDB. + (set_window_hscroll): New function, containing the old guts of + Fset_window_hscroll. Return the clipped value. + (Fset_window_hscroll, Fscroll_left, Fscroll_right): Use it. + This avoids the need to check against PTRDIFF_MAX. + * buffer.c (Fgenerate_new_buffer_name): Fix sprintf format mismatch. 2012-07-04 Dmitry Antipov diff --git a/src/window.c b/src/window.c index af4aa85a3b..a436965564 100644 --- a/src/window.c +++ b/src/window.c @@ -51,6 +51,11 @@ along with GNU Emacs. If not, see . */ #include "nsterm.h" #endif +/* Horizontal scrolling has problems with large scroll amounts. + It's too slow with long lines, and even with small lines the + display can be messed up. Impose a reasonable maximum. */ +enum { HSCROLL_MAX = 100000 }; + Lisp_Object Qwindowp, Qwindow_live_p; static Lisp_Object Qwindow_configuration_p, Qrecord_window_buffer; static Lisp_Object Qwindow_deletable_p, Qdelete_window, Qdisplay_buffer; @@ -670,27 +675,35 @@ WINDOW must be a live window and defaults to the selected one. */) return make_number (decode_window (window)->hscroll); } +/* Set W's horizontal scroll amount to HSCROLL clipped to a reasonable + range, returning the new amount as a fixnum. */ +static Lisp_Object +set_window_hscroll (struct window *w, EMACS_INT hscroll) +{ + int new_hscroll = clip_to_bounds (0, hscroll, HSCROLL_MAX); + + /* Prevent redisplay shortcuts when changing the hscroll. */ + if (w->hscroll != new_hscroll) + XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1; + + w->hscroll = new_hscroll; + return make_number (new_hscroll); +} + DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0, doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL. If WINDOW is nil, the selected window is used. -Return NCOL. NCOL should be zero or positive. +Clip the number to a reasonable value if out of range. +Return the new number. NCOL should be zero or positive. Note that if `automatic-hscrolling' is non-nil, you cannot scroll the window so that the location of point moves off-window. */) (Lisp_Object window, Lisp_Object ncol) { struct window *w = decode_window (window); - ptrdiff_t hscroll; CHECK_NUMBER (ncol); - hscroll = clip_to_bounds (0, XINT (ncol), PTRDIFF_MAX); - - /* Prevent redisplay shortcuts when changing the hscroll. */ - if (w->hscroll != hscroll) - XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1; - - w->hscroll = hscroll; - return ncol; + return set_window_hscroll (w, XINT (ncol)); } DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger, @@ -4850,9 +4863,6 @@ specifies the window to scroll. This takes precedence over return Qnil; } -/* Scrolling amount must fit in both ptrdiff_t and Emacs fixnum. */ -#define HSCROLL_MAX min (PTRDIFF_MAX, MOST_POSITIVE_FIXNUM) - DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "^P\np", doc: /* Scroll selected window display ARG columns left. Default for ARG is window width minus 2. @@ -4864,16 +4874,11 @@ will not scroll a window to a column less than the value returned by this function. This happens in an interactive call. */) (register Lisp_Object arg, Lisp_Object set_minimum) { - Lisp_Object result; - ptrdiff_t hscroll; struct window *w = XWINDOW (selected_window); EMACS_INT requested_arg = (NILP (arg) ? window_body_cols (w) - 2 : XINT (Fprefix_numeric_value (arg))); - ptrdiff_t clipped_arg = - clip_to_bounds (- w->hscroll, requested_arg, HSCROLL_MAX - w->hscroll); - hscroll = w->hscroll + clipped_arg; - result = Fset_window_hscroll (selected_window, make_number (hscroll)); + Lisp_Object result = set_window_hscroll (w, w->hscroll + requested_arg); if (!NILP (set_minimum)) w->min_hscroll = w->hscroll; @@ -4892,16 +4897,11 @@ will not scroll a window to a column less than the value returned by this function. This happens in an interactive call. */) (register Lisp_Object arg, Lisp_Object set_minimum) { - Lisp_Object result; - ptrdiff_t hscroll; struct window *w = XWINDOW (selected_window); EMACS_INT requested_arg = (NILP (arg) ? window_body_cols (w) - 2 : XINT (Fprefix_numeric_value (arg))); - ptrdiff_t clipped_arg = - clip_to_bounds (w->hscroll - HSCROLL_MAX, requested_arg, w->hscroll); - hscroll = w->hscroll - clipped_arg; - result = Fset_window_hscroll (selected_window, make_number (hscroll)); + Lisp_Object result = set_window_hscroll (w, w->hscroll - requested_arg); if (!NILP (set_minimum)) w->min_hscroll = w->hscroll; -- 2.20.1