Subject: bug#35385: 27.0.50; Make dired-dwim-target aware of other frames

From: Juri Linkov <[email-masked]>
Date: Thu, 19 Sep 2019 23:43:37 +0300

>> BTW, while looking at windows walking functions, I noticed
>> an opportunity for simplification.
>>
>> Martin, could you please confirm if I'm not mistaken with this patch:
>
> Removing the
>
>     (when (framep all-frames)
>       (select-window (frame-first-window all-frames) 'norecord))
>
> LGTM.  Whether we should remove the
>
>   (save-selected-window
>
> envelope is another question.  If FUN changes the selected window,
> we'd now have a side effect we didn't have so far.

So I left a comment explaining why save-selected-window is still needed.

Now I prepared a patch for dired-dwim-target to DWIM most recently used
windows from all frames:

diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index a321247b0b..7c477fa89d 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -1965,6 +1968,18 @@ dired-mark-read-file-name
    #'read-file-name
    (format prompt (dired-mark-prompt arg files)) dir default))
 
+(defun dired-dwim-target-directories ()
+  ;; Return directories from all visible windows with dired-mode buffers
+  ;; ordered by most-recently-used.
+  (mapcar #'cdr (sort (mapcan (lambda (w)
+                                (with-current-buffer (window-buffer w)
+                                  (when (eq major-mode 'dired-mode)
+                                    (list (cons (window-use-time w)
+                                                (dired-current-directory))))))
+                              (delq (selected-window)
+                                    (window-list-1 nil 'nomini 'visible)))
+                      (lambda (a b) (> (car a) (car b))))))
+
 (defun dired-dwim-target-directory ()
   ;; Try to guess which target directory the user may want.
   ;; If there is a dired buffer displayed in one of the next windows,
@@ -1973,15 +1988,7 @@ dired-dwim-target-directory
 		       (dired-current-directory))))
     ;; non-dired buffer may want to profit from this function, e.g. vm-uudecode
     (if dired-dwim-target
-	(let* ((other-win (get-window-with-predicate
-			   (lambda (window)
-			     (with-current-buffer (window-buffer window)
-			       (eq major-mode 'dired-mode)))))
-	       (other-dir (and other-win
-			       (with-current-buffer (window-buffer other-win)
-				 (and (eq major-mode 'dired-mode)
-				      (dired-current-directory))))))
-	  (or other-dir this-dir))
+        (or (car (dired-dwim-target-directories)) this-dir)
       this-dir)))
 
 (defun dired-dwim-target-defaults (fn-list target-dir)
@@ -1999,15 +2006,11 @@ dired-dwim-target-defaults
 	 (and (consp fn-list) (null (cdr fn-list)) (car fn-list)))
 	(current-dir (and (eq major-mode 'dired-mode)
 			  (dired-current-directory)))
-	dired-dirs)
-    ;; Get a list of directories of visible buffers in dired-mode.
-    (walk-windows (lambda (w)
-		    (with-current-buffer (window-buffer w)
-		      (and (eq major-mode 'dired-mode)
-			   (push (dired-current-directory) dired-dirs)))))
+        ;; Get a list of directories of visible buffers in dired-mode.
+        (dired-dirs (dired-dwim-target-directories)))
     ;; Force the current dir to be the first in the list.
     (setq dired-dirs
-	  (delete-dups (delq nil (cons current-dir (nreverse dired-dirs)))))
+          (delete-dups (delq nil (cons current-dir dired-dirs))))
     ;; Remove the target dir (if specified) or the current dir from
     ;; default values, because it should be already in initial input.
     (setq dired-dirs (delete (or target-dir current-dir) dired-dirs))
diff --git a/lisp/dired.el b/lisp/dired.el
index 854bc9f7d7..b0d40da57f 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -185,9 +185,9 @@ dired-keep-marker-symlink
 
 (defcustom dired-dwim-target nil
   "If non-nil, Dired tries to guess a default target directory.
-This means: if there is a Dired buffer displayed in the next
-window, use its current directory, instead of this Dired buffer's
-current directory.
+This means: if there is a Dired buffer displayed in one of recently
+selected windows, use its current directory, instead of this Dired
+buffer's current directory.
 
 The target is used in the prompt for file copy, rename etc."
   :type 'boolean