GNU bug report logs - #47300
delete-window to select window with same position

Previous Next

Package: emacs;

Reported by: Juri Linkov <juri <at> linkov.net>

Date: Sun, 21 Mar 2021 21:15:02 UTC

Severity: minor

Tags: fixed, patch

Fixed in version 28.0.50

Done: Juri Linkov <juri <at> linkov.net>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 47300 in the body.
You can then email your comments to 47300 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Sun, 21 Mar 2021 21:15:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Juri Linkov <juri <at> linkov.net>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Sun, 21 Mar 2021 21:15:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: bug-gnu-emacs <at> gnu.org
Subject: delete-window to select window with same position
Date: Sun, 21 Mar 2021 22:31:27 +0200
[Message part 1 (text/plain, inline)]
People still have trouble with unpredictable behavior of 'C-x 0'
that selects an unexpected window after the current window is deleted.

This is a recent example:
https://old.reddit.com/r/emacs/comments/m8omt0/how_can_deletewindow_cx_0_be_configured_to_stay/

The previous failed attempt to fix this was in bug#32790.

I still don't understand the current logic what window is selected
after deleting the selected window with 'C-x 0'.

But maybe this could be customizable?  Tried to write an advice:

(advice-add 'delete-window :around
            (lambda (orig-fun &optional window)
              (if window
                  ;; Non-interactive call
                  (funcall orig-fun window)
                ;; Interactive call
                (let* ((pos (window-absolute-pixel-position))
                       (x (when pos (/ (car pos) (frame-char-width))))
                       (y (when pos (/ (cdr pos) (frame-char-height)))))
                  (funcall orig-fun window)
                  ;; Select window that takes space from the deleted window
                  (when (and x y)
                    (select-window (window-at x y))))))
            '((name . delete-window-keep-pos)))

Maybe something like this could be adapted to delete-window
by adding an optional interactive argument keep-pos:

[delete-window-keep-pos.patch (text/x-diff, inline)]
diff --git a/lisp/window.el b/lisp/window.el
index f27631bb86..e2029406c7 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -4177,7 +4177,7 @@ window--before-delete-windows
                (push (list buf start-m pos-m) prev-buf)
                (set-window-prev-buffers win prev-buf)))))))
 
