diff options
Diffstat (limited to 'lisp/desktop.el')
-rw-r--r-- | lisp/desktop.el | 129 |
1 files changed, 96 insertions, 33 deletions
diff --git a/lisp/desktop.el b/lisp/desktop.el index 9cd26646dec..ef73bc596df 100644 --- a/lisp/desktop.el +++ b/lisp/desktop.el @@ -231,16 +231,26 @@ Zero or nil means disable auto-saving due to idleness." (defcustom desktop-load-locked-desktop 'ask "Specifies whether the desktop should be loaded if locked. Possible values are: - t -- load anyway. - nil -- don't load. - ask -- ask the user. -If the value is nil, or `ask' and the user chooses not to load the desktop, -the normal hook `desktop-not-loaded-hook' is run." + t -- load anyway. + nil -- don't load. + ask -- ask the user. + check-pid -- load if locking Emacs process is missing locally. + +If the value is nil, or `ask' and the user chooses not to load +the desktop, the normal hook `desktop-not-loaded-hook' is run. + +If the value is `check-pid', load the desktop if the Emacs +process that has locked it is not running on the local machine. +This should not be used in circumstances where the locking Emacs +might still be running on another machine. That could be the +case if you have remotely mounted (NFS) paths in +`desktop-dirname'." :type '(choice (const :tag "Load anyway" t) (const :tag "Don't load" nil) - (const :tag "Ask the user" ask)) + (const :tag "Ask the user" ask) + (const :tag "Load if no local process" check-pid)) :group 'desktop :version "22.2") @@ -425,7 +435,9 @@ 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." +of the screen. +Text-mode frames are always considered onscreen, so this option has +no effect on restoring frames in a non-GUI session." :type '(choice (const :tag "Only fully offscreen frames" t) (const :tag "Also partially offscreen frames" all) (const :tag "Do not force frames onscreen" nil)) @@ -469,7 +481,7 @@ If value is t, all buffers are restored immediately." (defcustom desktop-lazy-idle-delay 5 "Idle delay before starting to create buffers. See `desktop-restore-eager'." - :type 'integer + :type 'natnum :group 'desktop :version "22.1") @@ -636,6 +648,14 @@ Only valid during frame saving & restoring; intended for internal use.") "When the desktop file was last modified to the knowledge of this Emacs. Used to detect desktop file conflicts.") +(defun desktop--get-file-modtime () + "Get desktop file modtime, in list form for desktop format version 208." + (setq desktop-file-modtime + (time-convert (file-attribute-modification-time + (file-attributes + (desktop-full-file-name))) + 'list))) + (defvar desktop-var-serdes-funs (list (list 'mark-ring @@ -663,6 +683,44 @@ DIRNAME omitted or nil means use `desktop-dirname'." (integerp owner))) owner))) +(defun desktop--emacs-pid-running-p (pid) + "Return non-nil if an Emacs process whose ID is PID might still be running." + (when-let ((attr (process-attributes pid))) + (let ((proc-cmd (alist-get 'comm attr)) + (my-cmd (file-name-nondirectory (car command-line-args))) + (case-fold-search t)) + (or (equal proc-cmd my-cmd) + (and (eq system-type 'windows-nt) + (eq t (compare-strings proc-cmd + nil + (if (string-suffix-p ".exe" proc-cmd t) + -4) + my-cmd + nil + (if (string-suffix-p ".exe" my-cmd t) + -4)))) + ;; We should err on the safe side here: if any of the + ;; executables is something like "emacs-nox" or "emacs-42.1" + ;; or "gemacs", let's recognize them as well. + (and (string-match-p "emacs" proc-cmd) + (string-match-p "emacs" my-cmd)))))) + +(defun desktop--load-locked-desktop-p (owner) + "Return t if a locked desktop should be loaded. +OWNER is the pid in the lock file. +The return value of this function depends on the value of +`desktop-load-locked-desktop'." + (pcase desktop-load-locked-desktop + ('ask + (unless (daemonp) + (y-or-n-p (format "Warning: desktop file appears to be in use by PID %s.\n\ +Using it may cause conflicts. Use it anyway? " owner)))) + ('check-pid + (or (eq (emacs-pid) owner) + (not (desktop--emacs-pid-running-p owner)))) + ('nil nil) + (_ t))) + (defun desktop-claim-lock (&optional dirname) "Record this Emacs process as the owner of the desktop file in DIRNAME. DIRNAME omitted or nil means use `desktop-dirname'." @@ -806,15 +864,16 @@ buffer, which is (in order): ,(buffer-name) ,major-mode ;; minor modes - ,(let (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)) - ((get minor-mode :minor-mode-function)) - ((functionp minor-mode) minor-mode)))) - (when value (cl-pushnew value ret)))))) + ,(seq-filter + (lambda (minor-mode) + ;; Just two sanity checks. + (and (boundp minor-mode) + (symbol-value minor-mode) + (let ((special + (assq minor-mode desktop-minor-mode-table))) + (or (not special) + (cadr special))))) + local-minor-modes) ;; point and mark, and read-only status ,(point) ,(list (mark t) mark-active) @@ -1079,7 +1138,7 @@ no questions asked." (file-attributes (desktop-full-file-name))))) (when (or (not new-modtime) ; nothing to overwrite - (equal desktop-file-modtime new-modtime) + (time-equal-p desktop-file-modtime new-modtime) (yes-or-no-p (if desktop-file-modtime (if (time-less-p desktop-file-modtime new-modtime) @@ -1179,9 +1238,7 @@ no questions asked." (write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage)) (setq desktop-file-checksum checksum) ;; We remember when it was modified (which is presumably just now). - (setq desktop-file-modtime (file-attribute-modification-time - (file-attributes - (desktop-full-file-name))))))))))) + (desktop--get-file-modtime)))))))) ;; ---------------------------------------------------------------------------- ;;;###autoload @@ -1203,7 +1260,11 @@ This function also sets `desktop-dirname' to nil." ;; ---------------------------------------------------------------------------- (defun desktop-restoring-frameset-p () "True if calling `desktop-restore-frameset' will actually restore it." - (and desktop-restore-frames desktop-saved-frameset (display-graphic-p) t)) + (and desktop-restore-frames desktop-saved-frameset + ;; Don't restore frames when the selected frame is the daemon's + ;; initial frame. + (not (and (daemonp) (not (frame-parameter nil 'client)))) + t)) (defun desktop-restore-frameset () "Restore the state of a set of frames. @@ -1214,7 +1275,17 @@ being set (usually, by reading it from the desktop)." :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))) + :force-onscreen (and desktop-restore-forces-onscreen + (display-graphic-p))) + ;; When at least one restored frame contains a tab bar, + ;; enable `tab-bar-mode' that takes care about recalculating + ;; the correct values of the frame parameter `tab-bar-lines' + ;; (that depends on `tab-bar-show'), and also loads graphical buttons. + (when (seq-some + (lambda (frame) + (menu-bar-positive-p (frame-parameter frame 'tab-bar-lines))) + (frame-list)) + (tab-bar-mode 1)))) ;; Just to silence the byte compiler. ;; Dynamically bound in `desktop-read'. @@ -1270,13 +1341,7 @@ It returns t if a desktop file was loaded, nil otherwise. (desktop-save nil) (desktop-autosave-was-enabled)) (if (and owner - (memq desktop-load-locked-desktop '(nil ask)) - (or (null desktop-load-locked-desktop) - (daemonp) - (not (y-or-n-p (format " -Warning: desktop file appears to be in use by process with PID %s.\n\ -Using it may cause conflicts if that process still runs.\n\ -Use desktop file anyway? " owner))))) + (not (desktop--load-locked-desktop-p owner))) (let ((default-directory desktop-dirname)) (setq desktop-dirname nil) (run-hooks 'desktop-not-loaded-hook) @@ -1296,9 +1361,7 @@ Use desktop file anyway? " owner))))) 'window-configuration-change-hook))) (desktop-auto-save-disable) ;; Evaluate desktop buffer and remember when it was modified. - (setq desktop-file-modtime (file-attribute-modification-time - (file-attributes - (desktop-full-file-name)))) + (desktop--get-file-modtime) (load (desktop-full-file-name) t t t) ;; If it wasn't already, mark it as in-use, to bother other ;; desktop instances. |