X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/c863b6ade69aaac9db586b38654dd1f28b7b5870..9875d23d86c0668b1e697b67a394560d66c7826d:/lisp/desktop.el diff --git a/lisp/desktop.el b/lisp/desktop.el index 6ec3ceed9d..bad0073fbb 100644 --- a/lisp/desktop.el +++ b/lisp/desktop.el @@ -174,8 +174,8 @@ For further details, see info node `(emacs)Saving Emacs Sessions'." :global t :group 'desktop (if desktop-save-mode - (desktop-auto-save-set-timer) - (desktop-auto-save-cancel-timer))) + (desktop-auto-save-enable) + (desktop-auto-save-disable))) (defun desktop-save-mode-off () "Disable `desktop-save-mode'. Provided for use in hooks." @@ -207,13 +207,17 @@ determine where the desktop is saved." (defcustom desktop-auto-save-timeout auto-save-timeout "Number of seconds idle time before auto-save of the desktop. +The idle timer activates auto-saving only when window configuration changes. This applies to an existing desktop file when `desktop-save-mode' is enabled. Zero or nil means disable auto-saving due to idleness." :type '(choice (const :tag "Off" nil) (integer :tag "Seconds")) :set (lambda (symbol value) (set-default symbol value) - (ignore-errors (desktop-auto-save-set-timer))) + (ignore-errors + (if (and (integerp value) (> value 0)) + (desktop-auto-save-enable value) + (desktop-auto-save-disable)))) :group 'desktop :version "24.4") @@ -387,15 +391,18 @@ modes are restored automatically; they should not be listed here." :group 'desktop) (defcustom desktop-restore-frames t - "When non-nil, save frames to desktop file." + "When non-nil, save and restore the frame and window configuration. +See related options `desktop-restore-reuses-frames', +`desktop-restore-in-current-display', and `desktop-restore-forces-onscreen'." :type 'boolean :group 'desktop :version "24.4") (defcustom desktop-restore-in-current-display nil - "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." + "Controls how restoring of frames treats displays. +If t, restores frames into the current display. +If nil, restores frames into their original displays (if possible). +If `delete', deletes frames on other displays instead of restoring them." :type '(choice (const :tag "Restore in current display" t) (const :tag "Restore in original display" nil) (const :tag "Delete frames in other displays" delete)) @@ -403,21 +410,23 @@ If `delete', frames on other displays are deleted instead of restored." :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 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." + "If t, restores frames that are fully offscreen onscreen instead. +If `all', also restores frames that are partially offscreen onscreen. + +Note that checking of frame boundaries is only approximate. +It 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 nil, deletes existing frames. +If `keep', keeps existing frames and does not reuse them." :type '(choice (const :tag "Reuse existing frames" t) (const :tag "Delete existing frames" nil) (const :tag "Keep existing frames" :keep)) @@ -491,13 +500,13 @@ Handlers are called with argument list Furthermore, they may use the following variables: - desktop-file-version - desktop-buffer-major-mode - desktop-buffer-minor-modes - desktop-buffer-point - desktop-buffer-mark - desktop-buffer-read-only - desktop-buffer-locals + `desktop-file-version' + `desktop-buffer-major-mode' + `desktop-buffer-minor-modes' + `desktop-buffer-point' + `desktop-buffer-mark' + `desktop-buffer-read-only' + `desktop-buffer-locals' If a handler returns a buffer, then the saved mode settings and variable values for that buffer are copied into it. @@ -519,6 +528,8 @@ Furthermore the major mode function must be autoloaded.") (defcustom desktop-minor-mode-table '((auto-fill-function auto-fill-mode) + (defining-kbd-macro nil) + (isearch-mode nil) (vc-mode nil) (vc-dired-mode nil) (erc-track-minor-mode nil) @@ -551,15 +562,15 @@ Handlers are called with argument list Furthermore, they may use the following variables: - desktop-file-version - desktop-buffer-file-name - desktop-buffer-name - desktop-buffer-major-mode - desktop-buffer-minor-modes - desktop-buffer-point - desktop-buffer-mark - desktop-buffer-read-only - desktop-buffer-misc + `desktop-file-version' + `desktop-buffer-file-name' + `desktop-buffer-name' + `desktop-buffer-major-mode' + `desktop-buffer-minor-modes' + `desktop-buffer-point' + `desktop-buffer-mark' + `desktop-buffer-read-only' + `desktop-buffer-misc' When a handler is called, the buffer has been created and the major mode has been set, but local variables listed in desktop-buffer-locals has not yet been @@ -692,7 +703,7 @@ if different)." (frame-parameter frame 'desktop-dont-clear)) (delete-frame frame)) (error - (delay-warning 'desktop (error-message-string err)))))))) + (delay-warning 'desktop (error-message-string err)))))))) ;; ---------------------------------------------------------------------------- (unless noninteractive @@ -839,12 +850,13 @@ QUOTE may be `may' (value may be quoted), "Convert VALUE to a string that when read evaluates to the same value. Not all types of values are supported." (let* ((print-escape-newlines t) + (print-length nil) + (print-level nil) (float-output-format nil) (quote.sexp (desktop--v2s value)) (quote (car quote.sexp)) - (txt - (let ((print-quoted t)) - (prin1-to-string (cdr quote.sexp))))) + (print-quoted t) + (txt (prin1-to-string (cdr quote.sexp)))) (if (eq quote 'must) (concat "'" txt) txt))) @@ -878,23 +890,25 @@ FILENAME is the visited file name, BUFNAME is the buffer name, and MODE is the major mode. \n\(fn FILENAME BUFNAME MODE)" (let ((case-fold-search nil) - dired-skip) - (and (not (and (stringp desktop-buffers-not-to-save) - (not filename) - (string-match-p desktop-buffers-not-to-save bufname))) - (not (memq mode desktop-modes-not-to-save)) - ;; FIXME this is broken if desktop-files-not-to-save is nil. - (or (and filename - (stringp desktop-files-not-to-save) - (not (string-match-p desktop-files-not-to-save filename))) - (and (memq mode '(dired-mode vc-dir-mode)) - (with-current-buffer bufname - (not (setq dired-skip - (string-match-p desktop-files-not-to-save - default-directory))))) - (and (null filename) - (null dired-skip) ; bug#5755 - (with-current-buffer bufname desktop-save-buffer)))))) + (no-regexp-to-check (not (stringp desktop-files-not-to-save))) + dired-skip) + (and (or filename + (not (stringp desktop-buffers-not-to-save)) + (not (string-match-p desktop-buffers-not-to-save bufname))) + (not (memq mode desktop-modes-not-to-save)) + (or (and filename + (or no-regexp-to-check + (not (string-match-p desktop-files-not-to-save filename)))) + (and (memq mode '(dired-mode vc-dir-mode)) + (or no-regexp-to-check + (not (setq dired-skip + (with-current-buffer bufname + (string-match-p desktop-files-not-to-save + default-directory)))))) + (and (null filename) + (null dired-skip) ; bug#5755 + (with-current-buffer bufname desktop-save-buffer))) + t))) ;; ---------------------------------------------------------------------------- (defun desktop-file-name (filename dirname) @@ -930,12 +944,13 @@ Frames with a non-nil `desktop-dont-save' parameter are not saved." :predicate #'desktop--check-dont-save)))) ;;;###autoload -(defun desktop-save (dirname &optional release auto-save) +(defun desktop-save (dirname &optional release only-if-changed) "Save the desktop in a desktop file. Parameter DIRNAME specifies where to save the desktop file. 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." +If ONLY-IF-CHANGED is non-nil, compare the current desktop information +to that in the desktop file, and if the desktop information has not +changed since it was last saved then do not rewrite the file." (interactive (list ;; Or should we just use (car desktop-path)? (let ((default (if (member "." desktop-path) @@ -1008,7 +1023,7 @@ and don't save the buffer if they are the same." (setq default-directory desktop-dirname) ;; When auto-saving, avoid writing if nothing has changed since the last write. - (let* ((beg (and auto-save + (let* ((beg (and only-if-changed (save-excursion (goto-char (point-min)) ;; Don't check the header with changing timestamp @@ -1056,7 +1071,8 @@ This function depends on the value of `desktop-saved-frameset' being set (usually, by reading it from the desktop)." (when (desktop-restoring-frameset-p) (frameset-restore desktop-saved-frameset - :reuse-frames desktop-restore-reuses-frames + :reuse-frames (eq desktop-restore-reuses-frames t) + :cleanup-frames (not (eq desktop-restore-reuses-frames 'keep)) :force-display desktop-restore-in-current-display :force-onscreen desktop-restore-forces-onscreen))) @@ -1115,6 +1131,10 @@ Using it may cause conflicts. Use it anyway? " owner))))) (unless desktop-dirname (message "Desktop file in use; not loaded."))) (desktop-lazy-abort) + ;; Temporarily disable the autosave that will leave it + ;; disabled when loading the desktop fails with errors, + ;; thus not overwriting the desktop with broken contents. + (desktop-auto-save-disable) ;; Evaluate desktop buffer and remember when it was modified. (load (desktop-full-file-name) t t t) (setq desktop-file-modtime (nth 5 (file-attributes (desktop-full-file-name)))) @@ -1167,6 +1187,7 @@ Using it may cause conflicts. Use it anyway? " owner))))) (set-window-prev-buffers window nil) (set-window-next-buffers window nil)))) (setq desktop-saved-frameset nil) + (desktop-auto-save-enable) t)) ;; No desktop file found. (desktop-clear) @@ -1213,6 +1234,15 @@ directory DIRNAME." ;; Auto-Saving. (defvar desktop-auto-save-timer nil) +(defun desktop-auto-save-enable (&optional timeout) + (when (and (integerp (or timeout desktop-auto-save-timeout)) + (> (or timeout desktop-auto-save-timeout) 0)) + (add-hook 'window-configuration-change-hook 'desktop-auto-save-set-timer))) + +(defun desktop-auto-save-disable () + (remove-hook 'window-configuration-change-hook 'desktop-auto-save-set-timer) + (desktop-auto-save-cancel-timer)) + (defun desktop-auto-save () "Save the desktop periodically. Called by the timer created in `desktop-auto-save-set-timer'." @@ -1235,7 +1265,7 @@ after that many seconds of idle time." (when (and (integerp desktop-auto-save-timeout) (> desktop-auto-save-timeout 0)) (setq desktop-auto-save-timer - (run-with-idle-timer desktop-auto-save-timeout t + (run-with-idle-timer desktop-auto-save-timeout nil 'desktop-auto-save)))) (defun desktop-auto-save-cancel-timer () @@ -1345,7 +1375,9 @@ after that many seconds of idle time." ;; Restore buffer list order with new buffer at end. Don't change ;; the order for old desktop files (old desktop module behavior). (unless (< desktop-file-version 206) - (mapc 'bury-buffer buffer-list) + (dolist (buf buffer-list) + (and (buffer-live-p buf) + (bury-buffer buf))) (when result (bury-buffer result))) (when result (unless (or desktop-first-buffer (< desktop-file-version 206)) @@ -1378,20 +1410,21 @@ after that many seconds of idle time." (eval desktop-buffer-point) (error (message "%s" (error-message-string err)) 1)))) (when desktop-buffer-mark - (if (consp desktop-buffer-mark) - (progn - (set-mark (car desktop-buffer-mark)) - (setq mark-active (car (cdr desktop-buffer-mark)))) - (set-mark desktop-buffer-mark))) + (if (consp desktop-buffer-mark) + (progn + (move-marker (mark-marker) (car desktop-buffer-mark)) + (if (car (cdr desktop-buffer-mark)) + (activate-mark 'dont-touch-tmm))) + (move-marker (mark-marker) desktop-buffer-mark))) ;; Never override file system if the file really is read-only marked. (when desktop-buffer-read-only (setq buffer-read-only desktop-buffer-read-only)) (dolist (this desktop-buffer-locals) (if (consp this) - ;; an entry of this form `(symbol . value)' + ;; An entry of this form `(symbol . value)'. (progn (make-local-variable (car this)) (set (car this) (cdr this))) - ;; an entry of the form `symbol' + ;; An entry of the form `symbol'. (make-local-variable this) (makunbound this)))))))) @@ -1485,8 +1518,15 @@ If there are no buffers left to create, kill the timer." (setq command-line-args (delete key command-line-args)) (desktop-save-mode 0))) (when desktop-save-mode - (desktop-read) - (setq inhibit-startup-screen t)))) + ;; People don't expect emacs -nw, or --daemon, + ;; to create graphical frames (bug#17693). + ;; TODO perhaps there should be a separate value + ;; for desktop-restore-frames to control this startup behavior? + (let ((desktop-restore-frames (and desktop-restore-frames + initial-window-system + (not (daemonp))))) + (desktop-read) + (setq inhibit-startup-screen t))))) ;; So we can restore vc-dir buffers. (autoload 'vc-dir-mode "vc-dir" nil t)