can avoid the question by customizing the variable
@code{desktop-load-locked-desktop} to either @code{nil}, which means
never load the desktop in this case, or @code{t}, which means load the
-desktop without asking.
+desktop without asking. Finally, the @code{check-pid} value means to
+load the file if the Emacs process that has locked the desktop 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. This could be the case in multi-user environments
+where your home directory is mounted remotely using NFS or similar.
@cindex desktop restore in daemon mode
When Emacs starts in daemon mode, it cannot ask you any questions,
Instead, they're fetched as needed from the corresponding ".elc" file,
as was already the case for all the non-preloaded files.
+** Emacs Sessions (Desktop)
+
++++
+*** New option to load if locking Emacs not running locally.
+The option 'desktop-load-locked-desktop' can now be set to value
+'check-pid', which means to load the desktop only if the locking Emacs
+process is not running on the local machine. See the "(emacs) Saving
+Emacs Sessions" node in the Emacs manual for details.
+
\f
* Startup Changes in Emacs 29.1
(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")
(integerp owner)))
owner)))
+(defun desktop--emacs-pid-running-p (pid)
+ "Return t if an Emacs process with PID exists."
+ (when-let ((attr (process-attributes pid)))
+ (equal (alist-get 'comm attr)
+ (file-name-nondirectory (car command-line-args)))))
+
+(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'."
(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 PID %s.\n\
-Using it may cause conflicts. Use it anyway? " owner)))))
+ (not (desktop--load-locked-desktop-p owner)))
(let ((default-directory desktop-dirname))
(setq desktop-dirname nil)
(run-hooks 'desktop-not-loaded-hook)
--- /dev/null
+;;; desktop-tests.el --- Tests for desktop.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2020 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'ert)
+(require 'desktop)
+
+(ert-deftest desktop-tests--emacs-pid-running-p ()
+ (should (desktop--emacs-pid-running-p (emacs-pid)))
+ (should-not (desktop--emacs-pid-running-p 1)))
+
+(ert-deftest desktop-tests--load-locked-desktop-p ()
+ (let ((desktop-load-locked-desktop t))
+ (should (desktop--load-locked-desktop-p (emacs-pid)))))
+
+(ert-deftest desktop-tests--load-locked-desktop-p-nil ()
+ (let ((desktop-load-locked-desktop nil))
+ (should-not (desktop--load-locked-desktop-p (emacs-pid)))))
+
+(ert-deftest desktop-tests--load-locked-desktop-p-ask ()
+ (let ((desktop-load-locked-desktop 'ask))
+ (cl-letf (((symbol-function 'y-or-n-p) (lambda (&rest _) t)))
+ (should (desktop--load-locked-desktop-p (emacs-pid))))
+ (cl-letf (((symbol-function 'y-or-n-p) (lambda (&rest _) nil)))
+ (should-not (desktop--load-locked-desktop-p (emacs-pid))))))
+
+(ert-deftest desktop-tests--load-locked-desktop-p-check ()
+ (let ((desktop-load-locked-desktop 'check-pid))
+ (desktop--load-locked-desktop-p (emacs-pid))))
+
+(provide 'desktop-tests)