;;; desktop.el --- save partial status of Emacs when killed -*- lexical-binding: t -*-
-;; Copyright (C) 1993-1995, 1997, 2000-2014 Free Software Foundation, Inc.
+;; Copyright (C) 1993-1995, 1997, 2000-2015 Free Software Foundation,
+;; Inc.
;; Author: Morten Welinder <terra@diku.dk>
;; Keywords: convenience
;; (add-to-list 'desktop-minor-mode-handlers
;; '(bar-mode . bar-desktop-restore))
-;; in the module itself, and make sure that the mode function is
-;; autoloaded. See the docstrings of `desktop-buffer-mode-handlers' and
+;; in the module itself. The mode function must either be autoloaded,
+;; or of the form "foobar-mode" and defined in library "foobar", so that
+;; desktop can guess how to load its definition.
+;; See the docstrings of `desktop-buffer-mode-handlers' and
;; `desktop-minor-mode-handlers' for more info.
;; Minor modes.
(require 'cl-lib)
(require 'frameset)
-(defvar desktop-file-version "206"
+(defvar desktop-file-version "208"
"Version number of desktop file format.
Written into the desktop file and used at desktop read to provide
backward compatibility.")
it exits (this may prompt you; see the option `desktop-save'). The next
time Emacs starts, if this mode is active it will restore the desktop.
-To manually save the desktop at any time, use the command `M-x desktop-save'.
-To load it, use `M-x desktop-read'.
+To manually save the desktop at any time, use the command `\\[desktop-save]'.
+To load it, use `\\[desktop-read]'.
Once a desktop file exists, Emacs will auto-save it according to the
option `desktop-auto-save-timeout'.
(add-to-list 'desktop-buffer-mode-handlers
'(foo-mode . foo-restore-desktop-buffer))
-Furthermore the major mode function must be autoloaded.")
+The major mode function must either be autoloaded, or of the form
+\"foobar-mode\" and defined in library \"foobar\", so that desktop
+can guess how to load the mode's definition.")
;;;###autoload
(put 'desktop-buffer-mode-handlers 'risky-local-variable t)
(add-to-list 'desktop-minor-mode-handlers
'(foo-mode . foo-desktop-restore))
-Furthermore the minor mode function must be autoloaded.
+The minor mode function must either be autoloaded, or of the form
+\"foobar-mode\" and defined in library \"foobar\", so that desktop
+can guess how to load the mode's definition.
See also `desktop-minor-mode-table'.")
"When the desktop file was last modified to the knowledge of this Emacs.
Used to detect desktop file conflicts.")
+(defvar desktop-var-serdes-funs
+ (list (list
+ 'mark-ring
+ (lambda (mr)
+ (mapcar #'marker-position mr))
+ (lambda (mr)
+ (mapcar #'copy-marker mr))))
+ "Table of serialization/deserialization functions for variables.
+Each record is a list of form: (var serializer deserializer).
+These records can be freely reordered, deleted, or new ones added.
+However, for compatibility, don't modify the functions for existing records.")
+
(defun desktop-owner (&optional dirname)
"Return the PID of the Emacs process that owns the desktop file in DIRNAME.
Return nil if no desktop file found or no Emacs process is using it.
;; ----------------------------------------------------------------------------
(defun desktop-buffer-info (buffer)
+ "Return information describing BUFFER.
+This function is not pure, as BUFFER is made current with
+`set-buffer'.
+
+Returns a list of all the necessary information to recreate the
+buffer, which is (in order):
+
+ `uniquify-buffer-base-name';
+ `buffer-file-name';
+ `buffer-name';
+ `major-mode';
+ list of minor-modes,;
+ `point';
+ `mark';
+ `buffer-read-only';
+ auxiliary information given by `desktop-save-buffer';
+ local variables;
+ auxiliary information given by `desktop-var-serdes-funs'."
(set-buffer buffer)
(list
;; base name of the buffer; replaces the buffer name if managed by uniquify
major-mode
;; minor modes
(let (ret)
- (mapc
- #'(lambda (minor-mode)
- (and (boundp minor-mode)
- (symbol-value minor-mode)
- (let* ((special (assq minor-mode desktop-minor-mode-table))
- (value (cond (special (cadr special))
- ((functionp minor-mode) minor-mode))))
- (when value (add-to-list 'ret value)))))
- (mapcar #'car minor-mode-alist))
- ret)
+ (dolist (minor-mode (mapcar #'car minor-mode-alist) ret)
+ (and (boundp minor-mode)
+ (symbol-value minor-mode)
+ (let* ((special (assq minor-mode desktop-minor-mode-table))
+ (value (cond (special (cadr special))
+ ((functionp minor-mode) minor-mode))))
+ (when value (cl-pushnew value ret))))))
;; point and mark, and read-only status
(point)
(list (mark t) mark-active)
(push here ll))
((member local loclist)
(push local ll)))))
- ll)))
+ ll)
+ (mapcar (lambda (record)
+ (let ((var (car record)))
+ (list var
+ (funcall (cadr record) (symbol-value var)))))
+ desktop-var-serdes-funs)))
;; ----------------------------------------------------------------------------
(defun desktop--v2s (value)
(and desktop-restore-frames
(frameset-save nil
:app desktop--app-id
- :name (concat user-login-name "@" system-name)
+ :name (concat user-login-name "@" (system-name))
:predicate #'desktop--check-dont-save))))
;;;###autoload
(desktop-buffer-fail-count 0)
(owner (desktop-owner))
;; Avoid desktop saving during evaluation of desktop buffer.
- (desktop-save nil))
+ (desktop-save nil)
+ (desktop-autosave-was-enabled))
(if (and owner
(memq desktop-load-locked-desktop '(nil ask))
(or (null desktop-load-locked-desktop)
;; Temporarily disable the autosave that will leave it
;; disabled when loading the desktop fails with errors,
;; thus not overwriting the desktop with broken contents.
+ (setq desktop-autosave-was-enabled
+ (memq 'desktop-auto-save-set-timer window-configuration-change-hook))
(desktop-auto-save-disable)
;; Evaluate desktop buffer and remember when it was modified.
(load (desktop-full-file-name) t t t)
(set-window-prev-buffers window nil)
(set-window-next-buffers window nil))))
(setq desktop-saved-frameset nil)
- (desktop-auto-save-enable)
+ (if desktop-autosave-was-enabled (desktop-auto-save-enable))
t))
;; No desktop file found.
- (desktop-clear)
(let ((default-directory desktop-dirname))
(run-hooks 'desktop-no-desktop-file-hook))
(message "No desktop file.")
nil)))
(defun desktop-load-file (function)
- "Load the file where auto loaded FUNCTION is defined."
- (when (fboundp function)
- (autoload-do-load (symbol-function function) function)))
+ "Load the file where auto loaded FUNCTION is defined.
+If FUNCTION is not currently defined, guess the library that defines it
+and try to load that."
+ (if (fboundp function)
+ (autoload-do-load (symbol-function function) function)
+ ;; Guess that foobar-mode is defined in foobar.
+ ;; TODO rather than guessing or requiring an autoload, the desktop
+ ;; file should record the name of the library.
+ (let ((name (symbol-name function)))
+ (if (string-match "\\`\\(.*\\)-mode\\'" name)
+ (with-demoted-errors "Require error in desktop-load-file: %S"
+ (require (intern (match-string 1 name)) nil t))))))
;; ----------------------------------------------------------------------------
;; Create a buffer, load its file, set its mode, ...;
buffer-readonly
buffer-misc
&optional
- buffer-locals)
+ buffer-locals
+ compacted-vars
+ &rest _unsupported)
(let ((desktop-file-version file-version)
(desktop-buffer-file-name buffer-filename)
(set (car this) (cdr this)))
;; An entry of the form `symbol'.
(make-local-variable this)
- (makunbound this))))))))
+ (makunbound this)))
+ (unless (< desktop-file-version 208) ; Don't misinterpret any old custom args
+ (dolist (record compacted-vars)
+ (let*
+ ((var (car record))
+ (deser-fun (nth 2 (assq var desktop-var-serdes-funs))))
+ (if deser-fun (set var (funcall deser-fun (cadr record))))))))
+ result))))
;; ----------------------------------------------------------------------------
;; Backward compatibility -- update parameters to 205 standards.
(desktop-read)
(setq inhibit-startup-screen t)))))
-;; So we can restore vc-dir buffers.
-(autoload 'vc-dir-mode "vc-dir" nil t)
-
(provide 'desktop)
;;; desktop.el ends here
-
-;; Local Variables:
-;; coding: utf-8
-;; End: