Make :align-to account for display-line-numbers

These changes also update the various bundled packages to use
new feature, and better support customizations of the line-number
face.
* src/xdisp.c (calc_pixel_width_or_height): Improve commentary.
Make :align-to count from the end of the line-number display when
the offset or the width form reference that of the text area.
(Bug#28855)

* src/indent.c (Fline_number_display_width): Implement support for
the PIXELWISE argument being 'columns'.  Update the doc string.
(syms_of_indent): New symbol 'columns'.

* lisp/ruler-mode.el (ruler-mode-window-col, ruler-mode-ruler):
Call line-number-display-width with last argument 'columns'.

* lisp/proced.el (proced-header-line): Call
line-number-display-width with 2nd arg 'columns', which also fixes
a problem when display-line-numbers is nil.

* lisp/emacs-lisp/tabulated-list.el
(tabulated-list-line-number-width): Call line-number-display-width
with 2nd arg 'columns.
(tabulated-list-entry-lnum-width): Remove unneeded defvar.
(tabulated-list-print, tabulated-list-print-entry): No need to
account for the value of tabulated-list-entry-lnum-width.
(tabulated-list--current-lnum-width): New defvar.
(tabulated-list-watch-line-number-width): New function.
(tabulated-list-mode): Bind tabulated-list--current-lnum-width
locally, and set up tabulated-list-watch-line-number-width as
pre-redisplay-functions hook.

* doc/lispref/display.texi (Size of Displayed Text): Document the
'columns' value of the PIXELWISE argument.
(Pixel Specification): Update and improve the documentation of the
supported forms.
This commit is contained in:
Eli Zaretskii 2017-10-20 12:36:12 +03:00
parent 831eafc8ae
commit fd3d8610b2
6 changed files with 129 additions and 38 deletions

View file

@ -2050,14 +2050,17 @@ calculations.
@defun line-number-display-width &optional pixelwise @defun line-number-display-width &optional pixelwise
This function returns the width used for displaying the line numbers This function returns the width used for displaying the line numbers
in the selected window. Optional argument @var{pixelwise}, if in the selected window. If the optional argument @var{pixelwise} is
non-@code{nil}, means return the value in pixels; otherwise the value the symbol @code{columns}, the return value is a float number of the
is returned in column units of the font defined for the frame's canonical columns; if @var{pixelwise} is @code{t} or any other
non-@code{nil} value, the value is an integer and is measured in
pixels. If @var{pixelwise} is omitted or @code{nil}, the value is the
integer number of columns of the font defined for the
@code{line-number} face, and doesn't include the 2 columns used to pad @code{line-number} face, and doesn't include the 2 columns used to pad
the numbers. If line numbers are not displayed in the selected the numbers on display. If line numbers are not displayed in the
window, the value is zero. Use @code{with-selected-window} selected window, the value is zero regardless of the value of
(@pxref{Selecting Windows}) if you need this information about another @var{pixelwise}. Use @code{with-selected-window} (@pxref{Selecting
window. Windows}) if you need this information about another window.
@end defun @end defun
@ -4636,7 +4639,7 @@ as an absolute number of pixels.
@smallexample @smallexample
@group @group
@var{expr} ::= @var{num} | (@var{num}) | @var{unit} | @var{elem} | @var{pos} | @var{image} | @var{form} @var{expr} ::= @var{num} | (@var{num}) | @var{unit} | @var{elem} | @var{pos} | @var{image} | @var{xwidget} | @var{form}
@var{num} ::= @var{integer} | @var{float} | @var{symbol} @var{num} ::= @var{integer} | @var{float} | @var{symbol}
@var{unit} ::= in | mm | cm | width | height @var{unit} ::= in | mm | cm | width | height
@end group @end group
@ -4652,22 +4655,34 @@ as an absolute number of pixels.
The form @var{num} specifies a fraction of the default frame font The form @var{num} specifies a fraction of the default frame font
height or width. The form @code{(@var{num})} specifies an absolute height or width. The form @code{(@var{num})} specifies an absolute
number of pixels. If @var{num} is a symbol, @var{symbol}, its number of pixels. If @var{num} is a symbol, @var{symbol}, its
buffer-local variable binding is used. buffer-local variable binding is used; that binding can be either a
number or a cons cell of the forms shown above (including yet another
cons cell whose @code{car} is a symbol that has a buffer-local
binding).
The @code{in}, @code{mm}, and @code{cm} units specify the number of The @code{in}, @code{mm}, and @code{cm} units specify the number of
pixels per inch, millimeter, and centimeter, respectively. The pixels per inch, millimeter, and centimeter, respectively. The
@code{width} and @code{height} units correspond to the default width @code{width} and @code{height} units correspond to the default width
and height of the current face. An image specification @code{image} and height of the current face. An image specification of the form
corresponds to the width or height of the image. @w{@code{(image . @var{props})}} (@pxref{Image Descriptors})
corresponds to the width or height of the specified image. Similarly,
an xwidget specification of the form @w{@code{(xwidget . @var{props})}}
stands for the width or height of the specified xwidget.
@xref{Xwidgets}.
The elements @code{left-fringe}, @code{right-fringe}, The elements @code{left-fringe}, @code{right-fringe},
@code{left-margin}, @code{right-margin}, @code{scroll-bar}, and @code{left-margin}, @code{right-margin}, @code{scroll-bar}, and
@code{text} specify to the width of the corresponding area of the @code{text} specify the width of the corresponding area of the window.
window. When the window displays line numbers (@pxref{Size of Displayed
Text}), the width of the @code{text} area is decreased by the screen
space taken by the line-number display.
The @code{left}, @code{center}, and @code{right} positions can be The @code{left}, @code{center}, and @code{right} positions can be
used with @code{:align-to} to specify a position relative to the left used with @code{:align-to} to specify a position relative to the left
edge, center, or right edge of the text area. edge, center, or right edge of the text area. When the window
displays line numbers, the @code{left} and the @code{center} positions
are offset to account for the screen space taken by the line-number
display.
Any of the above window elements (except @code{text}) can also be Any of the above window elements (except @code{text}) can also be
used with @code{:align-to} to specify that the position is relative to used with @code{:align-to} to specify that the position is relative to
@ -4683,13 +4698,15 @@ the left-margin, use
If no specific base offset is set for alignment, it is always relative If no specific base offset is set for alignment, it is always relative
to the left edge of the text area. For example, @samp{:align-to 0} in a to the left edge of the text area. For example, @samp{:align-to 0} in a
header-line aligns with the first text column in the text area. header-line aligns with the first text column in the text area. When
the window displays line numbers, the text is considered to start where
the space used for line-number display ends.
A value of the form @code{(@var{num} . @var{expr})} stands for the A value of the form @code{(@var{num} . @var{expr})} stands for the
product of the values of @var{num} and @var{expr}. For example, product of the values of @var{num} and @var{expr}. For example,
@code{(2 . in)} specifies a width of 2 inches, while @code{(0.5 . @code{(2 . in)} specifies a width of 2 inches, while @code{(0.5 .
@var{image})} specifies half the width (or height) of the specified @var{image})} specifies half the width (or height) of the specified
image. @var{image} (which should be given by its image spec).
The form @code{(+ @var{expr} ...)} adds up the value of the The form @code{(+ @var{expr} ...)} adds up the value of the
expressions. The form @code{(- @var{expr} ...)} negates or subtracts expressions. The form @code{(- @var{expr} ...)} negates or subtracts

View file

@ -193,10 +193,10 @@ Populated by `tabulated-list-init-header'.")
;; is displayed. ;; is displayed.
(if (not display-line-numbers) (if (not display-line-numbers)
0 0
(let ((cbuf-window (get-buffer-window (current-buffer)))) (let ((cbuf-window (get-buffer-window (current-buffer) t)))
(if (window-live-p cbuf-window) (if (window-live-p cbuf-window)
(with-selected-window cbuf-window (with-selected-window cbuf-window
(+ (line-number-display-width) 2)) (line-number-display-width 'columns))
4)))) 4))))
(defun tabulated-list-init-header () (defun tabulated-list-init-header ()
@ -329,8 +329,6 @@ Check the current row, the previous one and the next row."
(string-width (if (stringp nt) nt (car nt))))) (string-width (if (stringp nt) nt (car nt)))))
tabulated-list--near-rows))) tabulated-list--near-rows)))
(defvar tabulated-list-entry-lnum-width nil)
(defun tabulated-list-print (&optional remember-pos update) (defun tabulated-list-print (&optional remember-pos update)
"Populate the current Tabulated List mode buffer. "Populate the current Tabulated List mode buffer.
This sorts the `tabulated-list-entries' list if sorting is This sorts the `tabulated-list-entries' list if sorting is
@ -373,7 +371,6 @@ changing `tabulated-list-sort-key'."
(unless tabulated-list-use-header-line (unless tabulated-list-use-header-line
(tabulated-list-print-fake-header))) (tabulated-list-print-fake-header)))
;; Finally, print the resulting list. ;; Finally, print the resulting list.
(setq tabulated-list-entry-lnum-width (tabulated-list-line-number-width))
(while entries (while entries
(let* ((elt (car entries)) (let* ((elt (car entries))
(tabulated-list--near-rows (tabulated-list--near-rows
@ -428,9 +425,8 @@ of column descriptors."
(x (max tabulated-list-padding 0)) (x (max tabulated-list-padding 0))
(ncols (length tabulated-list-format)) (ncols (length tabulated-list-format))
(inhibit-read-only t)) (inhibit-read-only t))
(setq x (+ x tabulated-list-entry-lnum-width))
(if (> tabulated-list-padding 0) (if (> tabulated-list-padding 0)
(insert (make-string (- x tabulated-list-entry-lnum-width) ?\s))) (insert (make-string x ?\s)))
(let ((tabulated-list--near-rows ; Bind it if not bound yet (Bug#25506). (let ((tabulated-list--near-rows ; Bind it if not bound yet (Bug#25506).
(or (bound-and-true-p tabulated-list--near-rows) (or (bound-and-true-p tabulated-list--near-rows)
(list (or (tabulated-list-get-entry (point-at-bol 0)) (list (or (tabulated-list-get-entry (point-at-bol 0))
@ -601,6 +597,14 @@ With a numeric prefix argument N, sort the Nth column."
(tabulated-list-init-header) (tabulated-list-init-header)
(tabulated-list-print t))) (tabulated-list-print t)))
(defvar tabulated-list--current-lnum-width nil)
(defun tabulated-list-watch-line-number-width (_window)
(if display-line-numbers
(let ((lnum-width (tabulated-list-line-number-width)))
(when (not (= tabulated-list--current-lnum-width lnum-width))
(setq-local tabulated-list--current-lnum-width lnum-width)
(tabulated-list-revert)))))
;;; The mode definition: ;;; The mode definition:
(define-derived-mode tabulated-list-mode special-mode "Tabulated" (define-derived-mode tabulated-list-mode special-mode "Tabulated"
@ -645,7 +649,12 @@ as the ewoc pretty-printer."
;; column of the first entry happens to begin with a R2L letter. ;; column of the first entry happens to begin with a R2L letter.
(setq bidi-paragraph-direction 'left-to-right) (setq bidi-paragraph-direction 'left-to-right)
;; This is for if/when they turn on display-line-numbers ;; This is for if/when they turn on display-line-numbers
(add-hook 'display-line-numbers-mode-hook #'tabulated-list-revert nil t)) (add-hook 'display-line-numbers-mode-hook #'tabulated-list-revert nil t)
;; This is for if/when they customize the line-number face or when
;; the line-number width needs to change due to scrolling.
(setq-local tabulated-list--current-lnum-width 0)
(add-hook 'pre-redisplay-functions
#'tabulated-list-watch-line-number-width nil t))
(put 'tabulated-list-mode 'mode-class 'special) (put 'tabulated-list-mode 'mode-class 'special)

View file

@ -604,7 +604,8 @@ Important: the match ends just after the marker.")
"Return header line for Proced buffer." "Return header line for Proced buffer."
(list (propertize " " (list (propertize " "
'display 'display
(list 'space :align-to (+ 2 (line-number-display-width)))) (list 'space :align-to
(line-number-display-width 'columns)))
(if (<= (window-hscroll) (length proced-header-line)) (if (<= (window-hscroll) (length proced-header-line))
(replace-regexp-in-string ;; preserve text properties (replace-regexp-in-string ;; preserve text properties
"\\(%\\)" "\\1\\1" "\\(%\\)" "\\1\\1"

View file

@ -307,7 +307,12 @@ or remove a tab stop. \\[ruler-mode-toggle-show-tab-stops] or
N is a column number relative to selected frame. N is a column number relative to selected frame.
If required, account for screen estate taken by `display-line-numbers'." If required, account for screen estate taken by `display-line-numbers'."
(if display-line-numbers (if display-line-numbers
(setq n (- n (line-number-display-width) 2))) ;; FIXME: ruler-mode relies on N being an integer, so if the
;; 'line-number' face is customized to use a font that is larger
;; or smaller than that of the default face, the alignment might
;; be off by up to half a column, unless the font width is an
;; integral multiple or divisor of the default face's font.
(setq n (- n (round (line-number-display-width 'columns)))))
(- n (- n
(or (car (window-margins)) 0) (or (car (window-margins)) 0)
(fringe-columns 'left) (fringe-columns 'left)
@ -668,7 +673,12 @@ Optional argument PROPS specifies other text properties to apply."
(let* ((w (ruler-mode-text-scaled-window-width)) (let* ((w (ruler-mode-text-scaled-window-width))
(m (window-margins)) (m (window-margins))
(f (window-fringes)) (f (window-fringes))
(i (if display-line-numbers (+ (line-number-display-width) 2) 0)) (i (if display-line-numbers
;; FIXME: ruler-mode relies on I being an integer, so
;; the column numbers might be slightly off if the
;; line-number face is customized.
(round (line-number-display-width 'columns))
0))
(j (ruler-mode-text-scaled-window-hscroll)) (j (ruler-mode-text-scaled-window-hscroll))
;; Setup the scrollbar, fringes, and margins areas. ;; Setup the scrollbar, fringes, and margins areas.
(lf (ruler-mode-space (lf (ruler-mode-space
@ -708,7 +718,7 @@ Optional argument PROPS specifies other text properties to apply."
;; line-number display be blank, not filled with ;; line-number display be blank, not filled with
;; ruler-mode-basic-graduation-char. ;; ruler-mode-basic-graduation-char.
(if display-line-numbers (if display-line-numbers
(let* ((lndw (+ (line-number-display-width) 2)) (let* ((lndw (round (line-number-display-width 'columns)))
(s (make-string lndw ?\s))) (s (make-string lndw ?\s)))
(concat s (make-string (- w lndw) (concat s (make-string (- w lndw)
ruler-mode-basic-graduation-char))) ruler-mode-basic-graduation-char)))

View file

@ -1991,15 +1991,26 @@ line_number_display_width (struct window *w, int *width, int *pixel_width)
DEFUN ("line-number-display-width", Fline_number_display_width, DEFUN ("line-number-display-width", Fline_number_display_width,
Sline_number_display_width, 0, 1, 0, Sline_number_display_width, 0, 1, 0,
doc: /* Return the width used for displaying line numbers in the selected window. doc: /* Return the width used for displaying line numbers in the selected window.
If optional argument PIXELWISE is non-nil, return the width in pixels, If optional argument PIXELWISE is the symbol `columns', return the width
otherwise return the width in columns of the face used to display in units of the frame's canonical character width. In this case, the
line numbers, `line-number'. Note that in the latter case, the value value is a float.
doesn't include the 2 columns used for padding the numbers. */) If optional argument PIXELWISE is t or any other non-nil value, return
the width as an integer number of pixels.
Otherwise return the value as an integer number of columns of the face
used to display line numbers, `line-number'. Note that in the latter
case, the value doesn't include the 2 columns used for padding the
numbers on display. */)
(Lisp_Object pixelwise) (Lisp_Object pixelwise)
{ {
int width, pixel_width; int width, pixel_width;
struct window *w = XWINDOW (selected_window);
line_number_display_width (XWINDOW (selected_window), &width, &pixel_width); line_number_display_width (XWINDOW (selected_window), &width, &pixel_width);
if (!NILP (pixelwise)) if (EQ (pixelwise, Qcolumns))
{
struct frame *f = XFRAME (w->frame);
return make_float ((double) pixel_width / FRAME_COLUMN_WIDTH (f));
}
else if (!NILP (pixelwise))
return make_number (pixel_width); return make_number (pixel_width);
return make_number (width); return make_number (width);
} }
@ -2361,6 +2372,8 @@ syms_of_indent (void)
doc: /* Indentation can insert tabs if this is non-nil. */); doc: /* Indentation can insert tabs if this is non-nil. */);
indent_tabs_mode = 1; indent_tabs_mode = 1;
DEFSYM (Qcolumns, "columns");
defsubr (&Scurrent_indentation); defsubr (&Scurrent_indentation);
defsubr (&Sindent_to); defsubr (&Sindent_to);
defsubr (&Scurrent_column); defsubr (&Scurrent_column);

View file

@ -25123,7 +25123,20 @@ else if the text is replaced by an ellipsis. */)
'(space :width (+ left-fringe left-margin (- (1)))) '(space :width (+ left-fringe left-margin (- (1))))
'(space :width (+ left-fringe left-margin (-1))) '(space :width (+ left-fringe left-margin (-1)))
*/ If ALIGN_TO is NULL, returns the result in *RES. If ALIGN_TO is
non-NULL, the value of *ALIGN_TO is a window-relative pixel
coordinate, and *RES is the additional pixel width from that point
till the end of the stretch glyph.
WIDTH_P non-zero means take the width dimension or X coordinate of
the object specified by PROP, WIDTH_P zero means take the height
dimension or the Y coordinate. (Therefore, if ALIGN_TO is
non-NULL, WIDTH_P should be non-zero.)
FONT is the font of the face of the surrounding text.
The return value is non-zero if width or height were successfully
calculated, i.e. if PROP is a valid spec. */
static bool static bool
calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
@ -25145,6 +25158,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
{ {
char *unit = SSDATA (SYMBOL_NAME (prop)); char *unit = SSDATA (SYMBOL_NAME (prop));
/* The UNIT expression, e.g. as part of (NUM . UNIT). */
if (unit[0] == 'i' && unit[1] == 'n') if (unit[0] == 'i' && unit[1] == 'n')
pixels = 1.0; pixels = 1.0;
else if (unit[0] == 'm' && unit[1] == 'm') else if (unit[0] == 'm' && unit[1] == 'm')
@ -25165,10 +25179,12 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
} }
#ifdef HAVE_WINDOW_SYSTEM #ifdef HAVE_WINDOW_SYSTEM
/* 'height': the height of FONT. */
if (EQ (prop, Qheight)) if (EQ (prop, Qheight))
return OK_PIXELS (font return OK_PIXELS (font
? normal_char_height (font, -1) ? normal_char_height (font, -1)
: FRAME_LINE_HEIGHT (it->f)); : FRAME_LINE_HEIGHT (it->f));
/* 'width': the width of FONT. */
if (EQ (prop, Qwidth)) if (EQ (prop, Qwidth))
return OK_PIXELS (font return OK_PIXELS (font
? FONT_WIDTH (font) ? FONT_WIDTH (font)
@ -25178,33 +25194,48 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
return OK_PIXELS (1); return OK_PIXELS (1);
#endif #endif
/* 'text': the width or height of the text area. */
if (EQ (prop, Qtext)) if (EQ (prop, Qtext))
return OK_PIXELS (width_p return OK_PIXELS (width_p
? window_box_width (it->w, TEXT_AREA) ? (window_box_width (it->w, TEXT_AREA)
- it->lnum_pixel_width)
: WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w)); : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w));
/* ':align_to'. First time we compute the value, window
elements are interpreted as the position of the element's
left edge. */
if (align_to && *align_to < 0) if (align_to && *align_to < 0)
{ {
*res = 0; *res = 0;
/* 'left': left edge of the text area. */
if (EQ (prop, Qleft)) if (EQ (prop, Qleft))
return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)); return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
+ it->lnum_pixel_width);
/* 'right': right edge of the text area. */
if (EQ (prop, Qright)) if (EQ (prop, Qright))
return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA)); return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA));
/* 'center': the center of the text area. */
if (EQ (prop, Qcenter)) if (EQ (prop, Qcenter))
return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA) return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
+ it->lnum_pixel_width
+ window_box_width (it->w, TEXT_AREA) / 2); + window_box_width (it->w, TEXT_AREA) / 2);
/* 'left-fringe': left edge of the left fringe. */
if (EQ (prop, Qleft_fringe)) if (EQ (prop, Qleft_fringe))
return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w) ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w)
: window_box_right_offset (it->w, LEFT_MARGIN_AREA)); : window_box_right_offset (it->w, LEFT_MARGIN_AREA));
/* 'right-fringe': left edge of the right fringe. */
if (EQ (prop, Qright_fringe)) if (EQ (prop, Qright_fringe))
return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w) return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
? window_box_right_offset (it->w, RIGHT_MARGIN_AREA) ? window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
: window_box_right_offset (it->w, TEXT_AREA)); : window_box_right_offset (it->w, TEXT_AREA));
/* 'left-margin': left edge of the left display margin. */
if (EQ (prop, Qleft_margin)) if (EQ (prop, Qleft_margin))
return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA)); return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA));
/* 'right-margin': left edge of the right display margin. */
if (EQ (prop, Qright_margin)) if (EQ (prop, Qright_margin))
return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA)); return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA));
/* 'scroll-bar': left edge of the vertical scroll bar. */
if (EQ (prop, Qscroll_bar)) if (EQ (prop, Qscroll_bar))
return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w) return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
? 0 ? 0
@ -25215,6 +25246,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
} }
else else
{ {
/* Otherwise, the elements stand for their width. */
if (EQ (prop, Qleft_fringe)) if (EQ (prop, Qleft_fringe))
return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w)); return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w));
if (EQ (prop, Qright_fringe)) if (EQ (prop, Qright_fringe))
@ -25237,6 +25269,8 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
int base_unit = (width_p int base_unit = (width_p
? FRAME_COLUMN_WIDTH (it->f) ? FRAME_COLUMN_WIDTH (it->f)
: FRAME_LINE_HEIGHT (it->f)); : FRAME_LINE_HEIGHT (it->f));
if (width_p && align_to && *align_to < 0)
return OK_PIXELS (XFLOATINT (prop) * base_unit + it->lnum_pixel_width);
return OK_PIXELS (XFLOATINT (prop) * base_unit); return OK_PIXELS (XFLOATINT (prop) * base_unit);
} }
@ -25248,6 +25282,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
if (SYMBOLP (car)) if (SYMBOLP (car))
{ {
#ifdef HAVE_WINDOW_SYSTEM #ifdef HAVE_WINDOW_SYSTEM
/* '(image PROPS...)': width or height of the specified image. */
if (FRAME_WINDOW_P (it->f) if (FRAME_WINDOW_P (it->f)
&& valid_image_p (prop)) && valid_image_p (prop))
{ {
@ -25256,12 +25291,15 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
return OK_PIXELS (width_p ? img->width : img->height); return OK_PIXELS (width_p ? img->width : img->height);
} }
/* '(xwidget PROPS...)': dimensions of the specified xwidget. */
if (FRAME_WINDOW_P (it->f) && valid_xwidget_spec_p (prop)) if (FRAME_WINDOW_P (it->f) && valid_xwidget_spec_p (prop))
{ {
/* TODO: Don't return dummy size. */ /* TODO: Don't return dummy size. */
return OK_PIXELS (100); return OK_PIXELS (100);
} }
#endif #endif
/* '(+ EXPR...)' or '(- EXPR...)' add or subtract
recursively calculated values. */
if (EQ (car, Qplus) || EQ (car, Qminus)) if (EQ (car, Qplus) || EQ (car, Qminus))
{ {
bool first = true; bool first = true;
@ -25289,15 +25327,18 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
car = Qnil; car = Qnil;
} }
/* '(NUM)': absolute number of pixels. */
if (NUMBERP (car)) if (NUMBERP (car))
{ {
double fact; double fact;
int offset =
width_p && align_to && *align_to < 0 ? it->lnum_pixel_width : 0;
pixels = XFLOATINT (car); pixels = XFLOATINT (car);
if (NILP (cdr)) if (NILP (cdr))
return OK_PIXELS (pixels); return OK_PIXELS (pixels + offset);
if (calc_pixel_width_or_height (&fact, it, cdr, if (calc_pixel_width_or_height (&fact, it, cdr,
font, width_p, align_to)) font, width_p, align_to))
return OK_PIXELS (pixels * fact); return OK_PIXELS (pixels * fact + offset);
return false; return false;
} }