;;; gnus-picon.el --- displaying pretty icons in Gnus
-;; Copyright (C) 1996,97 Free Software Foundation, Inc.
+;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
;; Author: Wes Hardaker <hardaker@ece.ucdavis.edu>
;; Keywords: news xpm annotation glyph faces
:group 'gnus-visual)
(defcustom gnus-picons-display-where 'picons
- "*Where to display the group and article icons.
+ "Where to display the group and article icons.
Legal values are `article' and `picons'."
:type '(choice symbol string)
:group 'picons)
(defcustom gnus-picons-has-modeline-p t
- "*Wether the picons window should have a modeline.
+ "*Whether the picons window should have a modeline.
This is only useful if `gnus-picons-display-where' is `picons'."
:type 'boolean
:group 'picons)
:group 'picons)
(defcustom gnus-picons-news-directories '("news")
- "*Sub-directory of the faces database containing the icons for newsgroups."
+ "*List of directories to search for newsgroups faces."
:type '(repeat string)
:group 'picons)
(define-obsolete-variable-alias 'gnus-picons-news-directory
:type '(repeat string)
:group 'picons)
-(defcustom gnus-picons-display-article-move-p t
+(defcustom gnus-picons-display-article-move-p nil
"*Whether to move point to first empty line when displaying picons.
This has only an effect if `gnus-picons-display-where' has value `article'."
:type 'boolean
:group 'picons)
(defface gnus-picons-xbm-face '((t (:foreground "black" :background "white")))
- "Face to show X face"
+ "Face to show xbm picons in."
:group 'picons)
;;; Internal variables:
"Picons file names cache.
List of pairs (KEY . NAME) where KEY is (USER HOST DBS) and NAME is an URL.")
-(defvar gnus-group-annotations nil
- "List of annotations added/removed when selecting/exiting a group")
-(defvar gnus-article-annotations nil
- "List of annotations added/removed when selecting an article")
-(defvar gnus-x-face-annotations nil
- "List of annotations added/removed when selecting an article with an X-Face.")
-
(defvar gnus-picons-jobs-alist nil
"List of jobs that still need be done.
This is a list of (SYM-ANN TAG ARGS...) where SYM-ANN three annotations list,
;;; Functions:
-(defun gnus-picons-remove (symbol)
- "Remove all annotations in variable named SYMBOL.
-This function is careful to set it to nil before removing anything so that
-asynchronous process don't get crazy."
- (setq gnus-picons-jobs-alist (remassq symbol gnus-picons-jobs-alist))
- ;; notify running job that it may have been preempted
- (if (eq (car gnus-picons-job-already-running) symbol)
- (setq gnus-picons-job-already-running t))
- ;; clear all annotations
- (mapc (function (lambda (item)
- (if (annotationp item)
- (delete-annotation item))))
- (prog1 (symbol-value symbol)
- (set symbol nil))))
-
(defun gnus-picons-remove-all ()
"Removes all picons from the Gnus display(s)."
(interactive)
- (gnus-picons-remove 'gnus-article-annotations)
- (gnus-picons-remove 'gnus-group-annotations)
- (gnus-picons-remove 'gnus-x-face-annotations))
+ (map-extents (function (lambda (ext unused) (delete-annotation ext) nil))
+ nil nil nil nil nil 'gnus-picon)
+ (setq gnus-picons-jobs-alist '())
+ ;; notify running job that it may have been preempted
+ (if (and (listp gnus-picons-job-already-running)
+ gnus-picons-job-already-running)
+ (setq gnus-picons-job-already-running t)))
(defun gnus-get-buffer-name (variable)
"Returns the buffer name associated with the contents of a variable."
- (cond ((symbolp variable) (let ((newvar (cdr (assq variable
- gnus-window-to-buffer))))
- (cond ((symbolp newvar)
- (symbol-value newvar))
- ((stringp newvar) newvar))))
- ((stringp variable) variable)))
+ (let ((buf (gnus-get-buffer-create (gnus-window-to-buffer-helper
+ (cdr
+ (assq variable gnus-window-to-buffer))))))
+ (and buf
+ (buffer-name buf))))
+
+(defun gnus-picons-buffer-name ()
+ (cond ((or (stringp gnus-picons-display-where)
+ (bufferp gnus-picons-display-where))
+ gnus-picons-display-where)
+ ((eq gnus-picons-display-where 'picons)
+ (if gnus-single-article-buffer
+ "*Picons*"
+ (concat "*Picons " gnus-newsgroup-name "*")))
+ (t
+ (gnus-get-buffer-name gnus-picons-display-where))))
+
+(defun gnus-picons-kill-buffer ()
+ (let ((buf (get-buffer (gnus-picons-buffer-name))))
+ (if (buffer-live-p buf)
+ (kill-buffer buf))))
+
+(defun gnus-picons-setup-buffer ()
+ (let ((name (gnus-picons-buffer-name)))
+ (save-excursion
+ (if (get-buffer name)
+ (set-buffer name)
+ (set-buffer (gnus-get-buffer-create name))
+ (buffer-disable-undo)
+ (setq buffer-read-only t)
+ (add-hook 'gnus-summary-prepare-exit-hook 'gnus-picons-kill-buffer))
+ (current-buffer))))
(defun gnus-picons-set-buffer ()
- (set-buffer
- (get-buffer-create (gnus-get-buffer-name gnus-picons-display-where)))
- (gnus-add-current-to-buffer-list)
+ (set-buffer (gnus-picons-setup-buffer))
(goto-char (point-min))
(if (and (eq gnus-picons-display-where 'article)
gnus-picons-display-article-move-p)
(list (list (current-buffer)
(cons nil gnus-picons-has-modeline-p)))))))
-(defun gnus-picons-prepare-for-annotations (annotations)
- "Prepare picons buffer for puting annotations memorized in ANNOTATIONS.
-ANNOTATIONS should be a symbol naming a variable wich contains a list of
-annotations. Sets buffer to `gnus-picons-display-where'."
+(defun gnus-picons-prepare-for-annotations ()
+ "Prepare picons buffer for putting annotations."
;; let drawing catch up
(when gnus-picons-refresh-before-display
(sit-for 0))
(gnus-picons-set-buffer)
- (gnus-picons-remove annotations))
+ (gnus-picons-remove-all))
-(defsubst gnus-picons-make-annotation (&rest args)
+(defun gnus-picons-make-annotation (&rest args)
(let ((annot (apply 'make-annotation args)))
- (set-extent-property annot 'duplicable nil)
+ (set-extent-property annot 'gnus-picon t)
+ (set-extent-property annot 'duplicable t)
annot))
(defun gnus-picons-article-display-x-face ()
"Display the x-face header bitmap in the 'gnus-picons-display-where buffer."
- ;; delete any old ones.
- ;; This is needed here because gnus-picons-display-x-face will not
- ;; be called if there is no X-Face header
- (gnus-picons-remove 'gnus-x-face-annotations)
- ;; display the new one.
(let ((gnus-article-x-face-command 'gnus-picons-display-x-face))
(gnus-article-display-x-face)))
(defun gnus-picons-x-face-sentinel (process event)
- (let* ((env (assq process gnus-picons-processes-alist))
- (annot (cdr env)))
+ (when (memq process gnus-picons-processes-alist)
(setq gnus-picons-processes-alist
- (remassq process gnus-picons-processes-alist))
- (when (annotationp annot)
- (set-annotation-glyph annot
- (make-glyph gnus-picons-x-face-file-name))
- (if (memq annot gnus-x-face-annotations)
- (delete-file gnus-picons-x-face-file-name)))))
+ (delq process gnus-picons-processes-alist))
+ (gnus-picons-set-buffer)
+ (gnus-picons-make-annotation (make-glyph gnus-picons-x-face-file-name)
+ nil 'text)
+ (when (file-exists-p gnus-picons-x-face-file-name)
+ (delete-file gnus-picons-x-face-file-name))))
(defun gnus-picons-display-x-face (beg end)
"Function to display the x-face header in the picons window.
(interactive)
(if (featurep 'xface)
;; Use builtin support
- (let ((buf (current-buffer)))
- (save-excursion
- (gnus-picons-prepare-for-annotations 'gnus-x-face-annotations)
- (setq gnus-x-face-annotations
- (cons (gnus-picons-make-annotation
- (vector 'xface
- :data (concat "X-Face: "
- (buffer-substring beg end buf)))
- nil 'text)
- gnus-x-face-annotations))))
+ (save-excursion
+ ;; Don't remove this binding, it is really needed: when
+ ;; `gnus-picons-set-buffer' changes buffer (like when it is
+ ;; set to display picons outside of the article buffer), BEG
+ ;; and END still refer the buffer current now !
+ (let ((buf (current-buffer)))
+ (gnus-picons-set-buffer)
+ (gnus-picons-make-annotation
+ (vector 'xface
+ :data (concat "X-Face: " (buffer-substring beg end buf)))
+ nil 'text nil nil nil t)))
;; convert the x-face header to a .xbm file
(let* ((process-connection-type nil)
- (annot (save-excursion
- (gnus-picons-prepare-for-annotations
- 'gnus-x-face-annotations)
- (gnus-picons-make-annotation nil nil 'text)))
(process (start-process-shell-command "gnus-x-face" nil
gnus-picons-convert-x-face)))
- (push annot gnus-x-face-annotations)
- (push (cons process annot) gnus-picons-processes-alist)
+ (push process gnus-picons-processes-alist)
(process-kill-without-query process)
(set-process-sentinel process 'gnus-picons-x-face-sentinel)
(process-send-region process beg end)
(when (and (featurep 'xpm)
(or (not (fboundp 'device-type)) (equal (device-type) 'x))
(setq from (mail-fetch-field "from"))
- (setq from (downcase (or (cadr (mail-extract-address-components
- from))
+ (setq from (downcase (or (cadr
+ (funcall gnus-extract-address-components
+ from))
"")))
(or (setq at-idx (string-match "@" from))
(setq at-idx (length from))))
(message-tokenize-header gnus-local-domain "."))
(message-tokenize-header (substring from (1+ at-idx))
"."))))
- (gnus-picons-prepare-for-annotations 'gnus-article-annotations)
- ;; if display in article buffer, the group annotations
- ;; wrongly placed. Move them here
- (if (eq gnus-picons-display-where 'article)
- (dolist (ext gnus-group-annotations)
- (set-extent-endpoints ext (point) (point))))
+ (gnus-picons-prepare-for-annotations)
+ (gnus-group-display-picons)
+ (unless gnus-picons-display-article-move-p
+ (save-restriction
+ (let ((buffer-read-only nil))
+ (when (re-search-forward "^From: " nil t)
+ (narrow-to-region (point) (gnus-point-at-eol))
+ (when (search-forward from nil t)
+ (gnus-put-text-property
+ (match-beginning 0) (match-end 0)
+ 'invisible t))))))
(if (null gnus-picons-piconsearch-url)
- (setq gnus-article-annotations
- (nconc gnus-article-annotations
- (gnus-picons-display-pairs
- (gnus-picons-lookup-pairs
- addrs gnus-picons-domain-directories)
- gnus-picons-display-as-address
- "." t)
- (if (and gnus-picons-display-as-address addrs)
- (list (gnus-picons-make-annotation
- [string :data "@"] nil
- 'text nil nil nil t)))
- (gnus-picons-display-picon-or-name
- (gnus-picons-lookup-user username addrs)
- username t)))
+ (progn
+ (gnus-picons-display-pairs (gnus-picons-lookup-pairs
+ addrs
+ gnus-picons-domain-directories)
+ gnus-picons-display-as-address
+ "." t)
+ (if (and gnus-picons-display-as-address addrs)
+ (gnus-picons-make-annotation
+ [string :data "@"] nil 'text nil nil nil t))
+ (gnus-picons-display-picon-or-name
+ (gnus-picons-lookup-user username addrs)
+ username t))
(push (list 'gnus-article-annotations 'search username addrs
gnus-picons-domain-directories t)
gnus-picons-jobs-alist)
- (gnus-picons-next-job))
-
- (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all))))))
+ (gnus-picons-next-job)))))))
(defun gnus-group-display-picons ()
- "Display icons for the group in the gnus-picons-display-where buffer."
+ "Display icons for the group in the `gnus-picons-display-where' buffer."
(interactive)
(when (and (featurep 'xpm)
(or (not (fboundp 'device-type)) (equal (device-type) 'x))
(or (null gnus-picons-group-excluded-groups)
(not (string-match gnus-picons-group-excluded-groups
gnus-newsgroup-name))))
- (save-excursion
- (gnus-picons-prepare-for-annotations 'gnus-group-annotations)
- (if (null gnus-picons-piconsearch-url)
- (setq gnus-group-annotations
- (gnus-picons-display-pairs
- (gnus-picons-lookup-pairs
- (reverse (message-tokenize-header
- (gnus-group-real-name gnus-newsgroup-name)
- "."))
- gnus-picons-news-directories)
- t "."))
- (push (list 'gnus-group-annotations 'search nil
- (message-tokenize-header
- (gnus-group-real-name gnus-newsgroup-name) ".")
- (if (listp gnus-picons-news-directories)
- gnus-picons-news-directories
- (list gnus-picons-news-directories))
- nil)
- gnus-picons-jobs-alist)
- (gnus-picons-next-job))
-
- (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all))))
-
-(defsubst gnus-picons-lookup-internal (addrs dir)
+ (let* ((newsgroups (mail-fetch-field "newsgroups"))
+ (groups
+ (if (or gnus-picons-display-article-move-p
+ (not newsgroups))(mail-fetch-field "newsgroups")
+ (list (gnus-group-real-name gnus-newsgroup-name))
+ (split-string newsgroups ",")))
+ group)
+ (save-excursion
+ (gnus-picons-prepare-for-annotations)
+ (while (setq group (pop groups))
+ (unless gnus-picons-display-article-move-p
+ (save-restriction
+ (let ((buffer-read-only nil))
+ (goto-char (point-min))
+ (when (re-search-forward "^Newsgroups:" nil t)
+ (narrow-to-region (point) (gnus-point-at-eol))
+ (when (search-forward group nil t)
+ (gnus-put-text-property
+ (match-beginning 0) (match-end 0)
+ 'invisible t))))))
+ (if (null gnus-picons-piconsearch-url)
+ (gnus-picons-display-pairs
+ (gnus-picons-lookup-pairs
+ (reverse (split-string group "\\."))
+ gnus-picons-news-directories)
+ t ".")
+ (push (list 'gnus-group-annotations 'search nil
+ (split-string group "\\.")
+ (if (listp gnus-picons-news-directories)
+ gnus-picons-news-directories
+ (list gnus-picons-news-directories))
+ nil)
+ gnus-picons-jobs-alist)
+ (gnus-picons-next-job))
+
+ (add-hook 'gnus-summary-exit-hook 'gnus-picons-remove-all))))))
+
+(defun gnus-picons-lookup-internal (addrs dir)
(setq dir (expand-file-name dir gnus-picons-database))
(gnus-picons-try-face (dolist (part (reverse addrs) dir)
(setq dir (expand-file-name part dir)))))
"Display picons in list PAIRS."
(let ((domain-p (and gnus-picons-display-as-address dot-p))
pair picons)
- (when (and bar-p domain-p right-p)
+ (when (and bar-p domain-p right-p
+ gnus-picons-display-article-move-p)
(setq picons (gnus-picons-display-glyph
(let ((gnus-picons-file-suffixes '("xbm")))
(gnus-picons-try-face
glyph))
(defun gnus-picons-display-glyph (glyph &optional part rightp)
+ (set-glyph-baseline glyph 70)
(let ((new (gnus-picons-make-annotation
glyph (point) 'text nil nil nil rightp)))
(when (and part gnus-picons-display-as-address)
'text nil nil nil rightp))))))
(defun gnus-picons-action-toggle (data)
- "Toggle annotation"
+ "Toggle annotation."
(interactive "e")
(let* ((annot (car data))
(glyph (annotation-glyph annot)))
(set-annotation-data annot (cons annot glyph))))
(defun gnus-picons-clear-cache ()
- "Clear the picons cache"
+ "Clear the picons cache."
(interactive)
(setq gnus-picons-glyph-alist nil
gnus-picons-url-alist nil))
(defun gnus-picons-network-display-internal (sym-ann glyph part right-p)
(gnus-picons-set-buffer)
- (set sym-ann (nconc (symbol-value sym-ann)
- (gnus-picons-display-picon-or-name glyph part right-p)))
+ (gnus-picons-display-picon-or-name glyph part right-p)
(gnus-picons-next-job-internal))
(defun gnus-picons-network-display-callback (url part sym-ann right-p)
(prog1 (gnus-picons-parse-filenames)
(kill-buffer (current-buffer)))))
+;; Initiate a query on the picon database
(defun gnus-picons-network-search (user addrs dbs sym-ann right-p)
(let* ((host (mapconcat 'identity addrs "."))
(key (list (or user "unknown") host (if user
(cond ((stringp tag);; (SYM-ANN "..." RIGHT-P)
(gnus-picons-network-display-internal sym-ann nil tag
(pop job)))
- ((eq 'bar tag)
+ ((and (eq 'bar tag)
+ gnus-picons-display-article-move-p)
(gnus-picons-network-display-internal
sym-ann
(let ((gnus-picons-file-suffixes '("xbm")))
(error "Unknown picon job tag %s" tag)))))))
(defun gnus-picons-next-job ()
- "Start processing the job queue if it is not in progress"
+ "Start processing the job queue if it is not in progress."
(unless gnus-picons-job-already-running
(gnus-picons-next-job-internal)))