-;;; desktop.el --- save partial status of Emacs when killed
+;;; desktop.el --- save partial status of Emacs when killed -*- lexical-binding: t -*-
-;; Copyright (C) 1993-1995, 1997, 2000-2013 Free Software Foundation,
+;; Copyright (C) 1993-1995, 1997, 2000-2014 Free Software Foundation,
;; Inc.
;; Author: Morten Welinder <terra@diku.dk>
;; f89-kam@nada.kth.se (Klas Mellbourn) for a mh-e tip.
;; kifer@sbkifer.cs.sunysb.edu (M. Kifer) for a bug hunt.
;; treese@lcs.mit.edu (Win Treese) for ange-ftp tips.
-;; pot@cnuce.cnr.it (Francesco Potorti`) for misc. tips.
+;; pot@cnuce.cnr.it (Francesco Potortì) for misc. tips.
;; ---------------------------------------------------------------------------
;; TODO:
;;
one session to another. See variable `desktop-save' and function
`desktop-read' for details."
:global t
- :group 'desktop)
+ :group 'desktop
+ (if desktop-save-mode
+ (desktop-auto-save-set-timer)
+ (desktop-auto-save-cancel-timer)))
(defun desktop-save-mode-off ()
"Disable `desktop-save-mode'. Provided for use in hooks."
:group 'desktop
:version "22.1")
-(defcustom desktop-auto-save-timeout nil
- "Number of seconds between auto-saves of the desktop.
-Zero or nil means disable timer-based auto-saving."
+(defcustom desktop-auto-save-timeout auto-save-timeout
+ "Number of seconds idle time before auto-save of the desktop.
+Zero or nil means disable auto-saving due to idleness."
:type '(choice (const :tag "Off" nil)
(integer :tag "Seconds"))
:set (lambda (symbol value)
:type '(repeat symbol)
:group 'desktop)
-(defcustom desktop-buffers-not-to-save nil
+(defcustom desktop-buffers-not-to-save "\\` "
"Regexp identifying buffers that are to be excluded from saving."
:type '(choice (const :tag "None" nil)
regexp)
- :version "23.2" ; set to nil
+ :version "24.4" ; skip invisible temporary buffers
:group 'desktop)
;; Skip tramp and ange-ftp files
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))
+ (const :tag "Delete frames in other displays" delete))
:group 'desktop
:version "24.4")
(defcustom desktop-restore-forces-onscreen t
"If t, offscreen frames are restored onscreen instead.
-If `all', frames that are partially offscreen are also forced onscren.
+If `:all', frames that are partially offscreen are also forced onscreen.
NOTE: Checking of frame boundaries is only approximate and can fail
to reliably detect frames whose onscreen/offscreen state depends on a
few pixels, especially near the right / bottom borders of the screen."
:type '(choice (const :tag "Only fully offscreen frames" t)
- (const :tag "Also partially offscreen frames" 'all)
+ (const :tag "Also partially offscreen frames" :all)
(const :tag "Do not force frames onscreen" nil))
:group 'desktop
:version "24.4")
(defcustom desktop-restore-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."
+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))
+ (const :tag "Keep existing frames" :keep))
:group 'desktop
:version "24.4")
"Empty the Desktop.
This kills all buffers except for internal ones and those with names matched by
a regular expression in the list `desktop-clear-preserve-buffers'.
-Furthermore, it clears the variables listed in `desktop-globals-to-clear'."
+Furthermore, it clears the variables listed in `desktop-globals-to-clear'.
+When called interactively and `desktop-restore-frames' is non-nil, it also
+deletes all frames except the selected one (and its minibuffer frame,
+if different)."
(interactive)
(desktop-lazy-abort)
(dolist (var desktop-globals-to-clear)
(string-match-p preserve-regexp bufname))
(kill-buffer buffer)))))
(delete-other-windows)
- (let* ((this (selected-frame))
- (mini (window-frame (minibuffer-window this)))) ; in case they difer
- (dolist (frame (sort (frame-list) #'frameset-sort-frames-for-deletion))
- (condition-case err
- (unless (or (eq frame this)
- (eq frame mini)
- (frame-parameter frame 'desktop-dont-clear))
- (delete-frame frame))
- (error
- (delay-warning 'desktop (error-message-string err)))))))
+ (when (and desktop-restore-frames
+ ;; Non-interactive calls to desktop-clear happen before desktop-read
+ ;; which already takes care of frame restoration and deletion.
+ (called-interactively-p 'any))
+ (let* ((this (selected-frame))
+ (mini (window-frame (minibuffer-window this)))) ; in case they differ
+ (dolist (frame (sort (frame-list) #'frameset-minibufferless-first-p))
+ (condition-case err
+ (unless (or (eq frame this)
+ (eq frame mini)
+ (frame-parameter frame 'desktop-dont-clear))
+ (delete-frame frame))
+ (error
+ (delay-warning 'desktop (error-message-string err))))))))
;; ----------------------------------------------------------------------------
(unless noninteractive
;; ----------------------------------------------------------------------------
-(defvar desktop-filter-parameters-alist
- (append '((font-backend . t)
- (name . t)
- (outer-window-id . t)
- (parent-id . t)
- (tty . desktop--filter-tty*)
- (tty-type . desktop--filter-tty*)
- (window-id . t)
- (window-system . t))
- frameset-filter-alist)
- "Alist of frame parameters and filtering functions.
-Its format is identical to `frameset-filter-alist' (which see).")
-
-(defun desktop--filter-tty* (_current parameters saving)
- ;; Remove tty and tty-type parameters when switching
- ;; to a GUI frame.
- (or saving
- (not (frameset-switch-to-gui-p parameters))))
-
(defun desktop--check-dont-save (frame)
(not (frame-parameter frame 'desktop-dont-save)))
Frames with a non-nil `desktop-dont-save' parameter are not saved."
(setq desktop-saved-frameset
(and desktop-restore-frames
- (let ((name (concat user-login-name "@" system-name
- (format-time-string " %Y-%m-%d %T"))))
- (frameset-save nil
- :filters desktop-filter-parameters-alist
- :predicate #'desktop--check-dont-save
- :properties (list :app desktop--app-id
- :name name))))))
+ (frameset-save nil
+ :app desktop--app-id
+ :name (concat user-login-name "@" system-name)
+ :predicate #'desktop--check-dont-save))))
;;;###autoload
(defun desktop-save (dirname &optional release auto-save)
Optional parameter RELEASE says whether we're done with this desktop.
If AUTO-SAVE is non-nil, compare the saved contents to the one last saved,
and don't save the buffer if they are the same."
- (interactive "DDirectory to save desktop file in: ")
+ (interactive (list
+ ;; Or should we just use (car desktop-path)?
+ (let ((default (if (member "." desktop-path)
+ default-directory
+ user-emacs-directory)))
+ (read-directory-name "Directory to save desktop file in: "
+ default default t))))
(setq desktop-dirname (file-name-as-directory (expand-file-name dirname)))
(save-excursion
(let ((eager desktop-restore-eager)
(insert ")\n\n"))))
(setq default-directory desktop-dirname)
- ;; If auto-saving, avoid writing if nothing has changed since the last write.
- ;; Don't check 300 characters of the header that contains the timestamp.
- (let ((checksum (and auto-save (md5 (current-buffer)
- (+ (point-min) 300) (point-max)
- 'emacs-mule))))
- (unless (and auto-save (equal checksum desktop-file-checksum))
+ ;; When auto-saving, avoid writing if nothing has changed since the last write.
+ (let* ((beg (and auto-save
+ (save-excursion
+ (goto-char (point-min))
+ ;; Don't check the header with changing timestamp
+ (and (search-forward "Global section" nil t)
+ ;; Also skip the timestamp in desktop-saved-frameset
+ ;; if it's saved in the first non-header line
+ (search-forward "desktop-saved-frameset"
+ (line-beginning-position 3) t)
+ ;; This is saved after the timestamp
+ (search-forward (format "%S" desktop--app-id) nil t))
+ (point))))
+ (checksum (and beg (md5 (current-buffer) beg (point-max) 'emacs-mule))))
+ (unless (and checksum (equal checksum desktop-file-checksum))
(let ((coding-system-for-write 'emacs-mule))
(write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage))
(setq desktop-file-checksum checksum)
being set (usually, by reading it from the desktop)."
(when (desktop-restoring-frameset-p)
(frameset-restore desktop-saved-frameset
- :filters desktop-filter-parameters-alist
:reuse-frames desktop-restore-reuses-frames
:force-display desktop-restore-in-current-display
:force-onscreen desktop-restore-forces-onscreen)))
;; Just to silence the byte compiler.
-;; Dynamicaly bound in `desktop-read'.
+;; Dynamically bound in `desktop-read'.
(defvar desktop-first-buffer)
(defvar desktop-buffer-ok-count)
(defvar desktop-buffer-fail-count)
(walk-window-tree (lambda (window)
(set-window-prev-buffers window nil)
(set-window-next-buffers window nil))))
+ (setq desktop-saved-frameset nil)
t))
;; No desktop file found.
(desktop-clear)
;; Save only to own desktop file.
(eq (emacs-pid) (desktop-owner))
desktop-dirname)
- (desktop-save desktop-dirname nil t))
- (desktop-auto-save-set-timer))
+ (desktop-save desktop-dirname nil t)))
(defun desktop-auto-save-set-timer ()
- "Reset the auto-save timer.
+ "Set the auto-save timer.
Cancel any previous timer. When `desktop-auto-save-timeout' is a positive
-integer, start a new timer to call `desktop-auto-save' in that many seconds."
- (when desktop-auto-save-timer
- (cancel-timer desktop-auto-save-timer)
- (setq desktop-auto-save-timer nil))
+integer, start a new idle timer to call `desktop-auto-save' repeatedly
+after that many seconds of idle time."
+ (desktop-auto-save-cancel-timer)
(when (and (integerp desktop-auto-save-timeout)
(> desktop-auto-save-timeout 0))
(setq desktop-auto-save-timer
- (run-with-timer desktop-auto-save-timeout nil
- 'desktop-auto-save))))
+ (run-with-idle-timer desktop-auto-save-timeout t
+ 'desktop-auto-save))))
+
+(defun desktop-auto-save-cancel-timer ()
+ (when desktop-auto-save-timer
+ (cancel-timer desktop-auto-save-timer)
+ (setq desktop-auto-save-timer nil)))
;; ----------------------------------------------------------------------------
;;;###autoload
(let ((key "--no-desktop"))
(when (member key command-line-args)
(setq command-line-args (delete key command-line-args))
- (setq desktop-save-mode nil)))
+ (desktop-save-mode 0)))
(when desktop-save-mode
(desktop-read)
- (desktop-auto-save-set-timer)
(setq inhibit-startup-screen t))))
;; So we can restore vc-dir buffers.
(provide 'desktop)
;;; desktop.el ends here
+
+;; Local Variables:
+;; coding: utf-8
+;; End: