unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* Help with windows and 'quit-restore
@ 2017-02-28  1:01 Eric Abrahamsen
  2017-03-01  0:57 ` Michael Heerdegen
  0 siblings, 1 reply; 9+ messages in thread
From: Eric Abrahamsen @ 2017-02-28  1:01 UTC (permalink / raw)
  To: help-gnu-emacs

I'm having a heck of a time understanding how the 'quit-restore window
parameter actually works.

I've got a pop-up window that goes into special-mode, and I'm trying to
get the right level of control over both the window splitting, and the
behavior of "q" (quit-window).

First it was the "manual way":

#+BEGIN_SRC elisp
(let* ((buf (get-buffer-I-want-to-pop-up))
       (window (get-window-I-want-to-split))
       (buffer-window (split-window window 0.5
				    'right)))
  (set-window-buffer buffer-window buf)
  (display-buffer-record-window 'window buffer-window buf))
#+END_SRC

The SIZE and SIDE args to `split-window' are calculated elsewhere, just
hard-coded in my cut-down example. This allows me to split windows
exactly as I want.

This call to `display-buffer-record-window', however, does *not* set up
the `quit-restore parameter correctly: when I hit "q" in the buffer, the
buffer quits but the popped-up window remains, displaying some other
buffer, usually a copy of a buffer that's already visible.

I can get a perfect 'quit-restore with the "automatic way":

