emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r113422: lisp/desktop.el (desktop-restore-frames): C


From: Juanma Barranquero
Subject: [Emacs-diffs] trunk r113422: lisp/desktop.el (desktop-restore-frames): Change default to t.
Date: Mon, 15 Jul 2013 00:07:59 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 113422
revision-id: address@hidden
parent: address@hidden
committer: Juanma Barranquero <address@hidden>
branch nick: trunk
timestamp: Mon 2013-07-15 02:07:51 +0200
message:
  lisp/desktop.el (desktop-restore-frames): Change default to t.
  (desktop-restore-in-current-display): Now offer more options.
  (desktop-restoring-reuses-frames): New customization option.
  (desktop--saved-states): Doc fix.
  (desktop-filter-parameters-alist): New variable, renamed and expanded from
  desktop--excluded-frame-parameters.
  (desktop--target-display): New variable.
  (desktop-switch-to-gui-p, desktop-switch-to-tty-p, desktop--filter-tty*)
  (desktop--filter-*-color, desktop--filter-minibuffer)
  (desktop--filter-restore-desktop-parm, desktop--filter-save-desktop-parm)
  (desktop-restore-in-original-display-p): New functions.
  (desktop--filter-frame-parms): Use new desktop-filter-parameters-alist.
  (desktop--save-minibuffer-frames): New function, inspired by a similar
  function from Martin Rudalics.
  (desktop--save-frames): Call it; play nice with desktop-globals-to-save.
  (desktop--restore-in-this-display-p): Remove.
  (desktop--find-frame): Rename from desktop--find-frame-in-display and add
  predicate argument.
  (desktop--make-full-frame): Remove, integrated into desktop--make-frame.
  (desktop--reuse-list): New variable.
  (desktop--select-frame, desktop--make-frame, desktop--sort-states):
  New functions.
  (desktop--restore-frames): Add support for "minibuffer-special" frames.
modified:
  etc/NEWS                       news-20100311060928-aoit31wvzf25yr1z-1
  lisp/ChangeLog                 changelog-20091113204419-o5vbwnq5f7feedwu-1432
  lisp/desktop.el                desktop.el-20091113204419-o5vbwnq5f7feedwu-591
=== modified file 'etc/NEWS'
--- a/etc/NEWS  2013-07-13 10:55:21 +0000
+++ b/etc/NEWS  2013-07-15 00:07:51 +0000
@@ -255,8 +255,10 @@
 *** `desktop-auto-save-timeout' defines the number of seconds between
 auto-saves of the desktop.
 
-*** `desktop-restore-frames' enables saving and restoring the window/frame
-configuration.
+*** `desktop-restore-frames', enabled by default, allows saving and
+restoring the window/frame configuration.  Additional options
+`desktop-restore-in-current-display' and
+`desktop-restoring-reuses-frames' allow further customization.
 
 ** Dired
 

=== modified file 'lisp/ChangeLog'
--- a/lisp/ChangeLog    2013-07-14 18:45:50 +0000
+++ b/lisp/ChangeLog    2013-07-15 00:07:51 +0000
@@ -1,3 +1,30 @@
+2013-07-14  Juanma Barranquero  <address@hidden>
+
+       * desktop.el (desktop-restore-frames): Change default to t.
+       (desktop-restore-in-current-display): Now offer more options.
+       (desktop-restoring-reuses-frames): New customization option.
+       (desktop--saved-states): Doc fix.
+       (desktop-filter-parameters-alist): New variable, renamed and expanded
+       from desktop--excluded-frame-parameters.
+       (desktop--target-display): New variable.
+       (desktop-switch-to-gui-p, desktop-switch-to-tty-p)
+       (desktop--filter-tty*, desktop--filter-*-color)
+       (desktop--filter-minibuffer, desktop--filter-restore-desktop-parm)
+       (desktop--filter-save-desktop-parm)
+       (desktop-restore-in-original-display-p): New functions.
+       (desktop--filter-frame-parms): Use new desktop-filter-parameters-alist.
+       (desktop--save-minibuffer-frames): New function, inspired by a similar
+       function from Martin Rudalics.
+       (desktop--save-frames): Call it; play nice with desktop-globals-to-save.
+       (desktop--restore-in-this-display-p): Remove.
+       (desktop--find-frame): Rename from desktop--find-frame-in-display
+       and add predicate argument.
+       (desktop--make-full-frame): Remove, integrated into desktop--make-frame.
+       (desktop--reuse-list): New variable.
+       (desktop--select-frame, desktop--make-frame, desktop--sort-states):
+       New functions.
+       (desktop--restore-frames): Add support for "minibuffer-special" frames.
+
 2013-07-14  Michael Albinus  <address@hidden>
 
        * net/tramp-sh.el (tramp-sh-handle-vc-registered): Use `ignore-error'.

