blob: 2713c5b6c139f37668a2ae598dbc53bd91fc3cff (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
(require 'ednc)
(require 'battery)
(require 's)
(require 'dash)
;; not toggled with the mode to prevent user from having to restart
;; applications producing notifs.
(when (equal window-system 'x)
(ednc-mode 1))
;; testing
;; (require 'notifications)
;; (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."
)
(defun single-header--with-face (str &rest face-plist)
"Convenience wrapper for `add-face-text-property'."
(add-face-text-property 0 (length str) face-plist t str)
str)
(defun single-header--register-notif-change (old new)
"Function to hook `ednc-notification-presentation-functions'."
(when new
(push new single-header--active-notifs))
(when (and old
(member old single-header--active-notifs))
(setq single-header--active-notifs
(remove old single-header--active-notifs))))
(defun single-header--make-notif-string ()
"Produce a string representation of the active notifications."
(mapconcat (lambda (e)
(format "[%s | %s | %s] "
(s-truncate 8 (ednc-notification-app-name e))
(s-truncate 8 (ednc-notification-summary e))
(s-truncate 20 (ednc-notification-body e)))
)
(ednc-notifications)))
(defun single-header-dismiss (num)
"Dismiss the most recent notification from the header line. With a prefix
arg, dismiss all the notifications."
(interactive "p")
(cond ((and (natnump num) (>= num 4))
(mapc 'ednc-dismiss-notification (ednc-notifications)))
(t
(let ((notifs (ednc-notifications)))
(when notifs
(ednc-dismiss-notification (car notifs))))))
(single-header-update))
(defun single-header-format ()
"Evaluated in the header buffer when empty to fill the buffer."
(let* ((win (get-buffer-window (current-buffer)))
(win-width (window-max-chars-per-line win 'single-header))
(info (single-header--make-header-info-string))
(info-width (string-width info))
(notifs (s-truncate (- win-width info-width 2)
(single-header--make-notif-string)))
(notifs-width (string-width notifs))
(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))
(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
(single-header--with-face (battery-format "[%b%p%%] " (and battery-status-function (funcall battery-status-function)))
:weight 'bold)
(single-header--with-face (let* ((mi (memory-info))
(tm (float (car mi)))
(fm (float (cadr mi)))
(ts (float (caddr mi)))
(fs (float (cadddr mi))))
(format "{%.2f %.2f} " (- 1 (/ fm tm)) (- 1 (/ fs ts))))
:foreground "#00ced1")
(single-header--with-face (format "<%03.2f> " (car (load-average 1)))
:foreground "#da70d6")
(format-time-string "%a, %b %+4Y-%0m-%0d ")
(single-header--with-face (format-time-string "%R")
:weight 'bold)
)))
(single-header--with-face str 'single-header)))
(defun single-header-init-buffer (buf)
(with-current-buffer buf
(insert "header test")
(jit-lock-mode nil)
(font-lock-mode -1)
(buffer-disable-undo)
(setq-local mode-line-format nil)
(setq-local header-line-format nil)
(setq-local cursor-type nil)
(setq-local cursor-in-non-selected-windows nil)
(setq-local overflow-newline-into-fringe nil)
(setq-local word-wrap nil)
(setq-local show-trailing-whitespace nil)))
(defun single-header-init-window (win)
(with-selected-window win
(set-window-dedicated-p win t)
(set-window-parameter win 'no-other-window t)
(set-window-parameter win 'no-delete-other-windows t)
(set-window-margins win 0 0)
(set-window-fringes win 0 0)
(set-window-scroll-bars win 0 nil 0 nil)
(setq-local window-min-height 1)
(setq-local window-safe-min-height 1)
(let
(window-size-fixed)
(fit-window-to-buffer win 1))
(setq-local window-size-fixed t)
(when
(fboundp 'window-preserve-size)
(window-preserve-size win nil t))))
(defun single-header-show (buf)
"Show the header, making it if necessary."
(if (buffer-live-p buf)
(let ((win (display-buffer-in-side-window buf '((side . top)
(slot . -100)))))
(single-header-init-window win))
(single-header-make)))
(defun single-header-make ()
"Create the header and show it."
(interactive)
(let ((registered
(or (equal 'single-header--register-notif-change
ednc-notification-presentation-functions )
(and (listp ednc-notification-presentation-functions)
(-contains? ednc-notification-presentation-functions
'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))))
(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))))
(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 )
)))
(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))
(when (buffer-live-p single-header--current-header-buffer)
(kill-buffer single-header--current-header-buffer)))
(defun single-header-update ()
"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))))
(define-minor-mode single-header-mode
"Global minor mode to enable a single info line at the top of each frame."
: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)
|