Subject: bug#15783: 24.3; posn-at-x-y is relative to the buffer area, posn-at-point is relative to the text area.

From: Eli Zaretskii <[email-masked]>
Date: Sat, 18 Nov 2017 10:40:00 +0200

> From: Alex <[email-masked]>
> Cc: [email-masked],  [email-masked]
> Date: Sat, 18 Nov 2017 00:35:27 -0600
> 
> >> It's pretty jarring to have the following return nil when a
> >> header-line is present:
> >> 
> >>   (let ((x-y (posn-x-y (posn-at-point))))
> >>     (equal x-y (posn-x-y (posn-at-x-y (car x-y)
> >>                                       (cdr x-y)))))
> >
> > It's less than ideal, but the alternatives are worse.
> 
> I don't understand.  The bug above seems to be about posn-col-row rather
> than posn(-at)-x-y.  What alternatives were considered, and how were
> they worse?

I think you didn't read all of the discussion that followed.  The
original bug report was about posn-col-row, but the underlying basic
issue is deeper.  The basic issue is the origin from which posn-at-x-y
and posn-at-point count their values.  There are two classes of
callers for these functions: those which start with mouse clicks, and
those which start with buffer positions.  They have basically
different needs, but both classes don't want to have special
application-level code that accounts for the header line, if it is
present.  So we changed the primitives to cater to each class in the
respective function: posn-at-x-y caters to those which deal with mouse
clicks, and posn-at-point caters to the other kind.  For the details,
see commit 9173a8f.

> >> Still, the above is pretty counterintuitive. If nothing else, I
> >> think this incompatibility should be highlighted.
> >
> > Not sure what "highlighted" means in this context.  What are you
> > suggesting in practice?
> 
> I was thinking about mentioning that you can't expect Elisp code such as
> the above to always be true.

Fine with me, but can you propose a patch for the documentation to do
that?

> Hmm, it appears that they're both wrong.  I believe this is the
> breakdown:
> 
>   1. Manual:
>      WHOLE is nil:     X and Y are relative to the text area
>      WHOLE is non-nil: X and Y are relative to the window area
> 
>   2. Docstring:
>      WHOLE is nil:     X and Y are relative to the text area
>      WHOLE is non-nil: X is relative to window area; Y to text area
> 
>   3. Actual:
>      WHOLE is nil:     X is relative to text area; Y to window area
>      WHOLE is non-nil: X and Y are relative to the window area

This is the same confusion about what "text area" means that is
present in many of our conversations.  The manual says:

  ‘Text Area’
       The “text area” of a frame is a somewhat fictitious area that can
       be embedded in the native frame.  Its position is unspecified.  Its
       width can be obtained by removing from that of the native width the
       widths of the internal border, one vertical scroll bar, and one
       left and one right fringe if they are specified for this frame, see
       *note Layout Parameters::.  Its height can be obtained by removing
       from that of the native height the widths of the internal border
       and the heights of the frame’s internal menu and tool bars and one
       horizontal scroll bar if specified for this frame.

This means the "text area" _includes_ the header line.  So when you
get this result in "emacs -Q":

  M-: (setq header-line-format "Hi There") RET
  M-: (posn-at-x-y 0 0)
   => (#<window 3 on *scratch*> header-line (8 . 0) 0 ("Hi There" . 1) nil (1 . -1) nil (0 . 0) (8 . 16))

it tells you that the origin is the left corner of the text area,
because the X coordinate is 8, not zero, and the position in the
header-line string is 1, not zero.  If, OTOH, you invoke posn-at-x-y
with last argument non-nil, you will get zero for X, which means the
origin is the left corner of the window, which is at the left edge of
the left fringe.

Therefore, the doc string is accurately describing the actual behavior.
Do you agree now?

> The behaviour in #1 makes the most sense to me, and I believe that was
> the behaviour before Emacs 24.

That behavior required features that used mouse clicks as input and
then looked for the corresponding buffer positions to account for the
header line in application code, which caused the bugs discussed in
the thread I pointed to.

> Any change of reverting to the behaviour to #1, or should the
> documentation just be updated to #3?

We are not going back.  The current behavior, while less than ideal,
caused zero bugs since it was introduced, AFAIK.  The documentation
should be updated, of course (I see that the above-mentioned commit
didn't do that, which is probably why the old description survived to
this day).

Thanks.