;;; desktop.el --- save partial status of Emacs when killed
-;; Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1993, 1994, 1995, 1997, 2000, 2001
+;; Free Software Foundation, Inc.
;; Author: Morten Welinder <terra@diku.dk>
;; Keywords: convenience
:type 'regexp
:group 'desktop)
+(defcustom desktop-buffer-modes-to-save
+ '(Info-mode rmail-mode)
+ "If a buffer is of one of these major modes, save the buffer name.
+It is up to the functions in `desktop-buffer-handlers' to decide
+whether the buffer should be recreated or not, and how."
+ :type '(repeat symbol)
+ :group 'desktop)
+
(defcustom desktop-modes-not-to-save nil
"List of major modes whose buffers should not be saved."
:type '(repeat symbol)
"When desktop creates a buffer, this holds a list of misc info.
It is used by the `desktop-buffer-handlers' functions.")
+(defcustom desktop-buffer-misc-functions
+ '(desktop-buffer-info-misc-data
+ desktop-buffer-dired-misc-data)
+ "*Functions used to determine auxiliary information for a buffer.
+These functions are called in order, with no arguments. If a function
+returns non-nil, its value is saved along with the desktop buffer for
+which it was called; no further functions will be called.
+
+Later, when desktop.el restores the buffers it has saved, each of the
+`desktop-buffer-handlers' functions will have access to a buffer local
+variable, named `desktop-buffer-misc', whose value is what the
+\"misc\" function returned previously."
+ :type '(repeat function)
+ :group 'desktop)
+
(defcustom desktop-buffer-handlers
'(desktop-buffer-dired
desktop-buffer-rmail
variables `desktop-buffer-major-mode', `desktop-buffer-file-name',
`desktop-buffer-name'.
If one function returns non-nil, no further functions are called.
-If the function returns t then the buffer is considered created."
+If the function returns a buffer, then the saved mode settings
+and variable values for that buffer are copied into it."
:type '(repeat function)
:group 'desktop)
+(put 'desktop-buffer-handlers 'risky-local-variable t)
+
(defvar desktop-create-buffer-form "(desktop-create-buffer 205"
"Opening of form for creation of new buffers.")
(not (string-match desktop-files-not-to-save
default-directory))))
(and (null filename)
- (memq mode '(Info-mode rmail-mode)))))))
+ (memq mode desktop-buffer-modes-to-save))))))
;; ----------------------------------------------------------------------------
+(defcustom desktop-relative-file-names nil
+ "*Store relative file names in the desktop file."
+ :type 'boolean
+ :group 'desktop)
+
(defun desktop-save (dirname)
"Save the Desktop file. Parameter DIRNAME specifies where to save desktop."
(interactive "DDirectory to save desktop file in: ")
(run-hooks 'desktop-save-hook)
(save-excursion
- (let ((filename (expand-file-name
- (concat dirname desktop-basefilename)))
+ (let ((filename (expand-file-name desktop-basefilename dirname))
(info (nreverse
(mapcar
(function
(lambda (b)
- (set-buffer b)
- (list
- (buffer-file-name)
- (buffer-name)
- major-mode
- ;; minor modes
- (let (ret)
- (mapcar
- #'(lambda (mim)
- (and (boundp mim)
- (symbol-value mim)
- (setq ret
- (cons (let ((special (assq mim desktop-minor-mode-table)))
- (if special
- (cadr special)
- mim))
- ret))))
- (mapcar #'car minor-mode-alist))
- ret)
- (point)
- (list (mark t) mark-active)
- buffer-read-only
- (cond ((eq major-mode 'Info-mode)
- (list Info-current-file
- Info-current-node))
- ((eq major-mode 'dired-mode)
- (cons
- (expand-file-name dired-directory)
- (cdr
- (nreverse
- (mapcar
- (function car)
- dired-subdir-alist))))))
- (let ((locals desktop-locals-to-save)
- (loclist (buffer-local-variables))
- (ll))
- (while locals
- (let ((here (assq (car locals) loclist)))
- (if here
- (setq ll (cons here ll))
- (if (member (car locals) loclist)
- (setq ll (cons (car locals) ll)))))
- (setq locals (cdr locals)))
- ll)
- )))
+ (set-buffer b)
+ (list
+ (let ((bn (buffer-file-name)))
+ (if bn
+ (if desktop-relative-file-names
+ (file-relative-name bn dirname)
+ bn)))
+ (buffer-name)
+ major-mode
+ ;; minor modes
+ (let (ret)
+ (mapcar
+ #'(lambda (mim)
+ (and (boundp mim)
+ (symbol-value mim)
+ (setq ret
+ (cons (let ((special (assq mim desktop-minor-mode-table)))
+ (if special
+ (cadr special)
+ mim))
+ ret))))
+ (mapcar #'car minor-mode-alist))
+ ret)
+ (point)
+ (list (mark t) mark-active)
+ buffer-read-only
+ (run-hook-with-args-until-success
+ 'desktop-buffer-misc-functions)
+ (let ((locals desktop-locals-to-save)
+ (loclist (buffer-local-variables))
+ (ll))
+ (while locals
+ (let ((here (assq (car locals) loclist)))
+ (if here
+ (setq ll (cons here ll))
+ (if (member (car locals) loclist)
+ (setq ll (cons (car locals) ll)))))
+ (setq locals (cdr locals)))
+ ll)
+ )))
(buffer-list))))
(buf (get-buffer-create "*desktop*")))
(set-buffer buf)
(erase-buffer)
- (insert desktop-header
+ (insert ";; -*- coding: emacs-mule; -*-\n"
+ desktop-header
";; Created " (current-time-string) "\n"
";; Emacs version " emacs-version "\n\n"
";; Global section:\n")
(insert "\n;; Buffer section:\n")
(mapcar
(function (lambda (l)
- (if (apply 'desktop-save-buffer-p l)
- (progn
- (insert desktop-create-buffer-form)
- (mapcar
- (function (lambda (e)
- (insert "\n "
- (desktop-value-to-string e))))
- l)
- (insert ")\n\n")))))
+ (if (apply 'desktop-save-buffer-p l)
+ (progn
+ (insert desktop-create-buffer-form)
+ (mapcar
+ (function (lambda (e)
+ (insert "\n "
+ (desktop-value-to-string e))))
+ l)
+ (insert ")\n\n")))))
info)
(setq default-directory dirname)
(if (file-exists-p filename) (delete-file filename))
- (write-region (point-min) (point-max) filename nil 'nomessage)))
+ (let ((coding-system-for-write 'emacs-mule))
+ (write-region (point-min) (point-max) filename nil 'nomessage))))
(setq desktop-dirname dirname))
;; ----------------------------------------------------------------------------
(defun desktop-remove ()
(setq dirs (cdr dirs)))
(setq desktop-dirname (and dirs (expand-file-name (car dirs))))
(if desktop-dirname
- (progn
+ (let ((desktop-last-buffer nil))
+ ;; `load-with-code-conversion' calls `eval-buffer' which
+ ;; contains a `save-excursion', so we end up with the same
+ ;; buffer before and after the load. This is a problem
+ ;; when the desktop is read initially when Emacs starts up
+ ;; because, if we still are in *scratch* after running
+ ;; `after-init-hook', the splash screen will be displayed.
(load (expand-file-name desktop-basefilename desktop-dirname)
t t t)
+ (when desktop-last-buffer
+ (switch-to-buffer desktop-last-buffer))
(run-hooks 'desktop-delay-hook)
(setq desktop-delay-hook nil)
(message "Desktop loaded."))
;; ----------------------------------------------------------------------------
;; Note: the following functions use the dynamic variable binding in Lisp.
;;
+(defun desktop-buffer-info-misc-data ()
+ (if (eq major-mode 'Info-mode)
+ (list Info-current-file
+ Info-current-node)))
+
+(defun desktop-buffer-dired-misc-data ()
+ (if (eq major-mode 'dired-mode)
+ (cons
+ (expand-file-name dired-directory)
+ (cdr
+ (nreverse
+ (mapcar
+ (function car)
+ dired-subdir-alist))))))
+
(defun desktop-buffer-info () "Load an info file."
(if (eq 'Info-mode desktop-buffer-major-mode)
(progn
- (require 'info)
- (Info-find-node (nth 0 desktop-buffer-misc) (nth 1 desktop-buffer-misc))
- (current-buffer))))
+ (let ((first (nth 0 desktop-buffer-misc))
+ (second (nth 1 desktop-buffer-misc)))
+ (when (and first second)
+ (require 'info)
+ (Info-find-node first second)
+ (current-buffer))))))
;; ----------------------------------------------------------------------------
(defun desktop-buffer-rmail () "Load an RMAIL file."
(if (eq 'rmail-mode desktop-buffer-major-mode)
(let ((buf (find-file-noselect desktop-buffer-file-name)))
(condition-case nil
(switch-to-buffer buf)
- (error (pop-to-buffer buf))))
+ (error (pop-to-buffer buf)))
+ buf)
'ignored)))
;; ----------------------------------------------------------------------------
;; Create a buffer, load its file, set is mode, ...; called from Desktop file
;; only.
+
+(defvar desktop-last-buffer nil
+ "Last buffer read. Dynamically bound in `desktop-read'.")
+
(defun desktop-create-buffer (ver desktop-buffer-file-name desktop-buffer-name
desktop-buffer-major-mode
mim pt mk ro desktop-buffer-misc
(setq result (funcall handler))
(setq hlist (cdr hlist)))
(when (bufferp result)
+ (setq desktop-last-buffer result)
(set-buffer result)
(if (not (equal (buffer-name) desktop-buffer-name))
(rename-buffer desktop-buffer-name))
(cond ((equal '(t) mim) (auto-fill-mode 1)) ; backwards compatible
((equal '(nil) mim) (auto-fill-mode 0))
(t (mapcar #'(lambda (minor-mode)
- (when minor-mode (funcall minor-mode 1)))
- mim)))
+ (when (functionp minor-mode)
+ (funcall minor-mode 1)))
+ mim)))
(goto-char pt)
(if (consp mk)
(progn