-(defun delete-window (&optional window)
+(defun delete-window (&optional window keep-pos)
   "Delete WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
 Return nil.
@@ -4194,13 +4194,16 @@ delete-window
 argument.  Signal an error if WINDOW is either the only window on
 its frame, the last non-side window, or part of an atomic window
 that is its frame's root window."
-  (interactive)
+  (interactive (list nil t))
   (when switch-to-buffer-preserve-window-point
     (window--before-delete-windows))
+  (setq keep-pos (and keep-pos (not window) (window-absolute-pixel-position)))
   (setq window (window-normalize-window window))
   (let* ((frame (window-frame window))
 	 (function (window-parameter window 'delete-window))
 	 (parent (window-parent window))
+	 (keep-pos-x (when keep-pos (/ (car keep-pos) (frame-char-width))))
+	 (keep-pos-y (when keep-pos (/ (cdr keep-pos) (frame-char-height))))
 	 atom-root)
     (window--check frame)
     (catch 'done
@@ -4259,6 +4262,8 @@ delete-window
 	  ;; `delete-window-internal' has selected a window that should
 	  ;; not be selected, fix this here.
 	  (other-window -1 frame))
+	(when (and keep-pos-x keep-pos-y (window-at keep-pos-x keep-pos-y))
+	  (select-window (window-at keep-pos-x keep-pos-y)))
 	(window--check frame)
 	;; Always return nil.
 	nil))))

Added tag(s) patch. Request was from Lars Ingebrigtsen <larsi <at> gnus.org> to control <at> debbugs.gnu.org. (Mon, 22 Mar 2021 18:59:02 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Tue, 18 May 2021 14:50:02 GMT) Full text and rfc822 format available.

Message #10 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Lars Ingebrigtsen <larsi <at> gnus.org>
To: Juri Linkov <juri <at> linkov.net>
Cc: martin rudalics <rudalics <at> gmx.at>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Tue, 18 May 2021 16:49:01 +0200
Juri Linkov <juri <at> linkov.net> writes:

> People still have trouble with unpredictable behavior of 'C-x 0'
> that selects an unexpected window after the current window is deleted.
>
> This is a recent example:
> https://old.reddit.com/r/emacs/comments/m8omt0/how_can_deletewindow_cx_0_be_configured_to_stay/
>
> The previous failed attempt to fix this was in bug#32790.
>
> I still don't understand the current logic what window is selected
> after deleting the selected window with 'C-x 0'.

`C-x 0' isn't a command I use much, so I don't really have much
intuition about how it's supposed to work.  But, indeed, playing around
with it, it seems unexpected that `C-x 0' selects a different window
(instead of remaining in the "merged" window).

> Maybe something like this could be adapted to delete-window
> by adding an optional interactive argument keep-pos:

If I'm reading that patch correctly (I haven't actually tested), that
seems more DWIM to me.  Perhaps Martin has some comments here; added to
the CCs.  (And if anybody else has an opinion here, please do chime in.)

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Tue, 18 May 2021 16:01:02 GMT) Full text and rfc822 format available.

Message #13 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Lars Ingebrigtsen <larsi <at> gnus.org>, Juri Linkov <juri <at> linkov.net>
Cc: 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Tue, 18 May 2021 18:00:40 +0200
>> People still have trouble with unpredictable behavior of 'C-x 0'
>> that selects an unexpected window after the current window is deleted.
>>
>> This is a recent example:
>> https://old.reddit.com/r/emacs/comments/m8omt0/how_can_deletewindow_cx_0_be_configured_to_stay/
>>
>> The previous failed attempt to fix this was in bug#32790.
>>
>> I still don't understand the current logic what window is selected
>> after deleting the selected window with 'C-x 0'.

By design it's the most recently used window (`get-mru-window') on the
same frame after the deleted window has been removed from its window
tree.

> `C-x 0' isn't a command I use much, so I don't really have much
> intuition about how it's supposed to work.  But, indeed, playing around
> with it, it seems unexpected that `C-x 0' selects a different window
> (instead of remaining in the "merged" window).
>
>> Maybe something like this could be adapted to delete-window
>> by adding an optional interactive argument keep-pos:
>
> If I'm reading that patch correctly (I haven't actually tested), that
> seems more DWIM to me.  Perhaps Martin has some comments here; added to
> the CCs.  (And if anybody else has an opinion here, please do chime in.)

Personally I don't care but people used to the current behavior might
get confused.  So an option should be the provided and could be "ON" by
default.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Tue, 18 May 2021 20:28:02 GMT) Full text and rfc822 format available.

Message #16 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Tue, 18 May 2021 23:17:37 +0300
> By design it's the most recently used window (`get-mru-window') on the
> same frame after the deleted window has been removed from its window
> tree.

I can't find where `get-mru-window' is called during window deletion.

> Personally I don't care but people used to the current behavior might
> get confused.  So an option should be the provided and could be "ON" by
> default.

Maybe a new option e.g. `delete-window-select' with type not boolean,
but a predicate with the default value `get-mru-window', and another
choice `delete-window-select-underlying' to select the "merged" window.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Wed, 19 May 2021 07:43:01 GMT) Full text and rfc822 format available.

Message #19 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Wed, 19 May 2021 09:42:49 +0200
> I can't find where `get-mru-window' is called during window deletion.

It's here in `delete-window-internal'

	  /* Now look whether `get-mru-window' gets us something.  */
	  mru_window = call1 (Qget_mru_window, frame);

> Maybe a new option e.g. `delete-window-select' with type not boolean,
> but a predicate with the default value `get-mru-window', and another
> choice `delete-window-select-underlying' to select the "merged" window.

`get-mru-window' is not a predicate.  You probably mean a function so
that someone could also use `get-lru-window' as value of that option?
The problem with such a function is that it has to be called with some
predefined sort of FRAME or ALL-FRAMES argument so some explanatory
footwork would be required.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Wed, 19 May 2021 16:32:02 GMT) Full text and rfc822 format available.

Message #22 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Wed, 19 May 2021 19:07:18 +0300
>> I can't find where `get-mru-window' is called during window deletion.
>
> It's here in `delete-window-internal'
>
> 	  /* Now look whether `get-mru-window' gets us something.  */
> 	  mru_window = call1 (Qget_mru_window, frame);

Thanks, I missed it because I searched with 'C-x p g get-mru-window'
instead of 'C-x p g get.mru.window'.

>> Maybe a new option e.g. `delete-window-select' with type not boolean,
>> but a predicate with the default value `get-mru-window', and another
>> choice `delete-window-select-underlying' to select the "merged" window.
>
> `get-mru-window' is not a predicate.  You probably mean a function so
> that someone could also use `get-lru-window' as value of that option?

Yes, a function to get a window to select after window deletion.

> The problem with such a function is that it has to be called with some
> predefined sort of FRAME or ALL-FRAMES argument so some explanatory
> footwork would be required.

It's fine to call it with a FRAME argument.  The problem is
how to write such a function that will find the window that
gets the screen space previously owned by the deleted window.
Could you recommend the right direction?  Maybe this window that
gets the screen space is just the parent of the deleted window?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Wed, 19 May 2021 17:42:01 GMT) Full text and rfc822 format available.

Message #25 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Wed, 19 May 2021 19:41:02 +0200
> It's fine to call it with a FRAME argument.  The problem is
> how to write such a function that will find the window that
> gets the screen space previously owned by the deleted window.
> Could you recommend the right direction?  Maybe this window that
> gets the screen space is just the parent of the deleted window?

No.  You probably have to save the old position of the deleted window's
point in frame coordinates and have the function that selects the new
window use the window that is now at that frame position.  The function
would be called instead of the currently hard-coded

	  mru_window = call1 (Qget_mru_window, frame);

and the call is fairly safe because the frame's first window has been
already selected at that time.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Sat, 22 May 2021 08:06:02 GMT) Full text and rfc822 format available.

Message #28 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Sat, 22 May 2021 10:05:20 +0200
[Message part 1 (text/plain, inline)]
> No.  You probably have to save the old position of the deleted window's
> point in frame coordinates and have the function that selects the new
> window use the window that is now at that frame position.

Just to explain what I meant above look at the attached patch.  I think
we should then move the `get-mru-window' call to `delete-window' too and
combine them all with the 'no-other-window' check so we never select a
window with NORECORD nil twice here.

martin
[window.el.diff (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Sat, 22 May 2021 21:28:02 GMT) Full text and rfc822 format available.

Message #31 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Sun, 23 May 2021 00:25:41 +0300
>> No.  You probably have to save the old position of the deleted window's
>> point in frame coordinates and have the function that selects the new
>> window use the window that is now at that frame position.
>
> Just to explain what I meant above look at the attached patch.  I think
> we should then move the `get-mru-window' call to `delete-window' too and
> combine them all with the 'no-other-window' check so we never select a
> window with NORECORD nil twice here.
>
> [2. text/x-patch; window.el.diff]...

I don't know why, but sometimes `window-at' returns 'nil'.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Sun, 23 May 2021 08:44:01 GMT) Full text and rfc822 format available.

Message #34 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Sun, 23 May 2021 10:43:32 +0200
> I don't know why, but sometimes `window-at' returns 'nil'.

This can happen because we are feeding it with the wrong arguments or
because there is a bug in its implementation.  I'd suggest you rewrite
`window-at' so you can easily put a breakpoint there when it returns nil
(or write your own `my-window-at' for that purpose) and wait till that
breakpoint gets hit.

Then have a look at the X, Y arguments and, if they are good, step with
GDB through coordinates_in_window to find out where and why it fails.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Tue, 25 May 2021 06:51:02 GMT) Full text and rfc822 format available.

Message #37 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Tue, 25 May 2021 08:50:23 +0200
> I don't know why, but sometimes `window-at' returns 'nil'.

`window-at' is pretty useless anyway.  Try the below instead.

martin

(defun window-at-pos (x y &optional frame)
  "Return live window at position X, Y on specified FRAME.
X and Y are counted in pixels from the origin at 0, 0 of FRAME's
native frame.  FRAME must specify a live frame and defaults to
the selected one.  Return nil if no such window can be found."
  (setq frame (window-normalize-frame frame))
  (catch 'window
    (walk-window-tree
     (lambda (window)
       (let ((edges (window-edges window nil nil t)))
	 (when (and (>= x (nth 0 edges)) (<= x (nth 2 edges))
		    (>= y (nth 1 edges)) (<= y (nth 3 edges)))
	   (throw 'window window))))
     frame nil nil)))






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Wed, 26 May 2021 21:41:02 GMT) Full text and rfc822 format available.

Message #40 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Thu, 27 May 2021 00:29:36 +0300
[Message part 1 (text/plain, inline)]
>> I don't know why, but sometimes `window-at' returns 'nil'.
>
> `window-at' is pretty useless anyway.  Try the below instead.
>
> (defun window-at-pos (x y &optional frame)

Thanks.  Now after tweaking I finally found what changes would make
the workable version:

[delete-window-use-posn.patch (text/x-diff, inline)]
diff --git a/lisp/window.el b/lisp/window.el
index fd1c617d6b..81a770ff32 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -4140,6 +4140,23 @@ window--in-subtree-p
 		(throw 'done t)
 	      (setq parent (window-parent parent))))))))
 
+(defun window-at-pos (x y &optional frame)
+  "Return live window at position X, Y on specified FRAME.
+X and Y are counted in pixels from the origin at 0, 0 of FRAME's
+native frame.  FRAME must specify a live frame and defaults to
+the selected one.  Return nil if no such window can be found."
+  (setq frame (window-normalize-frame frame))
+  (catch 'window
+    (walk-window-tree
+     (lambda (window)
+       (let ((edges (window-edges window nil nil t)))
+	 (when (and (>= x (nth 0 edges)) (< x (nth 2 edges))
+		    (>= y (nth 1 edges)) (< y (nth 3 edges)))
+	   (throw 'window window))))
+     frame nil nil)))
+
+(defvar delete-window-use-posn-at-point t)
+
 (defun delete-window (&optional window)
   "Delete WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
@@ -4162,7 +4179,7 @@ delete-window
   (let* ((frame (window-frame window))
 	 (function (window-parameter window 'delete-window))
 	 (parent (window-parent window))
-	 atom-root)
+	 atom-root posn-at-point-x posn-at-point-y window-at-posn-at-point)
     (window--check frame)
     (catch 'done
       ;; Handle window parameters.
@@ -4211,10 +4228,22 @@ delete-window
 	 (t
 	  ;; Can't do without resizing fixed-size windows.
 	  (window--resize-siblings window (- size) horizontal t)))
+        (when delete-window-use-posn-at-point
+          ;; Remember WINDOW's position at point.
+          (let ((edges (window-edges window nil nil t))
+                (posn-at-point (nth 2 (posn-at-point nil window))))
+            (when posn-at-point
+              (setq posn-at-point-x (+ (nth 0 edges) (car posn-at-point))
+                    posn-at-point-y (+ (nth 1 edges) (cdr posn-at-point))))))
 	;; Actually delete WINDOW.
 	(delete-window-internal window)
 	(window--pixel-to-total frame horizontal)
-	(when (and frame-selected
+        (when (and posn-at-point-x posn-at-point-y
+		   (setq window-at-posn-at-point
+			 (window-at-pos posn-at-point-x posn-at-point-y frame)))
+	  ;; Select window at WINDOW's position at point.
+	  (select-window window-at-posn-at-point))
+        (when (and frame-selected
 		   (window-parameter
 		    (frame-selected-window frame) 'no-other-window))
 	  ;; `delete-window-internal' has selected a window that should

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Thu, 27 May 2021 15:22:02 GMT) Full text and rfc822 format available.

Message #43 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Thu, 27 May 2021 17:20:51 +0200
+	 (when (and (>= x (nth 0 edges)) (< x (nth 2 edges))
+		    (>= y (nth 1 edges)) (< y (nth 3 edges)))

We have to mention the "<" somewhere.  For two side-by-side windows with
the right window's point at 1, we obviously must avoid the left window's
right edge because the X, Y coordinates set by pos_visible_p are the top
left edge of the character box at that position, i.e., 0, 0.

But OTOH the "<" leaves the right edge of a frame's rightmost window
unhandled and someone might use that function for other purposes.

[...]

It would be a tad more elegant to just save `posn-at-point' here ...

+              (setq posn-at-point-x (+ (nth 0 edges) (car posn-at-point))
+                    posn-at-point-y (+ (nth 1 edges) (cdr posn-at-point))))))
 	;; Actually delete WINDOW.
 	(delete-window-internal window)
 	(window--pixel-to-total frame horizontal)
-	(when (and frame-selected

... and delay extracting its car and cdr until here.

+        (when (and posn-at-point-x posn-at-point-y
+		   (setq window-at-posn-at-point
+			 (window-at-pos posn-at-point-x posn-at-point-y frame)))

I'd still urge you to transfer the `get-mru-window' call here too, that
is, the entire

	  /* Now look whether `get-mru-window' gets us something.  */
	  mru_window = call1 (Qget_mru_window, frame);
	  if (WINDOW_LIVE_P (mru_window)
	      && EQ (XWINDOW (mru_window)->frame, frame))
	    new_selected_window = mru_window;

	  /* If all ended up well, we now promote the mru window.  */
	  if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
	    Fselect_window (new_selected_window, Qnil);
	  else
	    fset_selected_window (f, new_selected_window);

block, and to include the

        (when (and frame-selected
		   (window-parameter
		    (frame-selected-window frame) 'no-other-window))
	  ;; `delete-window-internal' has selected a window that should
	  ;; not be selected, fix this here.
	  (other-window -1 frame))

so we can avoid selecting a new window up to four times when deleting a
window (the one remaining call in `delete-window-internal' does not
record the window and has to stay there).  It's simply not nice to do
that.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Mon, 31 May 2021 20:59:02 GMT) Full text and rfc822 format available.

Message #46 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Mon, 31 May 2021 23:46:49 +0300
> +	 (when (and (>= x (nth 0 edges)) (< x (nth 2 edges))
> +		    (>= y (nth 1 edges)) (< y (nth 3 edges)))
>
> We have to mention the "<" somewhere.  For two side-by-side windows with
> the right window's point at 1, we obviously must avoid the left window's
> right edge because the X, Y coordinates set by pos_visible_p are the top
> left edge of the character box at that position, i.e., 0, 0.
>
> But OTOH the "<" leaves the right edge of a frame's rightmost window
> unhandled and someone might use that function for other purposes.

I changed <= to < to fix only Y coordinates for top/bottom windows,
but maybe X coordinates should still use <= ?

> It would be a tad more elegant to just save `posn-at-point' here ...
>
> +              (setq posn-at-point-x (+ (nth 0 edges) (car posn-at-point))
> +                    posn-at-point-y (+ (nth 1 edges) (cdr posn-at-point))))))
>  	;; Actually delete WINDOW.
>  	(delete-window-internal window)
>  	(window--pixel-to-total frame horizontal)
> -	(when (and frame-selected
>
> ... and delay extracting its car and cdr until here.
>
> +        (when (and posn-at-point-x posn-at-point-y
> +		   (setq window-at-posn-at-point
> +			 (window-at-pos posn-at-point-x posn-at-point-y frame)))

Please note that the crucial difference is that now it uses
frame relative positions rather than window relative ones
with '(window-edges window nil nil t)' of the window to be deleted,
and window coordinates added to X and Y of posn-at-point.

> I'd still urge you to transfer the `get-mru-window' call here too, that
> is, the entire
>
> 	  /* Now look whether `get-mru-window' gets us something.  */
> 	  mru_window = call1 (Qget_mru_window, frame);
> 	  if (WINDOW_LIVE_P (mru_window)
> 	      && EQ (XWINDOW (mru_window)->frame, frame))
> 	    new_selected_window = mru_window;
>
> 	  /* If all ended up well, we now promote the mru window.  */
> 	  if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
> 	    Fselect_window (new_selected_window, Qnil);
> 	  else
> 	    fset_selected_window (f, new_selected_window);
>
> block, and to include the
>
>         (when (and frame-selected
> 		   (window-parameter
> 		    (frame-selected-window frame) 'no-other-window))
> 	  ;; `delete-window-internal' has selected a window that should
> 	  ;; not be selected, fix this here.
> 	  (other-window -1 frame))
>
> so we can avoid selecting a new window up to four times when deleting a
> window (the one remaining call in `delete-window-internal' does not
> record the window and has to stay there).  It's simply not nice to do
> that.

1. `get-mru-window' could be one possible choice of the new option.
2. `use-posn-at-point' could be another choice.
3. Selecting the first window could remain in `delete-window-internal'.
4. But what to do with this code block with '(other-window -1 frame)'?
   Should this be simply deleted?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Wed, 02 Jun 2021 09:09:02 GMT) Full text and rfc822 format available.

Message #49 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Wed, 2 Jun 2021 11:08:48 +0200
[Message part 1 (text/plain, inline)]
> I changed <= to < to fix only Y coordinates for top/bottom windows,
> but maybe X coordinates should still use <= ?

The function has to treat the case where an edge is shared between two
windows separately.  A non-shared edge always belongs to the
corresponding window.

> Please note that the crucial difference is that now it uses
> frame relative positions rather than window relative ones
> with '(window-edges window nil nil t)' of the window to be deleted,
> and window coordinates added to X and Y of posn-at-point.

Right.  But the X and Y values are needed separately only at the time
`window-at-pos' is called.

> 1. `get-mru-window' could be one possible choice of the new option.
> 2. `use-posn-at-point' could be another choice.

I called them just 'mru' and 'pos' now.  The option is called
`selected-window-after-deletion', there might be better names.

> 3. Selecting the first window could remain in `delete-window-internal'.

It has to stay there.

> 4. But what to do with this code block with '(other-window -1 frame)'?
>     Should this be simply deleted?

That `other-window' was a bug: A frame that is not selected should not
get selected because we delete a window on it.  In addition, the old
code did not record a newly selected window unless that window was
produced by `get-mru-window'.  I tried to fix those too.  Please have a
look.

martin
[selected-window-after-deletion.diff (text/x-patch, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Thu, 03 Jun 2021 21:45:02 GMT) Full text and rfc822 format available.

Message #52 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Fri, 04 Jun 2021 00:20:32 +0300
> I called them just 'mru' and 'pos' now.  The option is called
> `selected-window-after-deletion', there might be better names.

Maybe better with the same name prefix as `delete-window'?
For example, `delete-window-select'?  But the current is also fine.

> Please have a look.

Thanks, I tested out, and everything works nicely.
Only minor remarks:

> +(defun get-mru-window (&optional all-frames dedicated not-selected no-other)
> +non-nil means never return the selected window.  Optional
> +argument NO_OTHER non-nil means to never return a window whose

Typo:       NO-OTHER

> +(defcustom selected-window-after-deletion 'mru

Not strictly necessary now, but for future extensions
would it be possible to allow this option
to be customized to a function that selects a window?

> +  :type '(choice (const :tag "Most recently used" mru)
> +                 (const :tag "At position" pos)
> +                 nil)

This 'nil' needs to be replaced with a list like:

                    (const :tag "First window" nil)

> +        ;; If we deleted the selected window of WINDOW's frame, choose
> +        ;; another one based on `selected-window-after-deletion'.  Note
> +        ;; that both `window-at-pos' and `get-mru-window' mail fail to
                                                             =========
Typo.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Fri, 04 Jun 2021 09:20:02 GMT) Full text and rfc822 format available.

Message #55 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Fri, 4 Jun 2021 11:19:29 +0200
>> I called them just 'mru' and 'pos' now.  The option is called
>> `selected-window-after-deletion', there might be better names.
>
> Maybe better with the same name prefix as `delete-window'?
> For example, `delete-window-select'?  But the current is also fine.

It's not about "selecting a window", it's about "setting a frame's
selected window".

>> +(defun get-mru-window (&optional all-frames dedicated not-selected no-other)
>> +non-nil means never return the selected window.  Optional
>> +argument NO_OTHER non-nil means to never return a window whose
>
> Typo:       NO-OTHER

Indeed.

>> +(defcustom selected-window-after-deletion 'mru
>
> Not strictly necessary now, but for future extensions
> would it be possible to allow this option
> to be customized to a function that selects a window?
>
>> +  :type '(choice (const :tag "Most recently used" mru)
>> +                 (const :tag "At position" pos)
>> +                 nil)

In general, just plugging in some existing function would usually fail
here and I would like to avoid the illusion that it could work.  Also,
as you can see with the 'pos' case, some work must be done _before_
calling `delete-window-internal' so the actual work would have to be
split among two functions at least.

> This 'nil' needs to be replaced with a list like:
>
>                      (const :tag "First window" nil)
>
>> +        ;; If we deleted the selected window of WINDOW's frame, choose
>> +        ;; another one based on `selected-window-after-deletion'.  Note
>> +        ;; that both `window-at-pos' and `get-mru-window' mail fail to
>                                                               =========
> Typo.

But it rhymes!

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Fri, 04 Jun 2021 16:41:03 GMT) Full text and rfc822 format available.

Message #58 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Fri, 04 Jun 2021 19:29:34 +0300
>>> I called them just 'mru' and 'pos' now.  The option is called
>>> `selected-window-after-deletion', there might be better names.
>>
>> Maybe better with the same name prefix as `delete-window'?
>> For example, `delete-window-select'?  But the current is also fine.
>
> It's not about "selecting a window", it's about "setting a frame's
> selected window".

I just tried to keep the prefix `delete-window-...'.
Then maybe `delete-window-set-selected'?

>>> +(defcustom selected-window-after-deletion 'mru
>>
>> Not strictly necessary now, but for future extensions
>> would it be possible to allow this option
>> to be customized to a function that selects a window?
>
> In general, just plugging in some existing function would usually fail
> here and I would like to avoid the illusion that it could work.  Also,
> as you can see with the 'pos' case, some work must be done _before_
> calling `delete-window-internal' so the actual work would have to be
> split among two functions at least.

The 'pos' case is an exception.  What I meant is simple cases
like customizing to 'get-lru-window'.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Sun, 06 Jun 2021 07:44:02 GMT) Full text and rfc822 format available.

Message #61 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Sun, 6 Jun 2021 09:43:47 +0200
>> It's not about "selecting a window", it's about "setting a frame's
>> selected window".
>
> I just tried to keep the prefix `delete-window-...'.
> Then maybe `delete-window-set-selected'?

Not very illustrative either.

>> In general, just plugging in some existing function would usually fail
>> here and I would like to avoid the illusion that it could work.  Also,
>> as you can see with the 'pos' case, some work must be done _before_
>> calling `delete-window-internal' so the actual work would have to be
>> split among two functions at least.
>
> The 'pos' case is an exception.  What I meant is simple cases
> like customizing to 'get-lru-window'.

That one would have to handle the 'no-other-window' parameter.  And we
would have to mix functions and constants as customizable values which
looks queer in the customization interface.

martin





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Sun, 06 Jun 2021 21:16:01 GMT) Full text and rfc822 format available.

Message #64 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Sun, 06 Jun 2021 23:47:56 +0300
>>> In general, just plugging in some existing function would usually fail
>>> here and I would like to avoid the illusion that it could work.  Also,
>>> as you can see with the 'pos' case, some work must be done _before_
>>> calling `delete-window-internal' so the actual work would have to be
>>> split among two functions at least.
>>
>> The 'pos' case is an exception.  What I meant is simple cases
>> like customizing to 'get-lru-window'.
>
> That one would have to handle the 'no-other-window' parameter.  And we
> would have to mix functions and constants as customizable values which
> looks queer in the customization interface.

The customization interface could use only functions that could be
first called before deletion, then the customized function returns
a lambda that will be called after deletion.  Then for example
all 'pos' logic could be moved to a separate function:

(defun delete-window-pos ()
  (let ((frame-selected-window-edges (window-edges frame-selected-window nil nil t))
        (frame-selected-window-pos (nth 2 (posn-at-point nil frame-selected-window))))
    (lambda ()
      (let ((new-frame-selected-window
	     (window-at-pos
              (+ (nth 0 frame-selected-window-edges)
                 (car frame-selected-window-pos))
              (+ (nth 1 frame-selected-window-edges)
                 (cdr frame-selected-window-pos))
              frame t)))
        (and new-frame-selected-window
             ;; Select window at WINDOW's position at point.
	     (set-frame-selected-window
              frame new-frame-selected-window))))))




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Mon, 07 Jun 2021 07:36:02 GMT) Full text and rfc822 format available.

Message #67 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Mon, 7 Jun 2021 09:35:07 +0200
> The customization interface could use only functions that could be
> first called before deletion, then the customized function returns
> a lambda that will be called after deletion.

Only specialized users would be able to write such a function. And they
can use the 'delete-window' parameter for that purpose.

> Then for example
> all 'pos' logic could be moved to a separate function:
>
> (defun delete-window-pos ()
>    (let ((frame-selected-window-edges (window-edges frame-selected-window nil nil t))
>          (frame-selected-window-pos (nth 2 (posn-at-point nil frame-selected-window))))
>      (lambda ()
>        (let ((new-frame-selected-window
> 	     (window-at-pos
>                (+ (nth 0 frame-selected-window-edges)
>                   (car frame-selected-window-pos))
>                (+ (nth 1 frame-selected-window-edges)
>                   (cdr frame-selected-window-pos))
>                frame t)))
>          (and new-frame-selected-window
>               ;; Select window at WINDOW's position at point.
> 	     (set-frame-selected-window
>                frame new-frame-selected-window))))))

I'm completely lost with the scoping of that first `let'.  So at least
for a poor soul like me such a solution would not be feasible at all.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Mon, 07 Jun 2021 21:04:02 GMT) Full text and rfc822 format available.

Message #70 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Tue, 08 Jun 2021 00:00:27 +0300
>> The customization interface could use only functions that could be
>> first called before deletion, then the customized function returns
>> a lambda that will be called after deletion.
>
> Only specialized users would be able to write such a function. And they
> can use the 'delete-window' parameter for that purpose.

Then I'm not a specialized user because I didn't know about
the 'delete-window' parameter :-)

> I'm completely lost with the scoping of that first `let'.  So at least
> for a poor soul like me such a solution would not be feasible at all.

A lambda was just an example.  But constants like in your previous patch
are fine.  So you could just push it when you want.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Thu, 10 Jun 2021 07:45:02 GMT) Full text and rfc822 format available.

