Subject: bug#59080: 29.0.50; preview-get-dpi produces surprising result on vertical monitor

From: Po Lu <[email-masked]>
Date: Mon, 07 Nov 2022 09:30:16 +0800

Tony Zorman <[email-masked]> writes:

> Hi,
>
> tl;dr: the `preview-get-dpi' function compares the wrong values for
> horizontal monitors (i.e., ones that are flipped by 90/270 degrees).
>
> When previewing LaTeX fragments via AUCTeX's `preview.el' library,
> things get quite messed up when one or more monitors are set up in
> "portrait mode".  I have attached three images that show this; bug1.png
> shows a rendered equation for two vertical monitors, bug2.png for a
> single one, and horiz.png displays that same equation being rendered on
> a horizontal monitor (i.e., this is the expected result).
>
> Looking into `preview.el', it seems like that `preview-get-dpi' (called
> by `preview-get-geometry', which is in turn called by
> `preview-generate-preview') calculates the wrong "resolution".  The
> relevant implementation is
>
>     (defun preview-get-dpi ()
>       (let* ((monitor-attrs (frame-monitor-attributes))
>              (mm-dims (cdr (assoc 'mm-size monitor-attrs)))
>              (mm-width (nth 0 mm-dims))
>              (mm-height (nth 1 mm-dims))
>              (pixel-dims (cl-cdddr (assoc 'geometry monitor-attrs)))
>              (pixel-width (nth 0 pixel-dims))
>              (pixel-height (nth 1 pixel-dims)))
>         (cons (/ (* 25.4 pixel-width) mm-width)
>               (/ (* 25.4 pixel-height) mm-height))))
>
> An example output of `frame-monitor-attributes' for a horizontal
> monitor:
>
>     '((name . "DP1")
>       (geometry 0 0 1920 1080)
>       (workarea 0 0 1920 1080)
>       (mm-size 530 300)
>       (frames <<omitted>>)
>       (source . "XRandR 1.5"))
>
> The same monitor in "vertical-mode" returns:
>
>     '((name . "DP1")
>       (geometry 0 0 1080 1920)
>       (workarea 0 0 1080 1920)
>       (mm-size 530 300)
>       (frames <<omitted>>)
>       (source . "XRandR 1.5"))
>
> Crucially, the returned physical width and height of the monitor don't
> change, but the geometry—what will be the pixel width and height—does.
> However, turning the monitor by 90 degrees obviously switches the
> physical width an height around as well, although that perhaps can't be
> reported property.  In such a situation, we actually compare the pixel
> _width_ of the monitor with its physical _height_, as well as its pixel
> height with its width.  Naturally, and depending on the specific setup,
> this produces too narrow or too wide previews.
>
> I have fixed this locally by only comparing comparable values; i.e.,
> instead of
>
>     (cons (/ (* 25.4 pixel-width) mm-width)
>           (/ (* 25.4 pixel-height) mm-height))
>
> I wrote something like
>
>     (cons (/ (* 25.4 (max pixel-width pixel-height)) (max mm-width mm-height))
>           (/ (* 25.4 (min pixel-width pixel-height)) (min mm-width mm-height)))
>
> This fixed the problem for me, but I don't know if there is some
> situation (or strange resolution) in which it would be correct to
> compare some other combination of values.
>
> Hopefully this was comprehensible.  If not, feel free to ask for more
> information.
>
> Best,
>   Tony

Thanks.

The problem here is under version 1.5 of the RandR extension, monitors
can have multiple outputs attached to multiple CRTCs, each with its own
transform.  So the X server has to stretch itself very hard to calculate
the actual width and height of the monitor area.

I suggest filing a bug under xorgproto asking to clarify how the
physical width and height of a monitor can be reconciled with the
transforms of each of its outputs CRT controllers.

Under version 1.3 of the extension, Emacs should flip the physical
monitor width and height itself.  Unfortunately, version 1.3 is obsolete
and does not really take modern features (such as outputs that do not
display desktop contents) into account.