95 lines
4.2 KiB
EmacsLisp
95 lines
4.2 KiB
EmacsLisp
;;; email/mu4e/autoload/mu-lock.el -*- lexical-binding: t; -*-
|
|
(autoload 'file-notify-rm-watch "filenotify")
|
|
(autoload 'file-notify-add-watch "filenotify")
|
|
|
|
(defvar +mu4e-lock-file (expand-file-name "mu4e_lock" temporary-file-directory)
|
|
"Location of the lock file which stores the PID of the process currenty running mu4e")
|
|
(defvar +mu4e-lock-request-file (expand-file-name "mu4e_lock_request" temporary-file-directory)
|
|
"Location of the lock file for which creating indicated that another process wants the lock to be released")
|
|
|
|
(defvar +mu4e-lock-greedy nil
|
|
"Whether to 'grab' the `+mu4e-lock-file' if nobody else has it, i.e. start Mu4e")
|
|
(defvar +mu4e-lock-relaxed t
|
|
"Whether if someone else wants the lock (signaled via `+mu4e-lock-request-file'), we should stop Mu4e and let go of it")
|
|
|
|
(defun +mu4e-lock-pid-info ()
|
|
"Get info on the PID refered to in `+mu4e-lock-file' in the form (pid . process-attributes)
|
|
If the file or process do not exist, the lock file is deleted an nil returned."
|
|
(when (file-exists-p +mu4e-lock-file)
|
|
(let* ((coding-system-for-read 'utf-8)
|
|
(pid (string-to-number
|
|
(with-temp-buffer
|
|
(insert-file-contents +mu4e-lock-file)
|
|
(buffer-string))))
|
|
(process (process-attributes pid)))
|
|
(if (and process (string-match-p "[Ee]macs" (alist-get 'comm process)))
|
|
(cons pid process)
|
|
(delete-file +mu4e-lock-file) nil))))
|
|
|
|
;;;###autoload
|
|
(defun +mu4e-lock-available (&optional strict)
|
|
"If the `+mu4e-lock-file' is available (unset or owned by this emacs) return t.
|
|
If STRICT only accept an unset lock file."
|
|
(not (when-let* ((lock-info (+mu4e-lock-pid-info))
|
|
(pid (car lock-info)))
|
|
(when (or strict (/= (emacs-pid) pid)) t))))
|
|
|
|
(defun +mu4e-lock-file-delete-maybe ()
|
|
"Check `+mu4e-lock-file', and delete it if this process is responsible for it."
|
|
(when (+mu4e-lock-available)
|
|
(delete-file +mu4e-lock-file)
|
|
(file-notify-rm-watch +mu4e-lock--request-watcher)))
|
|
|
|
;;;###autoload
|
|
(defun +mu4e-lock-start (orig-fun &optional callback)
|
|
"Check `+mu4e-lock-file', and if another process is responsible for it, abort starting.
|
|
Else, write to this process' PID to the lock file"
|
|
(unless (+mu4e-lock-available)
|
|
(call-process "touch" nil nil nil +mu4e-lock-request-file)
|
|
(message "Lock file exists, requesting that it be given up")
|
|
(sleep-for 0.1)
|
|
(delete-file +mu4e-lock-request-file))
|
|
(if (not (+mu4e-lock-available))
|
|
(user-error "Unfortunately another Emacs is already doing stuff with Mu4e, and you can only have one at a time")
|
|
(write-region (number-to-string (emacs-pid)) nil +mu4e-lock-file)
|
|
(delete-file +mu4e-lock-request-file)
|
|
;; (call-process "touch" nil nil nil +mu4e-lock-request-file)
|
|
(funcall orig-fun callback)
|
|
(when +mu4e-lock--request-watcher
|
|
(file-notify-rm-watch +mu4e-lock--request-watcher))
|
|
(file-notify-add-watch +mu4e-lock-request-file
|
|
'(change)
|
|
#'+mu4e-lock--request)))
|
|
|
|
(defvar +mu4e-lock--file-watcher nil)
|
|
(defvar +mu4e-lock--file-just-deleted nil)
|
|
(defvar +mu4e-lock--request-watcher nil)
|
|
|
|
(defun +mu4e-lock-add-watcher ()
|
|
(setq +mu4e-lock--file-just-deleted nil)
|
|
(file-notify-rm-watch +mu4e-lock--file-watcher)
|
|
(setq +mu4e-lock--file-watcher
|
|
(file-notify-add-watch +mu4e-lock-file
|
|
'(change)
|
|
#'+mu4e-lock--file-updated)))
|
|
|
|
(defun +mu4e-lock--request (event)
|
|
"Handle another process requesting the Mu4e lock."
|
|
(when (eq (nth 1 event) 'created)
|
|
(when +mu4e-lock-relaxed
|
|
(mu4e--stop)
|
|
(file-notify-rm-watch +mu4e-lock--file-watcher)
|
|
(file-notify-rm-watch +mu4e-lock--request-watcher)
|
|
(message "Someone else wants to use Mu4e, releasing lock")
|
|
(delete-file +mu4e-lock-file)
|
|
(run-at-time 0.2 nil #'+mu4e-lock-add-watcher))
|
|
(delete-file +mu4e-lock-request-file)))
|
|
|
|
(defun +mu4e-lock--file-updated (event)
|
|
(if +mu4e-lock--file-just-deleted
|
|
(+mu4e-lock-add-watcher)
|
|
(when (eq (nth 1 event) 'deleted)
|
|
(setq +mu4e-lock--file-just-deleted t)
|
|
(when (and +mu4e-lock-greedy (+mu4e-lock-available t))
|
|
(message "Noticed Mu4e lock was available, grabbed it")
|
|
(run-at-time 0.2 nil #'mu4e)))))
|