=== modified file 'lisp/desktop.el'
--- a/lisp/desktop.el   2013-07-12 11:21:01 +0000
+++ b/lisp/desktop.el   2013-07-15 00:07:51 +0000
@@ -33,6 +33,7 @@
 ;;             - the mark & mark-active
 ;;             - buffer-read-only
 ;;             - some local variables
+;;     - frame and window configuration
 
 ;; To use this, use customize to turn on desktop-save-mode or add the
 ;; following line somewhere in your init file:
@@ -127,7 +128,6 @@
 ;; ---------------------------------------------------------------------------
 ;; TODO:
 ;;
-;; Save window configuration.
 ;; Recognize more minor modes.
 ;; Save mark rings.
 
@@ -369,16 +369,29 @@
   :type '(repeat symbol)
   :group 'desktop)
 
-(defcustom desktop-restore-frames nil
+(defcustom desktop-restore-frames t
   "When non-nil, save window/frame configuration to desktop file."
   :type 'boolean
   :group 'desktop
   :version "24.4")
 
 (defcustom desktop-restore-in-current-display nil
-  "When non-nil, frames are restored in the current display.
-Otherwise they are restored, if possible, in their original displays."
-  :type 'boolean
+  "If t, frames are restored in the current display.
+If nil, frames are restored, if possible, in their original displays.
+If `delete', frames on other displays are deleted instead of restored."
+  :type '(choice (const :tag "Restore in current display" t)
+                (const :tag "Restore in original display" nil)
+                (const :tag "Delete frames in other displays" 'delete))
+  :group 'desktop
+  :version "24.4")
+
+(defcustom desktop-restoring-reuses-frames t
+  "If t, restoring frames reuses existing frames.
+If nil, existing frames are deleted.
+If `keep', existing frames are kept and not reused."
+  :type '(choice (const :tag "Reuse existing frames" t)
+                (const :tag "Delete existing frames" nil)
+                (const :tag "Keep existing frames" 'keep))
   :group 'desktop
   :version "24.4")
 
@@ -566,7 +579,7 @@
 Used to avoid writing contents unchanged between auto-saves.")
 
 (defvar desktop--saved-states nil
-  "Internal use only.")
+  "Saved window/frame state.  Internal use only.")
 
 ;; ----------------------------------------------------------------------------
 ;; Desktop file conflict detection
@@ -869,30 +882,193 @@
 
 
 ;; ----------------------------------------------------------------------------
-(defconst desktop--excluded-frame-parameters
-  '(buffer-list
-    buffer-predicate
-    buried-buffer-list
-    explicit-name
-    font
-    font-backend
-    minibuffer
-    name
-    outer-window-id
-    parent-id
-    window-id
-    window-system)
-  "Frame parameters not saved or restored.")
-
-(defun desktop--filter-frame-parms (frame)
-  "Return frame parameters of FRAME.
-Parameters in `desktop--excluded-frame-parameters' are excluded.
+(defvar desktop-filter-parameters-alist
+  '((background-color  . desktop--filter-*-color)
+    (buffer-list       . t)
+    (buffer-predicate  . t)
+    (buried-buffer-list . t)
+    (desktop-font      . desktop--filter-restore-desktop-parm)
+    (desktop-fullscreen . desktop--filter-restore-desktop-parm)
+    (desktop-height    . desktop--filter-restore-desktop-parm)
+    (desktop-width     . desktop--filter-restore-desktop-parm)
+    (font              . desktop--filter-save-desktop-parm)
+    (font-backend      . t)
+    (foreground-color  . desktop--filter-*-color)
+    (fullscreen                . desktop--filter-save-desktop-parm)
+    (height            . desktop--filter-save-desktop-parm)
+    (minibuffer                . desktop--filter-minibuffer)
+    (name              . t)
+    (outer-window-id   . t)
+    (parent-id         . t)
+    (tty               . desktop--filter-tty*)
+    (tty-type          . desktop--filter-tty*)
+    (width             . desktop--filter-save-desktop-parm)
+    (window-id         . t)
+    (window-system     . t))
+  "Alist of frame parameters and filtering functions.
+
+Each element is a cons (PARAM . FILTER), where PARAM is a parameter
+name (a symbol identifying a frame parameter), and FILTER can be t
+\(meaning the parameter is removed from the parameter list on saving
+and restoring), or a function that will be called with three args:
+
+ CURRENT     a cons (PARAM . VALUE), where PARAM is the one being
+             filtered and VALUE is its current value
+ PARAMETERS  the complete alist of parameters being filtered
+ SAVING      non-nil if filtering before saving state, nil otherwise
+
+The FILTER function must return:
+ nil                  CURRENT is removed from the list
+ t                    CURRENT is left as is
+ (PARAM' . VALUE')    replace CURRENT with this
+
+Frame parameters not on this list are passed intact.")
+
+(defvar desktop--target-display nil
+  "Either (minibuffer . VALUE) or nil.
+This refers to the current frame config being processed inside
+`frame--restore-frames' and its auxiliary functions (like filtering).
+If nil, there is no need to change the display.
+If non-nil, display parameter to use when creating the frame.
+Internal use only.")
+
+(defun desktop-switch-to-gui-p (parameters)
+  "True when switching to a graphic display.
+Return t if PARAMETERS describes a text-only terminal and
+the target is a graphic display; otherwise return nil.
+Only meaningful when called from a filtering function in
+`desktop-filter-parameters-alist'."
+  (and desktop--target-display                ; we're switching
+       (null (cdr (assq 'display parameters))) ; from a tty
+       (cdr desktop--target-display)))        ; to a GUI display
+
+(defun desktop-switch-to-tty-p (parameters)
+  "True when switching to a text-only terminal.
+Return t if PARAMETERS describes a graphic display and
+the target is a text-only terminal; otherwise return nil.
+Only meaningful when called from a filtering function in
+`desktop-filter-parameters-alist'."
+  (and desktop--target-display                ; we're switching
+       (cdr (assq 'display parameters))               ; from a GUI display
+       (null (cdr desktop--target-display))))  ; to a tty
+
+(defun desktop--filter-tty* (_current parameters saving)
+  ;; Remove tty and tty-type parameters when switching
+  ;; to a GUI frame.
+  (or saving
+      (not (desktop-switch-to-gui-p parameters))))
+
+(defun desktop--filter-*-color (current parameters saving)
+  ;; Remove (foreground|background)-color parameters
+  ;; when switching to a GUI frame if they denote an
+  ;; "unspecified" color.
+  (or saving
+      (not (desktop-switch-to-gui-p parameters))
+      (not (stringp (cdr current)))
+      (not (string-match-p "^unspecified-[fb]g$" (cdr current)))))
+
+(defun desktop--filter-minibuffer (current _parameters saving)
+  ;; When minibuffer is a window, save it as minibuffer . t
+  (or (not saving)
+      (if (windowp (cdr current))
+         '(minibuffer . t)
+       t)))
+
+(defun desktop--filter-restore-desktop-parm (current parameters saving)
+  ;; When switching to a GUI frame, convert desktop-XXX parameter to XXX
+  (or saving
+      (not (desktop-switch-to-gui-p parameters))
+      (let ((val (cdr current)))
+       (if (eq val :desktop-processed)
+           nil
+         (cons (intern (substring (symbol-name (car current))
+                                  8)) ;; (length "desktop-")
+               val)))))
+
+(defun desktop--filter-save-desktop-parm (current parameters saving)
+  ;; When switching to a tty frame, save parameter XXX as desktop-XXX so it
+  ;; can be restored in a subsequent GUI session, unless it already exists.
+  (cond (saving t)
+       ((desktop-switch-to-tty-p parameters)
+        (let ((sym (intern (format "desktop-%s" (car current)))))
+          (if (assq sym parameters)
+              nil
+            (cons sym (cdr current)))))
+       ((desktop-switch-to-gui-p parameters)
+        (let* ((dtp (assq (intern (format "desktop-%s" (car current)))
+                          parameters))
+               (val (cdr dtp)))
+          (if (eq val :desktop-processed)
+              nil
+            (setcdr dtp :desktop-processed)
+            (cons (car current) val))))
+       (t t)))
+
+(defun desktop-restore-in-original-display-p ()
+  "True if saved frames' displays should be honored."
+  (cond ((daemonp) t)
+       ((eq system-type 'windows-nt) nil)
+       (t (null desktop-restore-in-current-display))))
+
+(defun desktop--filter-frame-parms (parameters saving)
+  "Filter frame parameters and return filtered list.
+PARAMETERS is a parameter alist as returned by `frame-parameters'.
+If SAVING is non-nil, filtering is happening before saving frame state;
+otherwise, filtering is being done before restoring frame state.
+Parameters are filtered according to the setting of
+`desktop-filter-parameters-alist' (which see).
 Internal use only."
-  (let (params)
-    (dolist (param (frame-parameters frame))
-      (unless (memq (car param) desktop--excluded-frame-parameters)
-       (push param params)))
-    params))
+  (let ((filtered nil))
+    (dolist (param parameters)
+      (let ((filter (cdr (assq (car param) desktop-filter-parameters-alist)))
+           this)
+       (cond (;; no filter: pass param
+              (null filter)
+              (push param filtered))
+             (;; filter = t; skip param
+              (eq filter t))
+             (;; filter func returns nil: skip param
+              (null (setq this (funcall filter param parameters saving))))
+             (;; filter func returns t: pass param
+              (eq this t)
+              (push param filtered))
+             (;; filter func returns a new param: use it
+              t
+              (push this filtered)))))
+    ;; Set the display parameter after filtering, so that filter functions
+    ;; have access to its original value.
+    (when desktop--target-display
+      (let ((display (assq 'display filtered)))
+       (if display
+           (setcdr display (cdr desktop--target-display))
+         (push desktop--target-display filtered))))
+    filtered))
+
+(defun desktop--save-minibuffer-frames ()
+  ;; Adds a desktop-mini parameter to frames
+  ;; desktop-mini is a list (MINIBUFFER NUMBER DEFAULT?) where
+  ;; MINIBUFFER         t if the frame (including minibuffer-only) owns a 
minibuffer
+  ;; NUMBER     if MINIBUFFER = t, an ID for the frame; if nil, the ID of
+  ;;            the frame containing the minibuffer used by this frame
+  ;; DEFAULT?   if t, this frame is the value of default-minibuffer-frame
+  ;;            FIXME: What happens with multi-terminal sessions?
+  (let ((frames (frame-list))
+       (count 0))
+    ;; Reset desktop-mini for all frames
+    (dolist (frame frames)
+      (set-frame-parameter frame 'desktop-mini nil))
+    ;; Number all frames with its own minibuffer
+    (dolist (frame (minibuffer-frame-list))
+      (set-frame-parameter frame 'desktop-mini
+                          (list t
+                                (setq count (1+ count))
+                                (eq frame default-minibuffer-frame))))
+    ;; Now link minibufferless frames with their minibuffer frames
+    (dolist (frame frames)
+      (unless (frame-parameter frame 'desktop-mini)
+       (let* ((mb-frame (window-frame (minibuffer-window frame)))
+              (this (cadr (frame-parameter mb-frame 'desktop-mini))))
+         (set-frame-parameter frame 'desktop-mini (list nil this nil)))))))
 
 (defun desktop--save-frames ()
   "Save window/frame state, as a global variable.
@@ -900,12 +1076,14 @@
 Internal use only."
   (setq desktop--saved-states
        (and desktop-restore-frames
-            (mapcar (lambda (frame)
-                      (cons (desktop--filter-frame-parms frame)
-                            (window-state-get (frame-root-window frame) t)))
-                    (cons (selected-frame)
-                          (delq (selected-frame) (frame-list))))))
-  (desktop-outvar 'desktop--saved-states))
+            (progn
+              (desktop--save-minibuffer-frames)
+              (mapcar (lambda (frame)
+                        (cons (desktop--filter-frame-parms (frame-parameters 
frame) t)
+                              (window-state-get (frame-root-window frame) t)))
+                      (frame-list)))))
+  (unless (memq 'desktop--saved-states desktop-globals-to-save)
+    (desktop-outvar 'desktop--saved-states)))
 
 ;;;###autoload
 (defun desktop-save (dirname &optional release auto-save)
@@ -1006,71 +1184,220 @@
 (defvar desktop-lazy-timer nil)
 
 ;; ----------------------------------------------------------------------------
-(defun desktop--restore-in-this-display-p ()
-  (or desktop-restore-in-current-display
-      (and (eq system-type 'windows-nt) (not (display-graphic-p)))))
-
-(defun desktop--find-frame-in-display (frames display)
-  (let (result)
-    (while (and frames (not result))
-      (if (equal display (frame-parameter (car frames) 'display))
-         (setq result (car frames))
-       (setq frames (cdr frames))))
-    result))
-
-(defun desktop--make-full-frame (full display config)
-  (let ((width (and (eq full 'fullheight) (cdr (assq 'width config))))
-       (height (and (eq full 'fullwidth) (cdr (assq 'height config))))
-       (params '((visibility)))
+(defvar desktop--reuse-list nil
+  "Internal use only.")
+
+(defun desktop--find-frame (predicate display &rest args)
+  "Find a suitable frame in `desktop--reuse-list'.
+Look through frames whose display property matches DISPLAY and
+return the first one for which (PREDICATE frame ARGS) returns t.
+If PREDICATE is nil, it is always satisfied.  Internal use only.
+This is an auxiliary function for `desktop--select-frame'."
+  (catch :found
+    (dolist (frame desktop--reuse-list)
+      (when (and (equal (frame-parameter frame 'display) display)
+                (or (null predicate)
+                    (apply predicate frame args)))
+       (throw :found frame)))
+    nil))
+
+(defun desktop--select-frame (display frame-cfg)
+  "Look for an existing frame to reuse.
+DISPLAY is the display where the frame will be shown, and FRAME-CFG
+is the parameter list of the frame being restored.  Internal use only."
+  (if (eq desktop-restoring-reuses-frames t)
+      (let ((frame nil)
+           mini)
+       ;; There are no fancy heuristics there.  We could implement some
+       ;; based on frame size and/or position, etc., but it is not clear
+       ;; that any "gain" (in the sense of reduced flickering, etc.) is
+       ;; worth the added complexity.  In fact, the code below mainly
+       ;; tries to work nicely when M-x desktop-read is used after a desktop
+       ;; session has already been loaded.  The other main use case, which
+       ;; is the initial desktop-read upon starting Emacs, should usually
+       ;; only have one, or very few, frame(s) to reuse.
+       (cond (;; When the target is tty, every existing frame is reusable.
+              (null display)
+              (setq frame (desktop--find-frame nil display)))
+             (;; If the frame has its own minibuffer, let's see whether
+              ;; that frame has already been loaded (which can happen after
+              ;; M-x desktop-read).
+              (car (setq mini (cdr (assq 'desktop-mini frame-cfg))))
+              (setq frame (or (desktop--find-frame
+                               (lambda (f m)
+                                 (equal (frame-parameter f 'desktop-mini) m))
+                               display mini))))
+             (;; For minibufferless frames, check whether they already exist,
+              ;; and that they are linked to the right minibuffer frame.
+              mini
+              (setq frame (desktop--find-frame
+                           (lambda (f n)
+                             (let ((m (frame-parameter f 'desktop-mini)))
+                               (and m
+                                    (null (car m))
+                                    (= (cadr m) n)
+                                    (equal (cadr (frame-parameter
+                                                  (window-frame 
(minibuffer-window f))
+                                                  'desktop-mini))
+                                           n))))
+                           display (cadr mini))))
+             (;; Default to just finding a frame in the same display.
+              t
+              (setq frame (desktop--find-frame nil display))))
+       ;; If found, remove from the list.
+       (when frame
+         (setq desktop--reuse-list (delq frame desktop--reuse-list)))
        frame)
-    (when width
-      (setq params (append `((user-size . t) (width . ,width)) params)
-            config (assq-delete-all 'height config)))
-    (when height
-      (setq params (append `((user-size . t) (height . ,height)) params)
-            config (assq-delete-all 'width config)))
-    (setq frame (make-frame-on-display display params))
-    (modify-frame-parameters frame config)
+    nil))
+
+(defun desktop--make-frame (frame-cfg window-cfg)
+  "Set up a frame according to its saved state.
+That means either creating a new frame or reusing an existing one.
+FRAME-CFG is the parameter list of the new frame; WINDOW-CFG is
+its window state.  Internal use only."
+  (let* ((fullscreen (cdr (assq 'fullscreen frame-cfg)))
+        (lines (assq 'tool-bar-lines frame-cfg))
+        (filtered-cfg (desktop--filter-frame-parms frame-cfg nil))
+        (display (cdr (assq 'display filtered-cfg))) ;; post-filtering
+        alt-cfg frame)
+
+    ;; This works around bug#14795 (or feature#14795, if not a bug :-)
+    (setq filtered-cfg (assq-delete-all 'tool-bar-lines filtered-cfg))
+    (push '(tool-bar-lines . 0) filtered-cfg)
+
+    (when fullscreen
+      ;; Currently Emacs has the limitation that it does not record the size
+      ;; and position of a frame before maximizing it, so we cannot save &
+      ;; restore that info.  Instead, when restoring, we resort to creating
+      ;; invisible "fullscreen" frames of default size and then maximizing them
+      ;; (and making them visible) which at least is somewhat user-friendly
+      ;; when these frames are later de-maximized.
+      (let ((width (and (eq fullscreen 'fullheight) (cdr (assq 'width 
filtered-cfg))))
+           (height (and (eq fullscreen 'fullwidth) (cdr (assq 'height 
filtered-cfg))))
+           (visible (assq 'visibility filtered-cfg)))
+       (dolist (parameter '(visibility fullscreen width height))
+         (setq filtered-cfg (assq-delete-all parameter filtered-cfg)))
+       (when width
+         (setq filtered-cfg (append `((user-size . t) (width . ,width))
+                                      filtered-cfg)))
+       (when height
+         (setq filtered-cfg (append `((user-size . t) (height . ,height))
+                                    filtered-cfg)))
+       ;; These are parameters to apply after creating/setting the frame.
+       (push visible alt-cfg)
+       (push (cons 'fullscreen fullscreen) alt-cfg)))
+
+    ;; Time to select or create a frame an apply the big bunch of parameters
+    (if (setq frame (desktop--select-frame display filtered-cfg))
+       (modify-frame-parameters frame filtered-cfg)
+      (setq frame (make-frame-on-display display filtered-cfg)))
+
+    ;; Let's give the finishing touches (visibility, tool-bar, maximization).
+    (when lines (push lines alt-cfg))
+    (when alt-cfg (modify-frame-parameters frame alt-cfg))
+    ;; Now restore window state.
+    (window-state-put window-cfg (frame-root-window frame) 'safe)
     frame))
 
+(defun desktop--sort-states (state1 state2)
+  ;; Order: default minibuffer frame
+  ;;       other frames with minibuffer, ascending ID
+  ;;       minibufferless frames, ascending ID
+  (let ((dm1 (cdr (assq 'desktop-mini (car state1))))
+       (dm2 (cdr (assq 'desktop-mini (car state2)))))
+    (cond ((nth 2 dm1) t)
+         ((nth 2 dm2) nil)
+         ((null (car dm2)) t)
+         ((null (car dm1)) nil)
+         (t (< (cadr dm1) (cadr dm2))))))
+
 (defun desktop--restore-frames ()
   "Restore window/frame configuration.
 Internal use only."
   (when (and desktop-restore-frames desktop--saved-states)
-    (let ((frames (frame-list))
-         (current (frame-parameter nil 'display))
-         (selected nil))
+    (let* ((frame-mb-map nil) ;; Alist of frames with their own minibuffer
+          (visible nil)
+          (delete-saved (eq desktop-restore-in-current-display 'delete))
+          (forcing (not (desktop-restore-in-original-display-p)))
+          (target (and forcing (cons 'display (frame-parameter nil 
'display)))))
+
+      ;; Sorting saved states allows us to easily restore minibuffer-owning 
frames
+      ;; before minibufferless ones.
+      (setq desktop--saved-states (sort desktop--saved-states 
#'desktop--sort-states))
+      ;; Potentially all existing frames are reusable. Later we will decide 
which ones
+      ;; to reuse, and how to deal with any leftover.
+      (setq desktop--reuse-list (frame-list))
+
       (dolist (state desktop--saved-states)
        (condition-case err
-           (let* ((config (car state))
-                  (display (if (desktop--restore-in-this-display-p)
-                               (setcdr (assq 'display config) current)
-                             (cdr (assq 'display config))))
-                  (full (cdr (assq 'fullscreen config)))
-                  (frame (and (not full)
-                              (desktop--find-frame-in-display frames 
display))))
-             (cond (full
-                    ;; treat fullscreen/maximized frames specially
-                    (setq frame (desktop--make-full-frame full display 
config)))
-                   (frame
-                    ;; found a frame in the right display -- reuse
-                    (setq frames (delq frame frames))
-                    (modify-frame-parameters frame config))
-                   (t
-                    ;; no frames in the display -- make a new one
-                    (setq frame (make-frame-on-display display config))))
-             ;; restore windows
-             (window-state-put (cdr state) (frame-root-window frame) 'safe)
-             (unless selected (setq selected frame)))
+           (let* ((frame-cfg (car state))
+                  (window-cfg (cdr state))
+                  (d-mini (cdr (assq 'desktop-mini frame-cfg)))
+                  num frame to-tty)
+             ;; Only set target if forcing displays and the target display is 
different.
+             (if (or (not forcing)
+                     (equal target (or (assq 'display frame-cfg) '(display . 
nil))))
+                 (setq desktop--target-display nil)
+               (setq desktop--target-display target
+                     to-tty (null (cdr target))))
+             ;; Time to restore frames and set up their minibuffers as they 
were.
+             ;; We only skip a frame (thus deleting it) if either:
+             ;; - we're switching displays, and the user chose the option to 
delete, or
+             ;; - we're switching to tty, and the frame to restore is 
minibuffer-only.
+             (unless (and desktop--target-display
+                          (or delete-saved
+                              (and to-tty
+                                   (eq (cdr (assq 'minibuffer frame-cfg)) 
'only))))
+
+               ;; Restore minibuffers.  Some of this stuff could be done in a 
filter
+               ;; function, but it would be messy because restoring 
minibuffers affects
+               ;; global state; it's best to do it here than add a bunch of 
global
+               ;; variables to pass info back-and-forth to/from the filter 
function.
+               (cond
+                ((null d-mini)) ;; No desktop-mini.  Process as normal frame.
+                (to-tty) ;; Ignore minibuffer stuff and process as normal 
frame.
+                ((car d-mini) ;; Frame has its own minibuffer (or it is 
minibuffer-only).
+                 (setq num (cadr d-mini))
+                 (when (eq (cdr (assq 'minibuffer frame-cfg)) 'only)
+                   (setq frame-cfg (append '((tool-bar-lines . 0) 
(menu-bar-lines . 0))
+                                           frame-cfg))))
+                (t ;; Frame depends on other frame's minibufer window.
+                 (let ((mb-frame (cdr (assq (cadr d-mini) frame-mb-map))))
+                   (unless (frame-live-p mb-frame)
+                     (error "Minibuffer frame %s not found" (cadr d-mini)))
+                   (let ((mb-param (assq 'minibuffer frame-cfg))
+                         (mb-window (minibuffer-window mb-frame)))
+                     (unless (and (window-live-p mb-window)
+                                  (window-minibuffer-p mb-window))
+                       (error "Not a minibuffer window %s" mb-window))
+                     (if mb-param
+                         (setcdr mb-param mb-window)
+                       (push (cons 'minibuffer mb-window) frame-cfg))))))
+               ;; OK, we're ready at last to create (or reuse) a frame and
+               ;; restore the window config.
+               (setq frame (desktop--make-frame frame-cfg window-cfg))
+               ;; Set default-minibuffer if required.
+               (when (nth 2 d-mini) (setq default-minibuffer-frame frame))
+               ;; Store frame/NUM to assign to minibufferless frames.
+               (when num (push (cons num frame) frame-mb-map))
+               ;; Try to locate at least one visible frame.
+               (when (and (not visible) (frame-visible-p frame))
+                 (setq visible frame))))
          (error
-          (message "Error restoring frame: %S" (error-message-string err)))))
-      (when selected
-       ;; make sure the original selected frame is visible and selected
-       (unless (or (frame-parameter selected 'visibility) (daemonp))
-         (modify-frame-parameters selected '((visibility . t))))
-       (select-frame-set-input-focus selected)
-       ;; delete any remaining frames
-       (mapc #'delete-frame frames)))))
+          (delay-warning 'desktop (error-message-string err) :error))))
+
+      ;; Delete remaining frames, but do not fail if some resist being deleted.
+      (unless (eq desktop-restoring-reuses-frames 'keep)
+       (dolist (frame desktop--reuse-list)
+         (ignore-errors (delete-frame frame))))
+      (setq desktop--reuse-list nil)
+      ;; Make sure there's at least one visible frame, and select it.
+      (unless (or visible (daemonp))
+       (setq visible (if (frame-live-p default-minibuffer-frame)
+                         default-minibuffer-frame
+                       (car (frame-list))))
+       (make-frame-visible visible)
+       (select-frame-set-input-focus visible)))))
 
 ;;;###autoload
 (defun desktop-read (&optional dirname)


reply via email to

[Prev in Thread] Current Thread [Next in Thread]