Subject: bug#15133: 24.3.50; REGRESSION: `after-make-frame-functions' now run with wrong frame selected

From: martin rudalics <[email-masked]>
Date: Tue, 20 Aug 2013 19:24:33 +0200

> Can you please tell me what to check, and how?  It's not clear to me what
 > you are asking/suggesting; sorry.

Whether with older versions your `fit-frame' function works with plain
`display-buffer', that is, bypassing `pop-to-buffer'.  Obviously,
`special-display-popup-frame' is disallowed as well because it does

	       (with-current-buffer buffer
		 (make-frame (append args special-display-frame-alist))))

and `temp-buffer-window-show' is disallowed because it does

     (with-current-buffer buffer
        ...
	      (setq window (display-buffer buffer action)))

 >> You want to apply `fit-frame' to the buffer you eventually want to
 >> display on the new frame.  Right?
 >
 > I want to apply it to the frame (not to a buffer) _after_ it has been
 > displayed.  Previously, creating the frame (`make-frame') also displayed it,
 > and it did so before hook `after-create-frame-functions' was invoked.

It displayed it if and only if it was current at the time `make-frame'
was called.  Also, at the time `after-make-frame-functions' is called
the buffer is not yet "displayed".  `make-frame' simply sets a slot in
the frame structure to reference that buffer.

 >> The _current_ buffer.
 >
 > The question is which buffer should be current for that frame at that point.

It's up to the caller to determine that, `make-frame' wouldn't know.

 > I'm not sure the doc string should really have said "current buffer", as in
 > `current-buffer'.  Seems like what was intended - what makes sense in terms
 > of the hook, and what I have always thought has been the behavior until now -
 > is the buffer the frame was created to display (which is harder to say than
 > "current buffer").  IOW, the buffer that ends up displayed in the frame.

This is not what `make-frame' does.

 > The key part of that doc string, for me, is that it returns a new frame that
 > is already displayed.

No.  Otherwise with `display-buffer' you would first see one buffer and
then another - or at least some kind of flicker.

 > No one ever _sees_ a newly created frame first display
 > the `current-buffer' and then switch to the actual buffer to be displayed in
 > the frame.

Then put a `sit-for' in `display-buffer-pop-up-frame' before it calls
`window--display-buffer'.

 > What you see is only the frame displayed (immediately) with the proper buffer.
 > And that displayed frame, with the buffer it displays, is what has always
 > been passed to the `after-make-frame-functions'.

Not necessarily - only when the buffer current at that time was also the
buffer finally displayed in that frame.

 > And previously that frame was always displayed before `after-make-frame-*'
 > was invoked.  So in a hook function you could do this, for example:
 >
 >  (save-window-excursion
 >    (select-frame frame)
 >    (setq specbuf-p
 >          (and empty-buf-p
 >               (special-display-p (buffer-name (window-buffer))))))
 >
 > And the `window-buffer' was the buffer that the frame displayed, which was
 > already the buffer that the frame was created to display.

I miss you here.  For `display-buffer' the hook is called after the
frame has been "created" but before it is ascertained that it displays
the "right" buffer.

 > Anyway, here is my question, given this discrepancy.  You want to make
 > the buffer be consistent.

I want `display-buffer' DTRT.  This means that it should call
`make-frame' with the buffer to be displayed current.

 > OK, But you have so far chosen the
 > `current-buffer' as the buffer to use, perhaps from a reading of the
 > doc string.  Why not instead choose the buffer that will be displayed
 > in the frame, consistently?

But that's what I do: I make the buffer "that will be displayed in the
frame" current so `make-frame' assigns it immediately to the new frame's
root window.  And I have to do this in the buffer display code because I
cannot pass a buffer to `make-frame' just as I cannot pass a buffer to
`split-window'.

 > IOW, for your test above, always have the buffer be *Messages*, since
 > that is the buffer displayed in the frame that is passed to
 > `after-make-frame-functions'?

It's not passed.  It's the current buffer at the time
`after-make-frame-functions' is called.

 > What is the use case for passing the
 > frame, which will display (or is already displaying?) the *Messages*
 > buffer, have as its root-window buffer some other buffer (*scratch*) that
 > is not even displayed in that frame and perhaps never will be?

`make-frame' has been designed that way - display the current buffer in
the new frame.  Just as `split-window' displays the buffer shown in the
window to be split in the new window too.

 > Sounds like you are suggesting the same thing I suggested immediately
 > above, and you are providing code that implements that.  And yes, a
 > quick trial indicates that that does seem to work, so far.  I will
 > load that code at startup and let you know if I notice any problems.

Thanks, martin