1 ;;; gnus-picon.el --- displaying pretty icons in Gnus
2 ;; Copyright (C) 1996 Free Software Foundation, Inc.
4 ;; Author: Wes Hardaker <hardaker@ece.ucdavis.edu>
5 ;; Keywords: news xpm annotation glyph faces
7 ;; This file is part of GNU Emacs.
9 ;; GNU Emacs is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; GNU Emacs is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
27 ;; - You must have XEmacs (19.12 or above I think) to use this.
28 ;; - Read the variable descriptions below.
32 ;; 1) display the icons in its own buffer:
34 ;; (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
35 ;; (add-hook 'gnus-summary-prepare-hook 'gnus-group-display-picons t)
36 ;; (setq gnus-picons-display-where 'picons)
38 ;; Then add the picons buffer to your display configuration:
39 ;; The picons buffer needs to be at least 48 pixels high,
40 ;; which for me is 5 lines:
42 ;; (gnus-add-configuration
43 ;; '(article (vertical 1.0
46 ;; (summary .25 point)
49 ;; (gnus-add-configuration
50 ;; '(summary (vertical 1.0 (group 6)
52 ;; (summary 1.0 point))))
54 ;; 2) display the icons in the summary buffer
56 ;; (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
57 ;; (add-hook 'gnus-summary-prepare-hook 'gnus-group-display-picons t)
58 ;; (setq gnus-picons-display-where 'summary)
60 ;; 3) display the icons in the article buffer
62 ;; (add-hook 'gnus-article-display-hook 'gnus-article-display-picons t)
63 ;; (add-hook 'gnus-article-prepare-hook 'gnus-group-display-picons t)
64 ;; (setq gnus-picons-display-where 'article)
68 ;; - I'm not even close to being a lisp expert.
69 ;; - The 't' (append) flag MUST be in the add-hook line
72 ;; - Remove the TODO section in the headers.
79 (require 'annotations)
81 (defvar gnus-picons-buffer "*Icon Buffer*"
82 "Buffer name to display the icons in if gnus-picons-display-where is 'picons.")
84 (defvar gnus-picons-display-where 'picons
85 "Where to display the group and article icons.")
87 (defvar gnus-picons-database "/usr/local/faces"
88 "Defines the location of the faces database.
89 For information on obtaining this database of pretty pictures, please
90 see http://www.cs.indiana.edu/picons/ftp/index.html" )
92 (defvar gnus-picons-news-directory "news"
93 "Sub-directory of the faces database containing the icons for newsgroups."
96 (defvar gnus-picons-user-directories '("local" "users" "usenix" "misc/MISC")
97 "List of directories to search for user faces."
100 (defvar gnus-picons-domain-directories '("domains")
101 "List of directories to search for domain faces.
102 Some people may want to add \"unknown\" to this list."
105 (defvar gnus-picons-x-face-file-name
106 (format "/tmp/picon-xface.%s.xbm" (user-login-name))
107 "The name of the file in which to store the converted X-face header.")
109 (defvar gnus-picons-convert-x-face (format "{ echo '/* Width=48, Height=48 */'; uncompface; } | icontopbm | pbmtoxbm > %s" gnus-picons-x-face-file-name)
110 "Command to convert the x-face header into a xbm file."
113 (defvar gnus-picons-file-suffixes
115 (let ((types (list "xbm")))
116 (when (featurep 'gif)
118 (when (featurep 'xpm)
121 "List of suffixes on picon file names to try.")
123 (defvar gnus-picons-display-article-move-p t
124 "*Whether to move point to first empty line when displaying picons.
125 This has only an effect if `gnus-picons-display-where' hs value article.")
127 ;;; Internal variables.
129 (defvar gnus-group-annotations nil)
130 (defvar gnus-article-annotations nil)
131 (defvar gnus-x-face-annotations nil)
133 (defun gnus-picons-remove (plist)
134 (let ((listitem (car plist)))
135 (while (setq listitem (car plist))
136 (if (annotationp listitem)
137 (delete-annotation listitem))
138 (setq plist (cdr plist))))
141 (defun gnus-picons-remove-all ()
142 "Removes all picons from the Gnus display(s)."
144 (gnus-picons-remove gnus-article-annotations)
145 (gnus-picons-remove gnus-group-annotations)
146 (gnus-picons-remove gnus-x-face-annotations)
147 (setq gnus-article-annotations nil
148 gnus-group-annotations nil
149 gnus-x-face-annotations nil)
150 (if (bufferp gnus-picons-buffer)
151 (kill-buffer gnus-picons-buffer))
154 (defun gnus-get-buffer-name (variable)
155 "Returns the buffer name associated with the contents of a variable."
156 (cond ((symbolp variable)
157 (let ((newvar (cdr (assq variable gnus-window-to-buffer))))
158 (cond ((symbolp newvar)
159 (symbol-value newvar))
160 ((stringp newvar) newvar))))
164 (defun gnus-picons-article-display-x-face ()
165 "Display the x-face header bitmap in the 'gnus-picons-display-where buffer."
166 ;; delete any old ones.
167 (gnus-picons-remove gnus-x-face-annotations)
168 (setq gnus-x-face-annotations nil)
169 ;; display the new one.
170 (let ((gnus-article-x-face-command 'gnus-picons-display-x-face))
171 (gnus-article-display-x-face)))
173 (defun gnus-picons-display-x-face (beg end)
174 "Function to display the x-face header in the picons window.
175 To use: (setq gnus-article-x-face-command 'gnus-picons-display-x-face)"
177 ;; convert the x-face header to a .xbm file
178 (let ((process-connection-type nil)
180 (process-kill-without-query
181 (setq process (start-process
182 "gnus-x-face" nil shell-file-name shell-command-switch
183 gnus-picons-convert-x-face)))
184 (process-send-region "gnus-x-face" beg end)
185 (process-send-eof "gnus-x-face")
187 (while (not (equal (process-status process) 'exit))
191 (set-buffer (get-buffer-create (gnus-get-buffer-name
192 gnus-picons-display-where)))
193 (gnus-add-current-to-buffer-list)
194 (goto-char (point-min))
195 (let (buffer-read-only)
197 (push (make-annotation "\n" (point) 'text)
198 gnus-x-face-annotations))
199 ;; append the annotation to gnus-article-annotations for deletion.
200 (setq gnus-x-face-annotations
202 (gnus-picons-try-to-find-face gnus-picons-x-face-file-name t)
203 gnus-x-face-annotations)))
204 ;; delete the tmp file
205 (delete-file gnus-picons-x-face-file-name)))
207 (defun gnus-article-display-picons ()
208 "Display faces for an author and his/her domain in gnus-picons-display-where."
210 (let (from at-idx databases)
211 (when (and (featurep 'xpm)
212 (or (not (fboundp 'device-type)) (equal (device-type) 'x))
213 (setq from (mail-fetch-field "from"))
214 (setq from (downcase (or (cadr (mail-extract-address-components
217 (or (setq at-idx (string-match "@" from))
218 (setq at-idx (length from))))
220 (let ((username (substring from 0 at-idx))
221 (addrs (if (eq at-idx (length from))
222 (if gnus-local-domain
223 (nreverse (message-tokenize-header
224 gnus-local-domain "."))
226 (nreverse (message-tokenize-header
227 (substring from (1+ at-idx)) ".")))))
228 (set-buffer (get-buffer-create
229 (gnus-get-buffer-name gnus-picons-display-where)))
230 (gnus-add-current-to-buffer-list)
231 (goto-char (point-min))
232 (if (and (eq gnus-picons-display-where 'article)
233 gnus-picons-display-article-move-p)
234 (when (search-forward "\n\n" nil t)
237 (push (make-annotation "\n" (point) 'text)
238 gnus-article-annotations)))
240 (gnus-picons-remove gnus-article-annotations)
241 (setq gnus-article-annotations nil)
243 (setq databases (append gnus-picons-user-directories
244 gnus-picons-domain-directories))
246 (setq gnus-article-annotations
247 (nconc (gnus-picons-insert-face-if-exists
251 (gnus-picons-insert-face-if-exists
254 (downcase username) t)
255 gnus-article-annotations))
256 (setq databases (cdr databases)))
257 (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all))))))
259 (defun gnus-group-display-picons ()
260 "Display icons for the group in the gnus-picons-display-where buffer."
262 (when (and (featurep 'xpm)
263 (or (not (fboundp 'device-type)) (equal (device-type) 'x)))
265 (set-buffer (get-buffer-create
266 (gnus-get-buffer-name gnus-picons-display-where)))
267 (gnus-add-current-to-buffer-list)
268 (goto-char (point-min))
269 (if (and (eq gnus-picons-display-where 'article)
270 gnus-picons-display-article-move-p)
271 (if (search-forward "\n\n" nil t)
274 (push (make-annotation "\n" (point) 'text)
275 gnus-group-annotations)))
277 ((listp gnus-group-annotations)
278 (mapc #'(lambda (ext) (if (extent-live-p ext) (delete-annotation ext)))
279 gnus-group-annotations)
280 (setq gnus-group-annotations nil))
281 ((annotationp gnus-group-annotations)
282 (delete-annotation gnus-group-annotations)
283 (setq gnus-group-annotations nil)))
284 (gnus-picons-remove gnus-group-annotations)
285 (setq gnus-group-annotations
286 (gnus-picons-insert-face-if-exists
287 gnus-picons-news-directory
288 (message-tokenize-header gnus-newsgroup-name ".")
290 (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all))))
292 (defsubst gnus-picons-try-suffixes (file)
293 (let ((suffixes gnus-picons-file-suffixes)
296 (not (file-exists-p (setq f (concat file (pop suffixes))))))
300 (defun gnus-picons-insert-face-if-exists (database addrs filename &optional
302 "Inserts a face at point if I can find one"
303 ;; '(gnus-picons-insert-face-if-exists
304 ; "Database" '("edu" "indiana" "cs") "Name")
306 ;; 1. edu/indiana/cs/Name
307 ;; 2. edu/indiana/Name
309 ;; '(gnus-picons-insert-face-if-exists
310 ;; "Database/MISC" '("edu" "indiana" "cs") "Name")
313 ;; The special treatment of MISC doesn't conform with the conventions for
314 ;; picon databases, but otherwise we would always see the MISC/unknown face.
315 (let ((bar (and (not nobar-p)
316 (annotations-in-region
317 (point) (min (point-max) (1+ (point)))
319 (path (concat (file-name-as-directory gnus-picons-database)
321 picons found bar-ann)
322 (if (string-match "/MISC" database)
325 (file-accessible-directory-p path))
326 (setq path (concat path (pop addrs) "/"))
328 (gnus-picons-try-suffixes
329 (concat path filename "/face.")))
331 (setq bar-ann (gnus-picons-try-to-find-face
332 (concat gnus-xmas-glyph-directory "bar.xbm")))
334 (setq picons (nconc picons bar-ann))
336 (setq picons (nconc (gnus-picons-try-to-find-face found)
340 (defvar gnus-picons-glyph-alist nil)
342 (defun gnus-picons-try-to-find-face (path &optional xface-p)
343 "If PATH exists, display it as a bitmap. Returns t if succedded."
344 (let ((glyph (and (not xface-p)
345 (cdr (assoc path gnus-picons-glyph-alist)))))
346 (when (or glyph (file-exists-p path))
348 (setq glyph (make-glyph path))
350 (push (cons path glyph) gnus-picons-glyph-alist))
351 (set-glyph-face glyph 'default))
353 (list (make-annotation glyph (point) 'text))
354 (when (eq major-mode 'gnus-article-mode)
355 (list (make-annotation " " (point) 'text)))))))
357 (defun gnus-picons-reverse-domain-path (str)
359 (mapconcat 'downcase (nreverse (message-tokenize-header str "/")) "/"))
361 (gnus-add-shutdown 'gnus-picons-close 'gnus)
363 (defun gnus-picons-close ()
364 "Shut down the picons."
365 (setq gnus-picons-glyph-alist nil))
367 (provide 'gnus-picon)
369 ;;; gnus-picon.el ends here