mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-02-18 06:01:22 -08:00
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.
This commit is contained in:
parent
5c97beae62
commit
b958c0ad58
3 changed files with 445 additions and 89 deletions
6
etc/NEWS
6
etc/NEWS
|
|
@ -255,8 +255,10 @@ on the given date.
|
|||
*** `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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,30 @@
|
|||
2013-07-14 Juanma Barranquero <lekktu@gmail.com>
|
||||
|
||||
* 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 <michael.albinus@gmx.de>
|
||||
|
||||
* net/tramp-sh.el (tramp-sh-handle-vc-registered): Use `ignore-error'.
|
||||
|
|
|
|||
501
lisp/desktop.el
501
lisp/desktop.el
|
|
@ -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 @@ modes are restored automatically; they should not be listed here."
|
|||
: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 @@ DIRNAME omitted or nil means use `desktop-dirname'."
|
|||
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 @@ DIRNAME must be the directory in which the desktop file will be saved."
|
|||
|
||||
|
||||
;; ----------------------------------------------------------------------------
|
||||
(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.")
|
||||
(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.
|
||||
|
||||
(defun desktop--filter-frame-parms (frame)
|
||||
"Return frame parameters of FRAME.
|
||||
Parameters in `desktop--excluded-frame-parameters' are excluded.
|
||||
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 @@ Intended to be called from `desktop-save'.
|
|||
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 @@ This function also sets `desktop-dirname' to nil."
|
|||
(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)))))
|
||||
(defvar desktop--reuse-list nil
|
||||
"Internal use only.")
|
||||
|
||||
(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--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--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)))
|
||||
(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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue