unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#34569: 26.1.90; Zero wide scroll bars
@ 2019-02-19  9:08 martin rudalics
  2019-02-23  9:51 ` Eli Zaretskii
  0 siblings, 1 reply; 11+ messages in thread
From: martin rudalics @ 2019-02-19  9:08 UTC (permalink / raw)
  To: 34569

Setting 'scroll-bar-width' to zero can have unforeseen consequences
depending on the toolkit used.  To reproduce with Emacs 26 run a Lucid
or Motif build as

emacs - Q --eval "(setq default-frame-alist '((minibuffer . nil) (vertical-scroll-bars . nil) (scroll-bar-width . 0)))"

Then evaluate

(set-frame-parameter nil 'vertical-scroll-bars 'left)

Emacs aborts with a

X protocol error: BadValue (integer parameter out of range for operation) on protocol request 12

GTK builds do not abort but have for example a scroll bar on the left
overwrite buffer text.  A similar bug can be produced with horizontal
scroll bars.

It's not entirely trivial to explain why Emacs aborts here.  The cause
is a combination of contrived logic and the absence of a more cautious
initial setting for X builds.  For starters, frame.h says that

/* Width that a scroll bar in frame F should have, if there is one.
    Measured in pixels.
    If scroll bars are turned off, this is still nonzero.  */
#define FRAME_CONFIG_SCROLL_BAR_WIDTH(f) ((f)->config_scroll_bar_width)

This comment is, unfortunately, wrong because in our example
'frame-notice-user-settings'

	    (setq parms (frame-parameters frame-initial-frame))

'frame-parameters' creates a zero entry for the 'scroll-bar-width'
frame parameter since our initial frame has no scroll bars and
'frame-notice-user-settings' passes that parameter on to 'make-frame'.
In frame.c this subsequently bypasses both checks in

x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
   int unit = FRAME_COLUMN_WIDTH (f);

   if (NILP (arg))
     {
       x_set_scroll_bar_default_width (f);
...
     }
   else if (RANGED_INTEGERP (1, arg, INT_MAX)
	   && XFASTINT (arg) != FRAME_CONFIG_SCROLL_BAR_WIDTH (f))
     {
       FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = XFASTINT (arg);
...

since ARG is zero which is neither nil nor a ranged integer > 0.  So
we continue with the initially zero FRAME_CONFIG_SCROLL_BAR_WIDTH (f)
and try to make a window with a zero wide scroll bar produced from the
initial w->scroll_bar_width (which equals -1) and these definitions in
window.h:

/* Width that a scroll bar in window W should have, if there is one.
    Measured in pixels.  If scroll bars are turned off, this is still
    nonzero.  */
#define WINDOW_CONFIG_SCROLL_BAR_WIDTH(W)		\
   (W->scroll_bar_width >= 0				\
    ? W->scroll_bar_width				\
    : FRAME_CONFIG_SCROLL_BAR_WIDTH (WINDOW_XFRAME (W)))

/* Width of scroll bar area in window W, measured in pixels.  */
#define WINDOW_SCROLL_BAR_AREA_WIDTH(W)					\
   (WINDOW_HAS_VERTICAL_SCROLL_BAR (W)					\
    ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (W)					\
    : 0)

Here the first comment is wrong again, WINDOW_CONFIG_SCROLL_BAR_WIDTH
is zero and X is rightfully annoyed.

The easisest fix I could come up with is switching the two branches of
the if clause in x_set_scroll_bar_width thusly:

void
x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
   int unit = FRAME_COLUMN_WIDTH (f);

  if (RANGED_INTEGERP (1, arg, INT_MAX)
	   && XFASTINT (arg) != FRAME_CONFIG_SCROLL_BAR_WIDTH (f))
     {
       FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = XFASTINT (arg);
       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + unit - 1) / unit;
       if (FRAME_X_WINDOW (f))
	adjust_frame_size (f, -1, -1, 3, 0, Qscroll_bar_width);

       SET_FRAME_GARBAGED (f);
     }
   else
     {
       x_set_scroll_bar_default_width (f);

       if (FRAME_X_WINDOW (f))
	adjust_frame_size (f, -1, -1, 3, 0, Qscroll_bar_width);

       SET_FRAME_GARBAGED (f);
     }

   XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
   XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
}

But maybe someone has a better idea.

Note that Windows builds sidestep the problem by unconditionally doing

   /* By default, make scrollbars the system standard width and height. */
   FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);

in 'x-create-frame'.

Note also that with emacs 27.1 the bug can be produced more directly by
including

(setq default-frame-alist '((vertical-scroll-bars . nil) (scroll-bar-width . 0)))

in the early-init.el and then enabling vertical scroll bars.  The
indirection via 'frame-notice-user-settings' is not needed there.

Thanks, martin





^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2019-03-04 10:14 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-02-19  9:08 bug#34569: 26.1.90; Zero wide scroll bars martin rudalics
2019-02-23  9:51 ` Eli Zaretskii
2019-02-23 14:01   ` martin rudalics
2019-02-23 16:49     ` Eli Zaretskii
2019-02-24  8:43       ` martin rudalics
2019-02-24 16:09         ` Eli Zaretskii
2019-02-24 18:31           ` martin rudalics
2019-02-24 19:04             ` Eli Zaretskii
2019-02-25 10:13               ` martin rudalics
2019-02-26 16:07                 ` Eli Zaretskii
2019-03-04 10:14           ` martin rudalics

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).