Message #73 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: martin rudalics <rudalics <at> gmx.at>
To: Juri Linkov <juri <at> linkov.net>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Thu, 10 Jun 2021 09:44:07 +0200
> A lambda was just an example.  But constants like in your previous patch
> are fine.  So you could just push it when you want.

Pushed now.  Feel free to change it if you have better ideas.

Thanks, martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#47300; Package emacs. (Fri, 11 Jun 2021 17:14:01 GMT) Full text and rfc822 format available.

Message #76 received at 47300 <at> debbugs.gnu.org (full text, mbox):

From: Juri Linkov <juri <at> linkov.net>
To: martin rudalics <rudalics <at> gmx.at>
Cc: Lars Ingebrigtsen <larsi <at> gnus.org>, 47300 <at> debbugs.gnu.org
Subject: Re: bug#47300: delete-window to select window with same position
Date: Fri, 11 Jun 2021 20:06:36 +0300
tags 47300 fixed
close 47300 28.0.50
thanks

> Pushed now.  Feel free to change it if you have better ideas.

Thank you for implementing this useful feature.
The name proposed by Eli is also good.
So this request could be closed now.

PS: I propose one additional tiny change - maybe would be better
to add for @code{delete-window-choose-selected} a xref
or pxref from the "Change Window" node of the User Manual
to the Lisp Reference Manual (there are already many
references to elisp in emacs/windows.texi.)




Added tag(s) fixed. Request was from Juri Linkov <juri <at> linkov.net> to control <at> debbugs.gnu.org. (Fri, 11 Jun 2021 17:14:02 GMT) Full text and rfc822 format available.

bug marked as fixed in version 28.0.50, send any further explanations to 47300 <at> debbugs.gnu.org and Juri Linkov <juri <at> linkov.net> Request was from Juri Linkov <juri <at> linkov.net> to control <at> debbugs.gnu.org. (Fri, 11 Jun 2021 17:14:02 GMT) Full text and rfc822 format available.

bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Sat, 10 Jul 2021 11:24:04 GMT) Full text and rfc822 format available.

This bug report was last modified 2 years and 262 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.