#+BEGIN_SRC elisp
(display-buffer
 buf
 `(display-buffer-pop-up-window . ((window-height . 0.5))))
#+END_SRC

Again, cut down to show the final effect. This gives me exactly the
quit-restore behavior I want, but the window splitting is erratic: Emacs
tries to DTRT, but it isn't TRT, and no amount of fiddling with the
`split-*-threshold' variables works. It's forever splitting the wrong
window, or splitting it the wrong way.

So I think what I want is to stick with the former incantation, but learn
how to call `display-buffer-record-window' correctly. I followed
`display-buffer-pop-up-window' as far as I could, but really can't see
how it builds its 'quit-restore.

Can anyone point me to the correct call for that? Or reveal some better
solution to the problem?

Thanks,
Eric




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

* Re: Help with windows and 'quit-restore
  2017-02-28  1:01 Help with windows and 'quit-restore Eric Abrahamsen
@ 2017-03-01  0:57 ` Michael Heerdegen
  2017-03-01 16:23   ` Eric Abrahamsen
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Heerdegen @ 2017-03-01  0:57 UTC (permalink / raw)
  To: Eric Abrahamsen; +Cc: help-gnu-emacs

Eric Abrahamsen <eric@ericabrahamsen.net> writes:

> Can anyone point me to the correct call for that?

M-x trace-functions shows that your call is equivalent to the one caused
by `display-buffer', so I guess the different behavior has another
reason.

`display-buffer' calls `window--display-buffer' which does some more
stuff - the (set-window-prev-buffers window nil) call looks like it
could be related.  Maybe you could try using `window--display-buffer' in
your code?

> Or reveal some better solution to the problem?

The better solution would be to get it work with `display-buffer', I
guess.


Michael.



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

* Re: Help with windows and 'quit-restore
@ 2017-03-01  7:10 martin rudalics
  2017-03-01 16:09 ` Eric Abrahamsen
  0 siblings, 1 reply; 9+ messages in thread
From: martin rudalics @ 2017-03-01  7:10 UTC (permalink / raw)
  To: eric; +Cc: help-gnu-emacs

 > I'm having a heck of a time understanding how the 'quit-restore window
 > parameter actually works.
 >
 > I've got a pop-up window that goes into special-mode, and I'm trying to
 > get the right level of control over both the window splitting, and the
 > behavior of "q" (quit-window).
 >
 > First it was the "manual way":
 >
 > #+BEGIN_SRC elisp
 > (let* ((buf (get-buffer-I-want-to-pop-up))
 >        (window (get-window-I-want-to-split))
 >        (buffer-window (split-window window 0.5

Do these 0.5 mean that you have advised ‘split-window’?

 >                                     'right)))
 >   (set-window-buffer buffer-window buf)
 >   (display-buffer-record-window 'window buffer-window buf))
 > #+END_SRC
 >
 > The SIZE and SIDE args to `split-window' are calculated elsewhere, just
 > hard-coded in my cut-down example. This allows me to split windows
 > exactly as I want.
 >
 > This call to `display-buffer-record-window', however, does *not* set up
 > the `quit-restore parameter correctly: when I hit "q" in the buffer, the
 > buffer quits but the popped-up window remains, displaying some other
 > buffer, usually a copy of a buffer that's already visible.

It does set up the ‘quit-restore’ parameter correctly.  The one missing
piece is that you didn't clear the new window's previous buffers by
doing something like

(let* ((buf (get-buffer-I-want-to-pop-up))
        (window (get-window-I-want-to-split))
        (buffer-window (split-window window 0.5
                                     'right)))
   (set-window-buffer buffer-window buf)
   (display-buffer-record-window 'window buffer-window buf)
   (set-window-prev-buffers buffer-window nil))

This is a technical issue I can't solve at a lower level: When Emacs
creates a new window, it first displays the buffer displayed in the
selected window in that new window and that buffer becomes the first
"previous" buffer of the new window.  So the new window ("buffer-window"
in your parlance) already showed a buffer _before_ it did show the
buffer you specify by `get-buffer-I-want-to-pop-up´.  In order to make
‘quit-window’ do what you mean, you have to clear that remembrance
first.

I'll probably add a sentence about this to the doc-string of
‘display-buffer-record-window’ although there will be no warranty that
that function will always work outside the scope of ‘display-buffer’.

martin




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

* Re: Help with windows and 'quit-restore
  2017-03-01  7:10 martin rudalics
@ 2017-03-01 16:09 ` Eric Abrahamsen
  0 siblings, 0 replies; 9+ messages in thread
From: Eric Abrahamsen @ 2017-03-01 16:09 UTC (permalink / raw)
  To: help-gnu-emacs

martin rudalics <rudalics@gmx.at> writes:

>> I'm having a heck of a time understanding how the 'quit-restore window
>> parameter actually works.
>>
>> I've got a pop-up window that goes into special-mode, and I'm trying to
>> get the right level of control over both the window splitting, and the
>> behavior of "q" (quit-window).
>>
>> First it was the "manual way":
>>
>> #+BEGIN_SRC elisp
>> (let* ((buf (get-buffer-I-want-to-pop-up))
>>        (window (get-window-I-want-to-split))
>>        (buffer-window (split-window window 0.5
>
> Do these 0.5 mean that you have advised ‘split-window’?

No, the 0.5 and 'right were there just to simplify the example. This
buffer is popped up differently in different contexts and those values
are dynamically generated.

>>                                     'right)))
>>   (set-window-buffer buffer-window buf)
>>   (display-buffer-record-window 'window buffer-window buf))
>> #+END_SRC
>>
>> The SIZE and SIDE args to `split-window' are calculated elsewhere, just
>> hard-coded in my cut-down example. This allows me to split windows
>> exactly as I want.
>>
>> This call to `display-buffer-record-window', however, does *not* set up
>> the `quit-restore parameter correctly: when I hit "q" in the buffer, the
>> buffer quits but the popped-up window remains, displaying some other
>> buffer, usually a copy of a buffer that's already visible.
>
> It does set up the ‘quit-restore’ parameter correctly.  

I could have phrased that more accurately :)

> The one missing piece is that you didn't clear the new window's
> previous buffers by doing something like
>
> (let* ((buf (get-buffer-I-want-to-pop-up))
>        (window (get-window-I-want-to-split))
>        (buffer-window (split-window window 0.5
>                                     'right)))
>   (set-window-buffer buffer-window buf)
>   (display-buffer-record-window 'window buffer-window buf)
>   (set-window-prev-buffers buffer-window nil))

Aha! Michael Heerdegen's previous reply also pointed me in this
direction. I will give this a shot.

> This is a technical issue I can't solve at a lower level: When Emacs
> creates a new window, it first displays the buffer displayed in the
> selected window in that new window and that buffer becomes the first
> "previous" buffer of the new window.  So the new window ("buffer-window"
> in your parlance) already showed a buffer _before_ it did show the
> buffer you specify by `get-buffer-I-want-to-pop-up´.  In order to make
> ‘quit-window’ do what you mean, you have to clear that remembrance
> first.
>
> I'll probably add a sentence about this to the doc-string of
> ‘display-buffer-record-window’ although there will be no warranty that
> that function will always work outside the scope of ‘display-buffer’.

Whatever the correct technical solution is, both the docs and the code
are pretty confusing. I think the key piece of missing information re
quit-restore is that, if there's a history of previously-displayed
buffers in this window, quitting the displayed buffer will display the
next buffer in the history. If there *isn't* such a history, quitting
the buffer will delete the window completely.

(Is that always true? Are there any other factors that influence this
behavior?)

It's a complicated topic, and probably hard to document. The Window
History section of the manual mentions previous buffers, but doesn't
mentioned the connection to quit-restore behavior.

In Quitting Windows, under the description of `quit-restore-window', it
says "If WINDOW was created specially for displaying its buffer, this
function deletes WINDOW..." When I was writing my functions I read that,
but didn't understand what "created specially" meant. My understanding
now is that that means there's no previous buffer history, but this
documentation makes it sound like this is something that happens at
window creation time, not something you can set later.

Lastly, the quit-restore description in Window Parameters says what the
parameter elements *are*, but (for the first two elements at least) not
what they *do*.

Those are three areas where I'd suggest tweaking the docs. I'd be happy
to provide specific suggestions or patches.

Lastly, as a shot in the dark, mightn't it make sense to allow
`display-buffer-record-window' to set the window history? The docstring
says the purpose of the function is to install or update the
quit-restore parameter -- wouldn't it make sense to let it set the
history part of the parameter, too?

Anyway, thanks very much for these tips! I'm sure I have enough
information to solve my problem now.

Eric




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

* Re: Help with windows and 'quit-restore
  2017-03-01  0:57 ` Michael Heerdegen
@ 2017-03-01 16:23   ` Eric Abrahamsen
  0 siblings, 0 replies; 9+ messages in thread
From: Eric Abrahamsen @ 2017-03-01 16:23 UTC (permalink / raw)
  To: help-gnu-emacs

Michael Heerdegen <michael_heerdegen@web.de> writes:

> Eric Abrahamsen <eric@ericabrahamsen.net> writes:
>
>> Can anyone point me to the correct call for that?
>
> M-x trace-functions shows that your call is equivalent to the one caused
> by `display-buffer', so I guess the different behavior has another
> reason.
>
> `display-buffer' calls `window--display-buffer' which does some more
> stuff - the (set-window-prev-buffers window nil) call looks like it
> could be related.  Maybe you could try using `window--display-buffer' in
> your code?

Yup, with Martin's later response I think you're right that
`set-window-prev-buffers` is the key here. I did try just sticking
`window--display-buffer` in my function, which seemed to *prevent* the
buffer from being displayed, though I haven't had time to look into it
at all, I'm sure I was just doing something dumb.

>> Or reveal some better solution to the problem?
>
> The better solution would be to get it work with `display-buffer', I
> guess.

This was definitely my instinct, and I would still prefer to be using
the highest-level functions possible. But `display-buffer' with the
`display-buffer-pop-up-window' action just makes it too hard to target
the right window for splitting. Its whole point is that it figures out a
reasonable default for you, and while that works out fine in some cases,
in other cases I really need to say "use this window right here". There
are a million knobs to twiddle, though, and maybe I can hit some
combination that works.

Thanks,
Eric




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

* Re: Help with windows and 'quit-restore
@ 2017-03-01 20:13 martin rudalics
  2017-03-03 19:27 ` Eric Abrahamsen
  0 siblings, 1 reply; 9+ messages in thread
From: martin rudalics @ 2017-03-01 20:13 UTC (permalink / raw)
  To: eric; +Cc: help-gnu-emacs@gnu.org >> GNU Emacs List

 > Whatever the correct technical solution is, both the docs and the code
 > are pretty confusing. I think the key piece of missing information re
 > quit-restore is that, if there's a history of previously-displayed
 > buffers in this window, quitting the displayed buffer will display the
 > next buffer in the history. If there *isn't* such a history, quitting
 > the buffer will delete the window completely.
 >
 > (Is that always true? Are there any other factors that influence this
 > behavior?)

I think it's true.

 > It's a complicated topic, and probably hard to document. The Window
 > History section of the manual mentions previous buffers, but doesn't
 > mentioned the connection to quit-restore behavior.
 >
 > In Quitting Windows, under the description of `quit-restore-window', it
 > says "If WINDOW was created specially for displaying its buffer, this
 > function deletes WINDOW..." When I was writing my functions I read that,
 > but didn't understand what "created specially" meant. My understanding
 > now is that that means there's no previous buffer history, but this
 > documentation makes it sound like this is something that happens at
 > window creation time, not something you can set later.

‘split-window’ has two connotations: The first one is that a user wants
to see two distinct portions of the same buffer.  The second one is that
the user wants to see two different buffers.  In the second case we
emulate a "pristine" history by pretending that the new window never
showed its initial buffer.  And we do that only for ‘display-buffer’ and
its clients because only in those cases we know for sure that the window
should have shown a different buffer right away.

 > Lastly, the quit-restore description in Window Parameters says what the
 > parameter elements *are*, but (for the first two elements at least) not
 > what they *do*.

Right.  I carefully tried to avoid saying that.  Once created, we change
the contents of the ‘quit-restore’ parameter only when we reuse its
window via ‘display-buffer’.  But we may show another buffer in that
window (and change the history of buffers shown in that window) any
time.  So when ‘quit-restore-window’ gets eventually called, it has to
deal with the situation that the ‘quit-restore’ parameter is out of
date, i.e., presumably no more describes the state of things at the time
it was created.  And in that occasion, the history of buffers previously
shown in that window will prevail.

 > Those are three areas where I'd suggest tweaking the docs. I'd be happy
 > to provide specific suggestions or patches.

Please do that.

 > Lastly, as a shot in the dark, mightn't it make sense to allow
 > `display-buffer-record-window' to set the window history? The docstring
 > says the purpose of the function is to install or update the
 > quit-restore parameter -- wouldn't it make sense to let it set the
 > history part of the parameter, too?

Maybe.  But ‘window--display-buffer’ currently does

     (display-buffer-record-window type window buffer) <---
     (unless (eq buffer (window-buffer window))
       (set-window-dedicated-p window nil)
       (set-window-buffer window buffer) <---
       (when dedicated
	(set-window-dedicated-p window dedicated))
       (when (memq type '(window frame))
	(set-window-prev-buffers window nil))) <---

and I'm not sure whether we anywhere might rely on the
‘set-window-prev-buffers’ call following the ‘set-window-buffer’ call.

martin




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

* Re: Help with windows and 'quit-restore
  2017-03-01 20:13 martin rudalics
@ 2017-03-03 19:27 ` Eric Abrahamsen
  0 siblings, 0 replies; 9+ messages in thread
From: Eric Abrahamsen @ 2017-03-03 19:27 UTC (permalink / raw)
  To: help-gnu-emacs

martin rudalics <rudalics@gmx.at> writes:

>> Whatever the correct technical solution is, both the docs and the code
>> are pretty confusing. I think the key piece of missing information re
>> quit-restore is that, if there's a history of previously-displayed
>> buffers in this window, quitting the displayed buffer will display the
>> next buffer in the history. If there *isn't* such a history, quitting
>> the buffer will delete the window completely.
>>
>> (Is that always true? Are there any other factors that influence this
>> behavior?)
>
> I think it's true.

I found the root of the behavior that was making me think I was crazy.
Basically I'm trying to replicate the behavior of this call:

(display-buffer "some buffer" '(display-buffer-pop-up-window))

But in a way that I can reliably select which window gets split to show
the pop up. (I'd still rather just be using `display-buffer', but that's
a different subject.)

This should be the lower-level equivalent:

(let ((buf "*scratch*")
      (new-window
       (split-window (selected-window))))
  (set-window-buffer new-window buf)
  (display-buffer-record-window 'window new-window buf)
  (set-window-prev-buffers new-window nil))

But it doesn't kill the window after calling `quit-window'. This is
apparently because `quit-restore-window' decides whether or not to kill
the window by checking (window.el:4766):

(eq (nth 3 quit-restore) buffer)

There's no call to `get-buffer' anywhere down the line, so (nth 3
quit-restore) is a buffer string name, while buffer is a buffer object.
Ergo, no kill window. If I'd started with a `get-buffer' in the let form
above, all would have been well. `display-buffer' calls `get-buffer'
first thing, so you don't see it there.

I don't know if this is a bug -- I'm the one insisting on doing it
manually, after all -- but it also wouldn't hurt to put a `get-buffer'
in `display-buffer-record-window' and ensure that it's always a buffer
object that gets recorded in the quit-restore parameter.

Or maybe, because the buffer might get deleted at any time, allow a
string and improve the check in `quit-restore-window'?

Either way, I vote adding some sort of safety.

I'm still up for doc suggestions, once I'm confident I actually
understand what's happening.

Eric




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

* Re: Help with windows and 'quit-restore
@ 2017-03-04  9:59 martin rudalics
  2017-03-04 17:37 ` Eric Abrahamsen
  0 siblings, 1 reply; 9+ messages in thread
From: martin rudalics @ 2017-03-04  9:59 UTC (permalink / raw)
  To: eric; +Cc: help-gnu-emacs

 > I found the root of the behavior that was making me think I was crazy.
 > Basically I'm trying to replicate the behavior of this call:
 >
 > (display-buffer "some buffer" '(display-buffer-pop-up-window))

The signature of ‘display-buffer’ is

   (display-buffer BUFFER-OR-NAME &optional ACTION FRAME)

while

 > But in a way that I can reliably select which window gets split to show
 > the pop up. (I'd still rather just be using `display-buffer', but that's
 > a different subject.)
 >
 > This should be the lower-level equivalent:
 >
 > (let ((buf "*scratch*")
 >       (new-window
 >        (split-window (selected-window))))
 >   (set-window-buffer new-window buf)
 >   (display-buffer-record-window 'window new-window buf)
 >   (set-window-prev-buffers new-window nil))

that of ‘display-buffer-record-window’ is

(display-buffer-record-window TYPE WINDOW BUFFER)

So the latter has no optional arguments (which is some sort of reminder
that the function is more strict in the interpretation of its arguments)
and uses BUFFER instead of BUFFER-OR-NAME (which means that it does not
allow a buffer name as argument).  This distinction is valuable when
coding with ‘eldoc-mode’: Whenever you see BUFFER-OR-NAME in the
argument list you know you are at the "user" level where more things are
allowed and more things are checked.  When you see plain BUFFER you know
you are at a "coder" level where less things are allowed and less things
are checked.

 > But it doesn't kill the window after calling `quit-window'. This is
 > apparently because `quit-restore-window' decides whether or not to kill
 > the window by checking (window.el:4766):
 >
 > (eq (nth 3 quit-restore) buffer)
 >
 > There's no call to `get-buffer' anywhere down the line, so (nth 3
 > quit-restore) is a buffer string name, while buffer is a buffer object.
 > Ergo, no kill window. If I'd started with a `get-buffer' in the let form
 > above, all would have been well. `display-buffer' calls `get-buffer'
 > first thing, so you don't see it there.

Right.  ‘display-buffer’ is "user" level while
‘display-buffer-record-window’ is "coder" level.  What you do is
"coding" and you are supposed to know what you do.

 > I don't know if this is a bug -- I'm the one insisting on doing it
 > manually, after all -- but it also wouldn't hurt to put a `get-buffer'
 > in `display-buffer-record-window' and ensure that it's always a buffer
 > object that gets recorded in the quit-restore parameter.

I have tried to use BUFFER-OR-NAME and BUFFER in a consistent manner
throughout the window.el code base.  If you compare the current code
with earlier versions you will notice that this required some work.  See
the ‘window-normalize-buffer’ function which interprets nil as meaning
the current buffer and does not allow a string to name a non-existent
buffer.  All these checks are meant for catching user errors and are
redundant at lower levels.  So I'd rather not change that.

 > Or maybe, because the buffer might get deleted at any time, allow a
 > string and improve the check in `quit-restore-window'?

Why?  When calling ‘quit-restore-window’

(buffer (window-buffer window))

will get me a valid buffer while

(nth 3 quit-restore)

will get me a killed buffer so

(eq (nth 3 quit-restore) buffer)

should be

 > Either way, I vote adding some sort of safety.

safe enough.  Don't you agree?

 > I'm still up for doc suggestions, once I'm confident I actually
 > understand what's happening.

We should move our discussion to emcs-devel, also because I'm not
subscribed to help-gnu-emacs.  There you will also find a patch for
bug#25946 which incorporates your earlier proposal to clear the list of
previous buffers in ‘display-buffer-record-window’.

martin




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

* Re: Help with windows and 'quit-restore
  2017-03-04  9:59 martin rudalics
@ 2017-03-04 17:37 ` Eric Abrahamsen
  0 siblings, 0 replies; 9+ messages in thread
From: Eric Abrahamsen @ 2017-03-04 17:37 UTC (permalink / raw)
  To: help-gnu-emacs

martin rudalics <rudalics@gmx.at> writes:

[...]

> Right.  ‘display-buffer’ is "user" level while
> ‘display-buffer-record-window’ is "coder" level.  What you do is
> "coding" and you are supposed to know what you do.

Well, now I do :)

>> I don't know if this is a bug -- I'm the one insisting on doing it
>> manually, after all -- but it also wouldn't hurt to put a `get-buffer'
>> in `display-buffer-record-window' and ensure that it's always a buffer
>> object that gets recorded in the quit-restore parameter.
>
> I have tried to use BUFFER-OR-NAME and BUFFER in a consistent manner
> throughout the window.el code base.  If you compare the current code
> with earlier versions you will notice that this required some work.  See
> the ‘window-normalize-buffer’ function which interprets nil as meaning
> the current buffer and does not allow a string to name a non-existent
> buffer.  All these checks are meant for catching user errors and are
> redundant at lower levels.  So I'd rather not change that.

I didn't mean this as criticism or even really a bug report! If it's
intentional, and I understand why it is, then all is well.

[...]

>> I'm still up for doc suggestions, once I'm confident I actually
>> understand what's happening.
>
> We should move our discussion to emcs-devel, also because I'm not
> subscribed to help-gnu-emacs.  There you will also find a patch for
> bug#25946 which incorporates your earlier proposal to clear the list of
> previous buffers in ‘display-buffer-record-window’.

I still think slightly clearer docs could have helped me solve this
problem without coming to the list at all, so it's worthwhile. I'll
follow up on emacs-devel, and the bug report.

Thanks for your time,
Eric




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

end of thread, other threads:[~2017-03-04 17:37 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-28  1:01 Help with windows and 'quit-restore Eric Abrahamsen
2017-03-01  0:57 ` Michael Heerdegen
2017-03-01 16:23   ` Eric Abrahamsen
  -- strict thread matches above, loose matches on Subject: below --
2017-03-01  7:10 martin rudalics
2017-03-01 16:09 ` Eric Abrahamsen
2017-03-01 20:13 martin rudalics
2017-03-03 19:27 ` Eric Abrahamsen
2017-03-04  9:59 martin rudalics
2017-03-04 17:37 ` Eric Abrahamsen

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).