From e9835c21aa7579db41d7c6e91050cd8c96b7f8e3 Mon Sep 17 00:00:00 2001 From: Thomas Ulmer Date: Mon, 9 Jun 2025 14:30:04 -0700 Subject: single-header fix, prevent thrashing and switch to post-command-hook --- emacs/init.el | 9 ++-- emacs/site-lisp/single-header.el | 89 ++++++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/emacs/init.el b/emacs/init.el index 3024828..1e8d2c9 100644 --- a/emacs/init.el +++ b/emacs/init.el @@ -918,17 +918,16 @@ BEG and END define the region." (global-set-key (kbd "C-x w o") 'my/toggle-window-other-reachability) -(use-package ednc ; notifications, required for single-header - ) + (progn ; single header line per frame w/ info ;; after exwm + (use-package ednc ; notifications, required for single-header + ) (require 'single-header) (single-header-mode 1) (keymap-global-set "M-L d" 'single-header-dismiss) - (keymap-global-set "M-L h" 'single-header-delete) - (keymap-global-set "M-L m" 'single-header-make) - ) + (keymap-global-set "M-L t" 'single-header-mode)) ;; ---------------------------------------------------------------------- diff --git a/emacs/site-lisp/single-header.el b/emacs/site-lisp/single-header.el index 2713c5b..e9cce2a 100755 --- a/emacs/site-lisp/single-header.el +++ b/emacs/site-lisp/single-header.el @@ -1,8 +1,14 @@ +;; single-header --- Display a topline inside a frame with global info -*- lexical-binding: t; -*- (require 'ednc) (require 'battery) (require 's) (require 'dash) +;;; Commentary: +;;; + +;;; Code: + ;; not toggled with the mode to prevent user from having to restart ;; applications producing notifs. (when (equal window-system 'x) @@ -13,16 +19,24 @@ ;; (notifications-notify :title "2st test" :body "hello, world" :app-name "EDNC" ;; :actions '("default" "default")) -(defvar single-header-update-increment 3 "Number of seconds before updating the header again.") - -(defvar single-header--current-header-buffer nil "Read the name") - -(defface single-header '((default . (:background "#000000" :family "Source Code Pro"))) "Face for top line") - -(setq single-header--active-notifs nil) -(setq single-header--timer nil -;; "Timer that triggers updates of the header contents. Use `single-header-update' for forcing updates." - ) +(defgroup single-header + '((single-header-face custom-face) + (single-header-update-increment custom-variable)) + "Custom variables for the single header package." + :prefix "single-header" + :group 'emacs) + +(defface single-header-face '((default . (:background "#000000" :family "Source Code Pro"))) + "Base face for the header line." + :group 'single-header) + +(defcustom single-header-update-increment 10 + "Number of seconds before updating the header again." + :type 'natnum + :group 'single-header) +(defvar single-header--current-header-buffer nil) +(defvar single-header--active-notifs nil) +(defvar single-header--last-update-time 0) (defun single-header--with-face (str &rest face-plist) "Convenience wrapper for `add-face-text-property'." @@ -36,7 +50,9 @@ (when (and old (member old single-header--active-notifs)) (setq single-header--active-notifs - (remove old single-header--active-notifs)))) + (remove old single-header--active-notifs))) + (when (or new old) + (single-header-update t))) (defun single-header--make-notif-string () "Produce a string representation of the active notifications." @@ -72,13 +88,11 @@ arg, dismiss all the notifications." (filled (min win-width (+ info-width notifs-width))) (padding-width (- win-width filled)) (padding (make-string padding-width ? ))) - (setq notifs (single-header--with-face notifs 'single-header)) - (setq padding (single-header--with-face padding 'single-header)) - (setq info (single-header--with-face info 'single-header)) + (setq notifs (single-header--with-face notifs 'single-header-face)) + (setq padding (single-header--with-face padding 'single-header-face)) + (setq info (single-header--with-face info 'single-header-face)) (insert notifs padding info))) - - (defun single-header--make-header-info-string () "Generates the mode line string that contains all the info to the right." (let ((str (concat @@ -97,7 +111,7 @@ arg, dismiss all the notifications." (single-header--with-face (format-time-string "%R") :weight 'bold) ))) - (single-header--with-face str 'single-header))) + (single-header--with-face str 'single-header-face))) (defun single-header-init-buffer (buf) (with-current-buffer buf @@ -128,7 +142,7 @@ arg, dismiss all the notifications." (fit-window-to-buffer win 1)) (setq-local window-size-fixed t) (when - (fboundp 'window-preserve-size) + (fboundp 'window-preserve-size) (window-preserve-size win nil t)))) (defun single-header-show (buf) @@ -141,8 +155,6 @@ arg, dismiss all the notifications." (defun single-header-make () "Create the header and show it." - (interactive) - (let ((registered (or (equal 'single-header--register-notif-change ednc-notification-presentation-functions ) @@ -151,56 +163,55 @@ arg, dismiss all the notifications." 'single-header--register-notif-change))))) (unless registered (if (listp ednc-notification-presentation-functions) - (push 'single-header--register-notif-change ednc-notification-presentation-functions) - (list 'single-header--register-notif-change ednc-notification-presentation-functions)))) + (push 'single-header--register-notif-change + ednc-notification-presentation-functions) + (list 'single-header--register-notif-change + ednc-notification-presentation-functions)))) (unless (buffer-live-p single-header--current-header-buffer) (let ((buf (generate-new-buffer "*header*"))) (single-header-init-buffer buf) (setq single-header--current-header-buffer buf) (single-header-show buf))) - (unless (timerp single-header--timer) - (setq single-header--timer (run-with-timer 0 single-header-update-increment 'single-header-update)))) + (add-hook 'post-command-hook #'single-header-update)) (defun single-header-delete () "Remove an existing header buffer." - (interactive) (let ((reg-list (and (listp ednc-notification-presentation-functions) (-contains? ednc-notification-presentation-functions 'single-header--register-notif-change))) (reg-equal (or (equal 'single-header--register-notif-change - ednc-notification-presentation-functions ) - ))) + ednc-notification-presentation-functions)))) (when reg-list (delete 'single-header--register-notif-change ednc-notification-presentation-functions)) (when reg-equal (setq ednc-notification-presentation-functions 'ednc--update-log-buffer))) - - (when (timerp single-header--timer) - (cancel-timer single-header--timer) - (setq single-header--timer nil)) + (remove-hook 'post-command-hook 'single-header-update) (when (buffer-live-p single-header--current-header-buffer) (kill-buffer single-header--current-header-buffer))) -(defun single-header-update () +(defun single-header-update (&optional force) "Update the contents of the header line by calling `single-header-format' with the header buffer current and empty." - (when (buffer-live-p single-header--current-header-buffer) - (with-current-buffer single-header--current-header-buffer - (erase-buffer) - (single-header-format)))) + (let ((cur-time (time-convert (current-time) 'integer)) + (next-time (time-add single-header--last-update-time + single-header-update-increment))) + (when (or force (time-less-p next-time cur-time)) + (with-current-buffer single-header--current-header-buffer + (erase-buffer) + (single-header-format)) + (setq single-header--last-update-time cur-time)))) (define-minor-mode single-header-mode "Global minor mode to enable a single info line at the top of each frame." + :group 'single-header :global t :init-value nil - ;; :keymap '(("s-l d" . 'single-header-dismiss) - ;; ("s-l t" . 'single-header-mode)) :interactive t (if (not single-header-mode) (single-header-delete) (single-header-make))) (provide 'single-header) - +;;; single-header.el ends here -- cgit v1.2.3