This changes `seen' to mean that the user viewed `enough' of the whole message: more precisely, a message is deemed seen if the top of the message and either the bottom of the message or a point at least some customisable number of lines into the message have each been visible in the buffer at some point.
This is placed into the post-command-hook infrastructure introduced in the previous patch. --- emacs/notmuch-show.el | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 1a7de85..1abf24b 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -211,6 +211,20 @@ (defcustom notmuch-show-mark-read-tags '("-unread") :type '(repeat string) :group 'notmuch-show) +(defcustom notmuch-show-seen-lines-needed 0.75 + "Control which messages get marked seen. + +A message is marked seen if both the top of the message and a +point far \"enough\" down in the message have each been visible +in the buffer at some point. This parameter controls the +definition of enough. + +Enough means either the bottom of the message or a point in the +message more than LINES-NEEDED lines into the message, where +LINES-NEEDED is this variable if this variable is an integer and +this variable times the current window height if it is a float." + :type 'number + :group 'notmuch-show) (defmacro with-current-notmuch-show-message (&rest body) "Evaluate body with current buffer set to the text of current message" @@ -1532,9 +1546,54 @@ (defun notmuch-show-mark-read (&optional unread) (apply 'notmuch-show-tag-message (notmuch-tag-change-list notmuch-show-mark-read-tags unread)))) +(defun notmuch-show-update-seen (top-or-bottom) + "Update seen status of current message + +Mark that we have seen the TOP-OR-BOTTOM of current message." + (let ((current (notmuch-show-get-prop :seen))) + (unless (or (eq current 'both) (eq current top-or-bottom)) + (if (not current) + (notmuch-show-set-prop :seen top-or-bottom) + (notmuch-show-set-prop :seen 'both) + (notmuch-show-mark-read))))) + +(defun notmuch-show-do-message-seen (start end) + "Update seen status for the current message. + +A message is seen if both the top and enough of the rest of the +message have been visible in the buffer. See the +`notmuch-show-seen-lines-needed' for the definition of `enough'." + (let* ((lines-needed (if (integerp notmuch-show-seen-lines-needed) + notmuch-show-seen-lines-needed + (truncate (* notmuch-show-seen-lines-needed (window-body-height))))) + (top (notmuch-show-message-top)) + (bottom (notmuch-show-message-bottom))) + (when (notmuch-show-message-visible-p) + (when (>= top start) + (notmuch-show-update-seen 'top)) + (when (or (<= bottom end) + (> (count-screen-lines top end) lines-needed)) + (notmuch-show-update-seen 'bottom))))) + (defun notmuch-show-do-seen (start end) - "Update seen status for all messages between start and end." - ) + "Update seen status for all messages between start and end. + +We mark the top (bottom) of a message seen if the top (enough of +the rest of the message) respectively have been visible in the +buffer. See the `notmuch-show-seen-lines-needed' for the +definition of `enough'. When both the top and bottom have been +seen we mark the message read." + (save-excursion + (goto-char start) + (notmuch-show-do-message-seen start end) + (while (and (< (notmuch-show-message-bottom) end) + (notmuch-show-goto-message-next)) + (notmuch-show-do-message-seen start end)) + ;; This is a work around because emacs gives weird answers for + ;; window-end if the buffer ends with invisible text. + (when (and (pos-visible-in-window-p (point-max)) + (notmuch-show-message-visible-p)) + (notmuch-show-update-seen 'bottom)))) (defun notmuch-show-command-hook () (when (eq major-mode 'notmuch-show-mode) -- 1.7.10.4