This is a patch adding a query function when exiting Emacs, warning the user if there is a running clock. This is useful for preventing the user from accidentally leaving dangling clocks. I have had success using a modified personal version of this code.
My personal version instead prompts the user to clock out and save the buffer. I didn't use it for the patch because it seems a little hacky to me; e.g., kill-emacs-query-functions doesn't mention whether functions can have side effects, and the UI is inconsistent with save-buffers-kill-emacs. The code for my personal version: (add-to-list 'kill-emacs-query-functions (lambda () (if (not (org-clocking-p)) t (if (y-or-n-p "Clock out and save?") (with-current-buffer (marker-buffer org-clock-marker) (org-clock-out) (save-buffer) t) (message "Aborting") nil)))) If there is great demand for this version, I might provide another patch. I have also attached another patch which deduplicates two identical functions that I noticed when preparing the first patch.
>From f6145afd7d457cec533c44c8a3297d28f11d7255 Mon Sep 17 00:00:00 2001 From: Allen Li <darkfel...@felesatra.moe> Date: Tue, 12 Jan 2021 00:26:47 -0800 Subject: [PATCH 1/2] org-clock: Replace org-clocking-buffer with org-clock-is-active org-clocking-buffer and org-clock-is-active have the same definition. org-clocking-buffer is defined in org-clock.el while org-clock-is-active is defined in org.el. org-clock.el requires org.el. org-clocking-buffer is kept as an alias to preserve backward compatibility with any user code. * lisp/org-clock.el (org-clocking-buffer): Changed to alias. (org-clocking-p): Changed reference to org-clocking-buffer. (org-clock-out): Changed reference to org-clocking-buffer. (org-clock-cancel): Changed reference to org-clocking-buffer. (org-clock-sum): Changed reference to org-clocking-buffer. (org-clock-out-if-current): Changed reference to org-clocking-buffer. (org-clock-save): Changed reference to org-clocking-buffer. --- lisp/org-clock.el | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 892ae1810..37459580b 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -503,13 +503,11 @@ of a different task.") (mapc (lambda (m) (org-check-and-save-marker m beg end)) org-clock-history)) -(defun org-clocking-buffer () - "Return the clocking buffer if we are currently clocking a task or nil." - (marker-buffer org-clock-marker)) +(defalias 'org-clocking-buffer #'org-clock-is-active) (defun org-clocking-p () "Return t when clocking a task." - (not (equal (org-clocking-buffer) nil))) + (not (equal (org-clock-is-active) nil))) (defvar org-clock-before-select-task-hook nil "Hook called in task selection just before prompting the user.") @@ -1501,7 +1499,7 @@ to, overriding the existing value of `org-clock-out-switch-to-state'." ts te s h m remove) (setq org-clock-out-time now) (save-excursion ; Do not replace this with `with-current-buffer'. - (org-no-warnings (set-buffer (org-clocking-buffer))) + (org-no-warnings (set-buffer (org-clock-is-active))) (save-restriction (widen) (goto-char org-clock-marker) @@ -1652,7 +1650,7 @@ Optional argument N tells to change by that many units." (force-mode-line-update) (error "No active clock")) (save-excursion ; Do not replace this with `with-current-buffer'. - (org-no-warnings (set-buffer (org-clocking-buffer))) + (org-no-warnings (set-buffer (org-clock-is-active))) (goto-char org-clock-marker) (if (org-looking-back (concat "^[ \t]*" org-clock-string ".*")) (progn (delete-region (1- (point-at-bol)) (point-at-eol)) @@ -1763,7 +1761,7 @@ PROPNAME lets you set a custom text property instead of :org-clock-minutes." (t ;; A headline ;; Add the currently clocking item time to the total (when (and org-clock-report-include-clocking-task - (equal (org-clocking-buffer) (current-buffer)) + (equal (org-clock-is-active) (current-buffer)) (equal (marker-position org-clock-hd-marker) (point)) tstart tend @@ -1897,8 +1895,8 @@ and is only done if the variable `org-clock-out-when-done' is not nil." (member org-state org-done-keywords)) (and (listp org-clock-out-when-done) (member org-state org-clock-out-when-done))) - (equal (or (buffer-base-buffer (org-clocking-buffer)) - (org-clocking-buffer)) + (equal (or (buffer-base-buffer (org-clock-is-active)) + (org-clock-is-active)) (or (buffer-base-buffer (current-buffer)) (current-buffer))) (< (point) org-clock-marker) @@ -2816,7 +2814,7 @@ The details of what will be saved are regulated by the variable system-name (format-time-string (cdr org-time-stamp-formats)))) (if (and (memq org-clock-persist '(t clock)) - (setq b (org-clocking-buffer)) + (setq b (org-clock-is-active)) (setq b (or (buffer-base-buffer b) b)) (buffer-live-p b) (buffer-file-name b) @@ -2824,7 +2822,7 @@ The details of what will be saved are regulated by the variable (y-or-n-p (concat "Save current clock (" org-clock-heading ") ")))) (insert "(setq resume-clock '(\"" - (buffer-file-name (org-clocking-buffer)) + (buffer-file-name (org-clock-is-active)) "\" . " (int-to-string (marker-position org-clock-marker)) "))\n")) ;; Store clocked task history. Tasks are stored reversed to make -- 2.30.0
>From d12b01955773be64d04bd391d822cf7d1b67f637 Mon Sep 17 00:00:00 2001 From: Allen Li <darkfel...@felesatra.moe> Date: Tue, 12 Jan 2021 00:33:32 -0800 Subject: [PATCH 2/2] org-clock: Query when exiting with running clock It's annoying to accidentally quit Emacs with a running clock, then resolve the clock the next time when Emacs is started. * lisp/org-clock.el (org-clock-kill-emacs-query): New function. --- lisp/org-clock.el | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lisp/org-clock.el b/lisp/org-clock.el index 37459580b..bc1762f63 100644 --- a/lisp/org-clock.el +++ b/lisp/org-clock.el @@ -2886,6 +2886,15 @@ The details of what will be saved are regulated by the variable (if (outline-invisible-p) (org-show-context)))))))))) +(defun org-clock-kill-emacs-query () + "Query user when killing Emacs. +This function is added to `kill-emacs-query-functions'." + (if (org-clocking-buffer) + (y-or-n-p "Org clock is running; exit anyway? ") + t)) + +(add-hook 'kill-emacs-query-functions #'org-clock-kill-emacs-query) + ;; Suggested bindings (org-defkey org-mode-map "\C-c\C-x\C-e" 'org-clock-modify-effort-estimate) -- 2.30.0