;; battery.jl --- Show ACPI battery status in window titles
;;
;; Author: Mark Triggs <mst@dishevelled.net>
;;
;; Description: I wrote this because I thought it would be nice to be able to
;; easily see the battery status. Then I discovered that rich-title.jl does
;; this and more. Oh well.

(require 'with-open-file)
(require 'timers)

(defvar *acpi-battery-dir* "/proc/acpi/battery/BAT%d/")

(defvar *battery-update-delay* 30
  "The number of seconds between battery checks")

(defun battery-max-capacity (n)
  "Return the maximum capcity of battery N"
  (with-open-file (info (format nil "%s/info"
                                (format nil *battery-dir* n)) 'read)
    (do ((line (read-line info) (read-line info)))
        ((string-match "^last full capacity" line)
         (string->number (nth 3 (string-split " +" line)))))))


(defun battery-remaining-capacity (n)
  "Return the remaining capacity of battery N"
  (with-open-file (state (format nil "%s/state"
                                 (format nil *battery-dir* n)) 'read)
    (do ((line (read-line state) (read-line state)))
        ((string-match "^remaining capacity" line)
         (string->number (nth 2 (string-split " +" line)))))))

(defun battery-level (&optional (n 1))
  "Return remaining percentage capacity of battery N"
  (if (file-exists-p (format nil *acpi-battery-dir* n))
      (let ((level (exact->inexact (* (/ (battery-remaining-capacity n)
                                         (battery-max-capacity n))
                                      100))))
        (if (> level 100)
            100
          level))
    nil))


(defun add-battery-to-window-title (w)
  (set-window-frame
   w
   (mapcar (lambda (elt)
             (mapcar (lambda (x)
                       (if (eq (car x) 'text)
                           (cons 'text
                                 (lambda ()
                                   (format nil "%s [b: %.4d%%]"
                                           ((cdr x) w)
                                           *battery*)))
                         x))
                     elt))
           (window-frame w))))

(defun run-battery-timer ()
  (make-timer (lambda (timer)
                (setq *battery* (battery-level))
                (when (input-focus)
                  (refresh-window (input-focus)))
                (run-battery-timer))
              *battery-update-delay*))


(defvar *battery* (battery-level) "The current battery level")

(add-hook 'after-add-window-hook add-battery-to-window-title)

(run-battery-timer)
