(gnus-xmas-update-toolbars): New function.
[gnus] / lisp / gnus-xmas.el
1 ;;; gnus-xmas.el --- Gnus functions for XEmacs
2
3 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
4 ;;        Free Software Foundation, Inc.
5
6 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
7 ;; Keywords: news
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
25
26 ;;; Commentary:
27
28 ;;; Code:
29
30 (eval-when-compile
31   (autoload 'gnus-active "gnus" nil nil 'macro)
32   (autoload 'gnus-group-entry "gnus" nil nil 'macro)
33   (autoload 'gnus-info-level "gnus" nil nil 'macro)
34   (autoload 'gnus-info-marks "gnus" nil nil 'macro)
35   (autoload 'gnus-info-method "gnus" nil nil 'macro)
36   (autoload 'gnus-info-score "gnus" nil nil 'macro))
37
38 (require 'text-props)
39 (defvar menu-bar-mode (featurep 'menubar))
40 (require 'messagexmas)
41 (require 'wid-edit)
42 (require 'timer-funcs)
43
44 (defgroup gnus-xmas nil
45   "XEmacsoid support for Gnus"
46   :group 'gnus)
47
48 (defcustom gnus-xmas-glyph-directory nil
49   "Directory where Gnus logos and icons are located.
50 If this variable is nil, Gnus will try to locate the directory
51 automatically."
52   :type '(choice (const :tag "autodetect" nil)
53                  directory)
54   :group 'gnus-xmas)
55
56 (unless gnus-xmas-glyph-directory
57   (unless (setq gnus-xmas-glyph-directory
58                 (message-xmas-find-glyph-directory "gnus"))
59     (error "Can't find glyph directory. \
60 Possibly the `etc' directory has not been installed.")))
61
62 ;;; Internal variables.
63
64 ;; Don't warn about these undefined variables.
65
66 ;;defined in gnus.el
67 (defvar gnus-active-hashtb)
68 (defvar gnus-article-buffer)
69 (defvar gnus-auto-center-summary)
70 (defvar gnus-current-headers)
71 (defvar gnus-level-killed)
72 (defvar gnus-level-zombie)
73 (defvar gnus-newsgroup-bookmarks)
74 (defvar gnus-newsgroup-dependencies)
75 (defvar gnus-newsgroup-selected-overlay)
76 (defvar gnus-newsrc-hashtb)
77 (defvar gnus-read-mark)
78 (defvar gnus-refer-article-method)
79 (defvar gnus-reffed-article-number)
80 (defvar gnus-unread-mark)
81 (defvar gnus-version)
82 (defvar gnus-view-pseudos)
83 (defvar gnus-view-pseudos-separately)
84 (defvar gnus-visual)
85 (defvar gnus-zombie-list)
86 ;;defined in gnus-msg.el
87 (defvar gnus-article-copy)
88 (defvar gnus-check-before-posting)
89 ;;defined in gnus-vis.el
90 (defvar gnus-article-button-face)
91 (defvar gnus-article-mouse-face)
92 (defvar gnus-summary-selected-face)
93 (defvar gnus-group-reading-menu)
94 (defvar gnus-group-group-menu)
95 (defvar gnus-group-misc-menu)
96 (defvar gnus-summary-article-menu)
97 (defvar gnus-summary-thread-menu)
98 (defvar gnus-summary-misc-menu)
99 (defvar gnus-summary-post-menu)
100 (defvar gnus-summary-kill-menu)
101 (defvar gnus-article-article-menu)
102 (defvar gnus-article-treatment-menu)
103 (defvar gnus-mouse-2)
104 (defvar standard-display-table)
105 (defvar gnus-tree-minimize-window)
106
107 (defun gnus-xmas-highlight-selected-summary ()
108   ;; Highlight selected article in summary buffer
109   (when gnus-summary-selected-face
110     (when gnus-newsgroup-selected-overlay
111       (delete-extent gnus-newsgroup-selected-overlay))
112     (setq gnus-newsgroup-selected-overlay
113           (make-extent (point-at-bol) (point-at-eol)))
114     (set-extent-face gnus-newsgroup-selected-overlay
115                      gnus-summary-selected-face)))
116
117 (defcustom gnus-xmas-force-redisplay nil
118   "*If non-nil, force a redisplay before recentering the summary buffer.
119 This is ugly, but it works around a bug in `window-displayed-height'."
120   :type 'boolean
121   :group 'gnus-xmas)
122
123 (defun gnus-xmas-switch-horizontal-scrollbar-off ()
124   (when (featurep 'scrollbar)
125     (set-specifier scrollbar-height (cons (current-buffer) 0))))
126
127 (defun gnus-xmas-summary-recenter ()
128   "\"Center\" point in the summary window.
129 If `gnus-auto-center-summary' is nil, or the article buffer isn't
130 displayed, no centering will be performed."
131   ;; Suggested by earle@mahendo.JPL.NASA.GOV (Greg Earle).
132   ;; Recenter only when requested.  Suggested by popovich@park.cs.columbia.edu.
133   ;; Force redisplay to get properly computed window height.
134   (when gnus-xmas-force-redisplay
135     (sit-for 0))
136   (when gnus-auto-center-summary
137     (let* ((height (if (fboundp 'window-displayed-height)
138                        (window-displayed-height)
139                      (- (window-height) 2)))
140            (top (cond ((< height 4) 0)
141                       ((< height 7) 1)
142                       (t (if (numberp gnus-auto-center-summary)
143                              gnus-auto-center-summary
144                            2))))
145            (bottom (save-excursion (goto-char (point-max))
146                                    (forward-line (- height))
147                                    (point)))
148            (window (get-buffer-window (current-buffer))))
149       (when (get-buffer-window gnus-article-buffer)
150         ;; Only do recentering when the article buffer is displayed,
151         ;; Set the window start to either `bottom', which is the biggest
152         ;; possible valid number, or the second line from the top,
153         ;; whichever is the least.
154         ;; NOFORCE parameter suggested by Daniel Pittman <daniel@danann.net>.
155         (set-window-start
156          window (min bottom (save-excursion (forward-line (- top)) (point)))
157          t))
158       ;; Do horizontal recentering while we're at it.
159       (when (and (get-buffer-window (current-buffer) t)
160                  (not (eq gnus-auto-center-summary 'vertical)))
161         (let ((selected (selected-window)))
162           (select-window (get-buffer-window (current-buffer) t))
163           (gnus-summary-position-point)
164           (gnus-horizontal-recenter)
165           (select-window selected))))))
166
167 (defun gnus-xmas-summary-set-display-table ()
168   ;; Setup the display table -- like `gnus-summary-setup-display-table',
169   ;; but done in an XEmacsish way.
170   (let ((table (make-display-table))
171         (i 32))
172     ;; Nix out all the control chars...
173     (while (>= (setq i (1- i)) 0)
174       (aset table i [??]))
175     ;; ... but not newline and cr, of course.  (cr is necessary for the
176     ;; selective display).
177     (aset table ?\n nil)
178     (aset table ?\r nil)
179     ;; We keep TAB as well.
180     (aset table ?\t nil)
181     ;; We nix out any glyphs over 126 below ctl-arrow.
182     (let ((i (if (integerp ctl-arrow) ctl-arrow 160)))
183       (while (>= (setq i (1- i)) 127)
184         (unless (aref table i)
185           (aset table i [??]))))
186     ;; Can't use `set-specifier' because of a bug in 19.14 and earlier
187     (add-spec-to-specifier current-display-table table (current-buffer) nil)))
188
189 (defun gnus-xmas-add-text-properties (start end props &optional object)
190   (add-text-properties start end props object)
191   (put-text-property start end 'start-closed nil object))
192
193 (defun gnus-xmas-put-text-property (start end prop value &optional object)
194   (put-text-property start end prop value object)
195   (put-text-property start end 'start-closed nil object))
196
197 (defun gnus-xmas-extent-start-open (point)
198   (map-extents (lambda (extent arg)
199                  (set-extent-property extent 'start-open t))
200                nil point (min (1+ (point)) (point-max))))
201
202 (defun gnus-xmas-article-push-button (event)
203   "Check text under the mouse pointer for a callback function.
204 If the text under the mouse pointer has a `gnus-callback' property,
205 call it with the value of the `gnus-data' text property."
206   (interactive "e")
207   (set-buffer (window-buffer (event-window event)))
208   (let* ((pos (event-closest-point event))
209          (data (get-text-property pos 'gnus-data))
210          (fun (get-text-property pos 'gnus-callback)))
211     (goto-char pos)
212     (when fun
213       (funcall fun data))))
214
215 (defun gnus-xmas-move-overlay (extent start end &optional buffer)
216   (set-extent-endpoints extent start end buffer))
217
218 (defun gnus-xmas-kill-all-overlays ()
219   "Delete all extents in the current buffer."
220   (map-extents (lambda (extent ignore)
221                  (delete-extent extent)
222                  nil)))
223
224 (defun gnus-xmas-window-top-edge (&optional window)
225   (nth 1 (window-pixel-edges window)))
226
227 (defun gnus-xmas-tree-minimize ()
228   (when (and gnus-tree-minimize-window
229              (not (one-window-p)))
230     (let* ((window-min-height 2)
231            (height (1+ (count-lines (point-min) (point-max))))
232            (min (max (1- window-min-height) height))
233            (tot (if (numberp gnus-tree-minimize-window)
234                     (min gnus-tree-minimize-window min)
235                   min))
236            (win (get-buffer-window (current-buffer)))
237            (wh (and win (1- (window-height win)))))
238       (when (and win
239                  (not (eq tot wh)))
240         (let ((selected (selected-window)))
241           (select-window win)
242           (enlarge-window (- tot wh))
243           (select-window selected))))))
244
245 ;; Select the lowest window on the frame.
246 (defun gnus-xmas-select-lowest-window ()
247   (let* ((lowest-window (selected-window))
248          (bottom-edge (car (cdr (cdr (cdr (window-pixel-edges))))))
249          (last-window (previous-window))
250          (window-search t))
251     (while window-search
252       (let* ((this-window (next-window))
253              (next-bottom-edge (car (cdr (cdr (cdr
254                                                (window-pixel-edges
255                                                 this-window)))))))
256         (when (< bottom-edge next-bottom-edge)
257           (setq bottom-edge next-bottom-edge)
258           (setq lowest-window this-window))
259
260         (select-window this-window)
261         (when (eq last-window this-window)
262           (select-window lowest-window)
263           (setq window-search nil))))))
264
265 (defmacro gnus-xmas-menu-add (type &rest menus)
266   `(gnus-xmas-menu-add-1 ',type ',menus))
267 (put 'gnus-xmas-menu-add 'lisp-indent-function 1)
268
269 (defun gnus-xmas-menu-add-1 (type menus)
270   (when (and menu-bar-mode
271              (gnus-visual-p (intern (format "%s-menu" type)) 'menu))
272     (while menus
273       (easy-menu-add (symbol-value (pop menus))))))
274
275 (defun gnus-xmas-group-menu-add ()
276   (gnus-xmas-menu-add group
277     gnus-group-reading-menu gnus-group-group-menu gnus-group-misc-menu))
278
279 (defun gnus-xmas-summary-menu-add ()
280   (gnus-xmas-menu-add summary
281     gnus-summary-misc-menu gnus-summary-kill-menu
282     gnus-summary-article-menu gnus-summary-thread-menu
283     gnus-summary-post-menu ))
284
285 (defun gnus-xmas-article-menu-add ()
286   (gnus-xmas-menu-add article
287     gnus-article-article-menu gnus-article-treatment-menu
288     gnus-article-post-menu gnus-article-commands-menu))
289
290 (defun gnus-xmas-score-menu-add ()
291   (gnus-xmas-menu-add score
292     gnus-score-menu))
293
294 (defun gnus-xmas-pick-menu-add ()
295   (gnus-xmas-menu-add pick
296     gnus-pick-menu))
297
298 (defun gnus-xmas-topic-menu-add ()
299   (gnus-xmas-menu-add topic
300     gnus-topic-menu))
301
302 (defun gnus-xmas-binary-menu-add ()
303   (gnus-xmas-menu-add binary
304     gnus-binary-menu))
305
306 (defun gnus-xmas-agent-summary-menu-add ()
307   (gnus-xmas-menu-add agent-summary
308     gnus-agent-summary-menu))
309
310 (defun gnus-xmas-agent-group-menu-add ()
311   (gnus-xmas-menu-add agent-group
312     gnus-agent-group-menu))
313
314 (defun gnus-xmas-agent-server-menu-add ()
315   (gnus-xmas-menu-add agent-server
316     gnus-agent-server-menu))
317
318 (defun gnus-xmas-tree-menu-add ()
319   (gnus-xmas-menu-add tree
320     gnus-tree-menu))
321
322 (defun gnus-xmas-draft-menu-add ()
323   (gnus-xmas-menu-add draft
324     gnus-draft-menu))
325
326 (defun gnus-xmas-server-menu-add ()
327   (gnus-xmas-menu-add menu
328     gnus-server-server-menu gnus-server-connections-menu))
329
330 (defun gnus-xmas-browse-menu-add ()
331   (gnus-xmas-menu-add browse
332     gnus-browse-menu))
333
334 (defun gnus-xmas-read-event-char (&optional prompt)
335   "Get the next event."
336   (when prompt
337     (message "%s" prompt))
338   (let ((event (next-command-event)))
339     (sit-for 0)
340     ;; We junk all non-key events.  Is this naughty?
341     (while (not (or (key-press-event-p event)
342                     (button-press-event-p event)))
343       (dispatch-event event)
344       (setq event (next-command-event)))
345     (cons (and (key-press-event-p event)
346                (event-to-character event))
347           event)))
348
349 (defun gnus-xmas-define ()
350   (setq gnus-mouse-2 [button2])
351   (setq gnus-mouse-3 [button3])
352   (setq gnus-widget-button-keymap widget-button-keymap)
353
354   (unless (memq 'underline (face-list))
355     (and (fboundp 'make-face)
356          (funcall (intern "make-face") 'underline)))
357   ;; Must avoid calling set-face-underline-p directly, because it
358   ;; is a defsubst in emacs19, and will make the .elc files non
359   ;; portable!
360   (unless (face-differs-from-default-p 'underline)
361     (funcall (intern "set-face-underline-p") 'underline t))
362
363   (cond
364    ((fboundp 'char-or-char-int-p)
365     ;; Handle both types of marks for XEmacs-20.x.
366     (defalias 'gnus-characterp 'char-or-char-int-p))
367    ;; V19 of XEmacs, probably.
368    (t
369     (defalias 'gnus-characterp 'characterp)))
370
371   (defalias 'gnus-make-overlay 'make-extent)
372   (defalias 'gnus-delete-overlay 'delete-extent)
373   (defalias 'gnus-overlay-put 'set-extent-property)
374   (defalias 'gnus-move-overlay 'gnus-xmas-move-overlay)
375   (defalias 'gnus-overlay-buffer 'extent-object)
376   (defalias 'gnus-overlay-start 'extent-start-position)
377   (defalias 'gnus-overlay-end 'extent-end-position)
378   (defalias 'gnus-kill-all-overlays 'gnus-xmas-kill-all-overlays)
379   (defalias 'gnus-extent-detached-p 'extent-detached-p)
380   (defalias 'gnus-add-text-properties 'gnus-xmas-add-text-properties)
381   (defalias 'gnus-put-text-property 'gnus-xmas-put-text-property)
382   (defalias 'gnus-deactivate-mark 'ignore)
383   (defalias 'gnus-window-edges 'window-pixel-edges)
384   (defalias 'gnus-assq-delete-all 'gnus-xmas-assq-delete-all)
385
386   (unless (boundp 'standard-display-table)
387     (setq standard-display-table nil))
388
389   (defvar gnus-mouse-face-prop 'highlight)
390
391   (defun gnus-byte-code (func)
392     "Return a form that can be `eval'ed based on FUNC."
393     (let ((fval (indirect-function func)))
394       (if (compiled-function-p fval)
395           (list 'funcall fval)
396         (cons 'progn (cdr (cdr fval))))))
397
398   (unless (fboundp 'match-string-no-properties)
399     (defalias 'match-string-no-properties 'match-string))
400
401   (defalias 'gnus-x-color-values
402         (if (fboundp 'x-color-values)
403             'x-color-values
404           (lambda (color)
405             (color-instance-rgb-components
406              (make-color-instance color)))))
407
408   (unless (fboundp 'char-width)
409     (defalias 'char-width (lambda (ch) 1))))
410
411 (defun gnus-xmas-redefine ()
412   "Redefine lots of Gnus functions for XEmacs."
413   (defalias 'gnus-summary-set-display-table 'gnus-xmas-summary-set-display-table)
414   (defalias 'gnus-visual-turn-off-edit-menu 'identity)
415   (defalias 'gnus-summary-recenter 'gnus-xmas-summary-recenter)
416   (defalias 'gnus-extent-start-open 'gnus-xmas-extent-start-open)
417   (defalias 'gnus-article-push-button 'gnus-xmas-article-push-button)
418   (defalias 'gnus-window-top-edge 'gnus-xmas-window-top-edge)
419   (defalias 'gnus-read-event-char 'gnus-xmas-read-event-char)
420   (defalias 'gnus-group-startup-message 'gnus-xmas-group-startup-message)
421   (defalias 'gnus-tree-minimize 'gnus-xmas-tree-minimize)
422   (defalias 'gnus-select-lowest-window
423     'gnus-xmas-select-lowest-window)
424   (defalias 'gnus-mail-strip-quoted-names 'gnus-xmas-mail-strip-quoted-names)
425   (defalias 'gnus-character-to-event 'character-to-event)
426   (defalias 'gnus-mode-line-buffer-identification
427     'gnus-xmas-mode-line-buffer-identification)
428   (defalias 'gnus-key-press-event-p 'key-press-event-p)
429   (defalias 'gnus-region-active-p 'region-active-p)
430   (defalias 'gnus-mark-active-p 'region-exists-p)
431   (defalias 'gnus-annotation-in-region-p 'gnus-xmas-annotation-in-region-p)
432   (defalias 'gnus-mime-button-menu 'gnus-xmas-mime-button-menu)
433   (defalias 'gnus-image-type-available-p 'gnus-xmas-image-type-available-p)
434   (defalias 'gnus-put-image 'gnus-xmas-put-image)
435   (defalias 'gnus-create-image 'gnus-xmas-create-image)
436   (defalias 'gnus-remove-image 'gnus-xmas-remove-image)
437
438   ;; These ones are not defcutom'ed, sometimes not even defvar'ed. They
439   ;; probably should. If that is done, the code below should then be moved
440   ;; where each variable is defined, in order not to mess with user settings.
441   ;; -- didier
442   (add-hook 'gnus-score-mode-hook 'gnus-xmas-score-menu-add)
443   (add-hook 'gnus-binary-mode-hook 'gnus-xmas-binary-menu-add)
444   (add-hook 'gnus-server-mode-hook 'gnus-xmas-server-menu-add)
445   (add-hook 'gnus-browse-mode-hook 'gnus-xmas-browse-menu-add)
446   (add-hook 'gnus-draft-mode-hook 'gnus-xmas-draft-menu-add)
447   (add-hook 'gnus-mailing-list-mode-hook 'gnus-xmas-mailing-list-menu-add))
448
449
450 ;;; XEmacs logo and toolbar.
451
452 (defun gnus-xmas-group-startup-message (&optional x y)
453   "Insert startup message in current buffer."
454   ;; Insert the message.
455   (erase-buffer)
456   (cond
457    ((and (console-on-window-system-p)
458          (or (featurep 'xpm)
459              (featurep 'xbm)))
460     (let* ((logo-xpm (expand-file-name "gnus.xpm" gnus-xmas-glyph-directory))
461            (logo-xbm (expand-file-name "gnus.xbm" gnus-xmas-glyph-directory))
462            (glyph (make-glyph
463                    (cond ((featurep 'xpm)
464                           `[xpm
465                             :file ,logo-xpm
466                             :color-symbols
467                             (("thing" . ,(car gnus-logo-colors))
468                              ("shadow" . ,(cadr gnus-logo-colors))
469                              ("oort" . "#eeeeee")
470                              ("background" . ,(face-background 'default)))])
471                          ((featurep 'xbm)
472                           `[xbm :file ,logo-xbm])
473                          (t [nothing])))))
474       (insert " ")
475       (set-extent-begin-glyph (make-extent (point) (point)) glyph)
476       (goto-char (point-min))
477       (while (not (eobp))
478         (insert (make-string (/ (max (- (window-width) (or x 35)) 0) 2)
479                              ?\ ))
480         (forward-line 1))
481       (setq gnus-simple-splash nil))
482     (goto-char (point-min))
483     (let* ((pheight (+ 20 (count-lines (point-min) (point-max))))
484            (wheight (window-height))
485            (rest (- wheight pheight)))
486       (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n))))
487    (t
488     (insert
489      (format "              %s
490           _    ___ _             _
491           _ ___ __ ___  __    _ ___
492           __   _     ___    __  ___
493               _           ___     _
494              _  _ __             _
495              ___   __            _
496                    __           _
497                     _      _   _
498                    _      _    _
499                       _  _    _
500                   __  ___
501                  _   _ _     _
502                 _   _
503               _    _
504              _    _
505             _
506           __
507
508 "
509              ""))
510     ;; And then hack it.
511     (gnus-indent-rigidly (point-min) (point-max)
512                          (/ (max (- (window-width) (or x 46)) 0) 2))
513     (goto-char (point-min))
514     (forward-line 1)
515     (let* ((pheight (count-lines (point-min) (point-max)))
516            (wheight (window-height))
517            (rest (- wheight pheight)))
518       (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
519     ;; Paint it.
520     (put-text-property (point-min) (point-max) 'face 'gnus-splash)))
521   (setq modeline-buffer-identification
522         (list (concat gnus-version ": *Group*")))
523   (set-buffer-modified-p t))
524
525
526 ;;; The toolbar.
527
528 (defun gnus-xmas-update-toolbars ()
529   "Update the toolbars' appearance."
530   (when (and (not noninteractive)
531              (featurep 'gnus-xmas))
532     (save-excursion
533       (dolist (buffer (buffer-list))
534         (set-buffer buffer)
535         (cond ((eq major-mode 'gnus-group-mode)
536                (gnus-xmas-setup-group-toolbar))
537               ((eq major-mode 'gnus-summary-mode)
538                (gnus-xmas-setup-summary-toolbar)))))))
539
540 (defcustom gnus-use-toolbar (if (featurep 'toolbar) 'default)
541   "*Position to display the toolbar.  Nil means do not use a toolbar.
542 If it is non-nil, it should be one of the symbols `default', `top',
543 `bottom', `right', and `left'.  `default' means to use the default
544 toolbar, the rest mean to display the toolbar on the place which those
545 names show."
546   :type '(choice (const default)
547                  (const top) (const bottom) (const left) (const right)
548                  (const :tag "no toolbar" nil))
549   :set (lambda (symbol value)
550          (set-default
551           symbol
552           (if (or (not value)
553                   (memq value (list 'default 'top 'bottom 'right 'left)))
554               value
555             'default))
556          (gnus-xmas-update-toolbars))
557   :group 'gnus-xmas)
558
559 (defcustom gnus-toolbar-thickness
560   (if (featurep 'toolbar)
561       (cons (specifier-instance default-toolbar-height)
562             (specifier-instance default-toolbar-width)))
563   "*Cons of the height and the width specifying the thickness of a toolbar.
564 The height is used for the toolbar displayed on the top or the bottom,
565 the width is used for the toolbar displayed on the right or the left."
566   :type '(cons :tag "height & width"
567                (integer :tag "height") (integer :tag "width"))
568   :set (lambda (symbol value)
569          (set-default
570           symbol
571           (if (and (consp value) (natnump (car value)) (natnump (cdr value)))
572               value
573             '(37 . 40)))
574          (gnus-xmas-update-toolbars))
575   :group 'gnus-xmas)
576
577 (defvar gnus-group-toolbar
578   '([gnus-group-get-new-news gnus-group-get-new-news t "Get new news"]
579     [gnus-group-get-new-news-this-group
580      gnus-group-get-new-news-this-group t "Get new news in this group"]
581     [gnus-group-catchup-current
582      gnus-group-catchup-current t "Catchup group"]
583     [gnus-group-describe-group
584      gnus-group-describe-group t "Describe group"]
585     [gnus-group-unsubscribe gnus-group-unsubscribe t "Unsubscribe group"]
586     [gnus-group-subscribe gnus-group-subscribe t "Subscribe group"]
587     [gnus-group-kill-group gnus-group-kill-group t "Kill group"]
588     [gnus-summary-mail-save
589      gnus-group-save-newsrc t "Save .newsrc files"] ; borrowed icon.
590     [gnus-group-exit gnus-group-exit t "Exit Gnus"])
591   "The group buffer toolbar.")
592
593 (defvar gnus-summary-toolbar
594   '([gnus-summary-prev-unread
595      gnus-summary-prev-page-or-article t "Page up"]
596     [gnus-summary-next-unread
597      gnus-summary-next-page t "Page down"]
598     [gnus-summary-post-news
599      gnus-summary-post-news t "Post an article"]
600     [gnus-summary-followup-with-original
601      gnus-summary-followup-with-original t
602      "Post a followup and yank the original"]
603     [gnus-summary-followup
604      gnus-summary-followup t "Post a followup"]
605     [gnus-summary-reply-with-original
606      gnus-summary-reply-with-original t "Mail a reply and yank the original"]
607     [gnus-summary-reply
608      gnus-summary-reply t "Mail a reply"]
609     [gnus-summary-caesar-message
610      gnus-summary-caesar-message t "Rot 13"]
611     [gnus-uu-decode-uu
612      gnus-uu-decode-uu t "Decode uuencoded articles"]
613     [gnus-summary-save-article-file
614      gnus-summary-save-article-file t "Save article in file"]
615     [gnus-summary-save-article
616      gnus-summary-save-article t "Save article"]
617     [gnus-uu-post-news
618      gnus-uu-post-news t "Post a uuencoded article"]
619     [gnus-summary-cancel-article
620      gnus-summary-cancel-article t "Cancel article"]
621     [gnus-summary-catchup
622      gnus-summary-catchup t "Catchup"]
623     [gnus-summary-catchup-and-exit
624      gnus-summary-catchup-and-exit t "Catchup and exit"]
625     [gnus-summary-exit gnus-summary-exit t "Exit this summary"])
626   "The summary buffer toolbar.")
627
628 (defvar gnus-summary-mail-toolbar
629   '(
630     [gnus-summary-prev-unread
631      gnus-summary-prev-unread-article t "Prev unread article"]
632     [gnus-summary-next-unread
633      gnus-summary-next-unread-article t "Next unread article"]
634     [gnus-summary-mail-reply gnus-summary-reply t "Reply"]
635     [gnus-summary-mail-originate gnus-summary-post-news t "Originate"]
636     [gnus-summary-mail-save gnus-summary-save-article t "Save"]
637     [gnus-summary-mail-copy gnus-summary-copy-article t "Copy message"]
638     [gnus-summary-mail-forward gnus-summary-mail-forward t "Forward message"]
639     [gnus-summary-caesar-message
640      gnus-summary-caesar-message t "Rot 13"]
641     [gnus-uu-decode-uu
642      gnus-uu-decode-uu t "Decode uuencoded articles"]
643     [gnus-summary-save-article-file
644      gnus-summary-save-article-file t "Save article in file"]
645     [gnus-summary-save-article
646      gnus-summary-save-article t "Save article"]
647     [gnus-summary-cancel-article ; usenet : cancellation :: mail : deletion.
648      gnus-summary-delete-article t "Delete message"]
649     [gnus-summary-catchup
650      gnus-summary-catchup t "Catchup"]
651     [gnus-summary-catchup-and-exit
652      gnus-summary-catchup-and-exit t "Catchup and exit"]
653     [gnus-summary-exit gnus-summary-exit t "Exit this summary"])
654   "The summary buffer mail toolbar.")
655
656 (defun gnus-xmas-setup-toolbar (toolbar)
657   (when (featurep 'toolbar)
658     (if (and gnus-use-toolbar
659              (message-xmas-setup-toolbar toolbar nil "gnus"))
660         (let* ((bar (or (intern-soft (format "%s-toolbar" gnus-use-toolbar))
661                         'default-toolbar))
662                (bars (delq bar (list 'top-toolbar 'bottom-toolbar
663                                      'right-toolbar 'left-toolbar)))
664                hw)
665           (while bars
666             (remove-specifier (symbol-value (pop bars)) (current-buffer)))
667           (unless (eq bar 'default-toolbar)
668             (set-specifier default-toolbar nil (current-buffer)))
669           (set-specifier (symbol-value bar) toolbar (current-buffer))
670           (when (setq hw (cdr (assq gnus-use-toolbar
671                                     '((default . default-toolbar-height)
672                                       (top . top-toolbar-height)
673                                       (bottom . bottom-toolbar-height)))))
674             (set-specifier (symbol-value hw) (car gnus-toolbar-thickness)
675                            (current-buffer)))
676           (when (setq hw (cdr (assq gnus-use-toolbar
677                                     '((default . default-toolbar-width)
678                                       (right . right-toolbar-width)
679                                       (left . left-toolbar-width)))))
680             (set-specifier (symbol-value hw) (cdr gnus-toolbar-thickness)
681                            (current-buffer))))
682       (set-specifier default-toolbar nil (current-buffer))
683       (remove-specifier top-toolbar (current-buffer))
684       (remove-specifier bottom-toolbar (current-buffer))
685       (remove-specifier right-toolbar (current-buffer))
686       (remove-specifier left-toolbar (current-buffer)))
687     (set-specifier default-toolbar-visible-p t (current-buffer))
688     (set-specifier top-toolbar-visible-p t (current-buffer))
689     (set-specifier bottom-toolbar-visible-p t (current-buffer))
690     (set-specifier right-toolbar-visible-p t (current-buffer))
691     (set-specifier left-toolbar-visible-p t (current-buffer))))
692
693 (defun gnus-xmas-setup-group-toolbar ()
694   (gnus-xmas-setup-toolbar gnus-group-toolbar))
695
696 (defun gnus-xmas-setup-summary-toolbar ()
697   (gnus-xmas-setup-toolbar (if (gnus-news-group-p gnus-newsgroup-name)
698                                gnus-summary-toolbar
699                              gnus-summary-mail-toolbar)))
700
701 (defun gnus-xmas-mail-strip-quoted-names (address)
702   "Protect mail-strip-quoted-names from nil input.
703 XEmacs compatibility workaround."
704   (if (null address)
705       nil
706     (mail-strip-quoted-names address)))
707
708 (defun gnus-xmas-call-region (command &rest args)
709   (apply
710    'call-process-region (point-min) (point-max) command t '(t nil) nil
711    args))
712
713 (defvar gnus-xmas-modeline-left-extent
714   (let ((ext (copy-extent modeline-buffer-id-left-extent)))
715     ext))
716
717 (defvar gnus-xmas-modeline-right-extent
718   (let ((ext (copy-extent modeline-buffer-id-right-extent)))
719     ext))
720
721 (defvar gnus-xmas-modeline-glyph
722   (progn
723     (let* ((file-xpm (expand-file-name "gnus-pointer.xpm"
724                                        gnus-xmas-glyph-directory))
725            (file-xbm (expand-file-name "gnus-pointer.xbm"
726                                        gnus-xmas-glyph-directory))
727            (glyph (make-glyph
728                    ;; Gag gag gag.
729                    (cond ((featurep 'xpm)
730                           ;; Let's try a nifty XPM
731                           `[xpm :file ,file-xpm])
732                          ((featurep 'xbm)
733                           ;; Then a not-so-nifty XBM
734                           `[xbm :file ,file-xbm])
735                          ;; Then the simple string
736                          (t [string :data "Gnus:"])))))
737       (set-glyph-face glyph 'modeline-buffer-id)
738       glyph)))
739
740 (defun gnus-xmas-mode-line-buffer-identification (line)
741   (let ((line (car line))
742         chop)
743     (cond
744      ;; This is some weird type of id.
745      ((not (stringp line))
746       (list line))
747      ;; This is non-standard, so we just pass it through.
748      ((not (string-match "^Gnus:" line))
749       (list line))
750      ;; We have a standard line, so we colorize and glyphize it a bit.
751      (t
752       (setq chop (match-end 0))
753       (list
754        (if gnus-xmas-modeline-glyph
755            (cons gnus-xmas-modeline-left-extent gnus-xmas-modeline-glyph)
756          (cons gnus-xmas-modeline-left-extent (substring line 0 chop)))
757        (cons gnus-xmas-modeline-right-extent (substring line chop)))))))
758
759 (defun gnus-xmas-splash ()
760   (when (eq (device-type) 'x)
761     (gnus-splash)))
762
763 (defun gnus-xmas-annotation-in-region-p (b e)
764   (or (map-extents (lambda (e u) t) nil b e nil nil 'mm t)
765       (if (= b e)
766           (eq (cadr (memq 'gnus-undeletable (text-properties-at b))) t)
767         (text-property-any b e 'gnus-undeletable t))))
768
769 (defun gnus-xmas-mime-button-menu (event prefix)
770   "Construct a context-sensitive menu of MIME commands."
771   (interactive "e\nP")
772   (let ((response (get-popup-menu-response
773                    `("MIME Part"
774                      ,@(mapcar (lambda (c) `[,(caddr c) ,(car c) t])
775                                gnus-mime-button-commands)))))
776     (set-buffer (event-buffer event))
777     (goto-char (event-point event))
778     (funcall (event-function response) (event-object response))))
779
780 (defun gnus-group-add-icon ()
781   "Add an icon to the current line according to `gnus-group-icon-list'."
782   (let* ((p (point))
783          (end (point-at-eol))
784          ;; now find out where the line starts and leave point there.
785          (beg (progn (beginning-of-line) (point))))
786     (save-restriction
787       (narrow-to-region beg end)
788       (goto-char beg)
789       (when (search-forward "==&&==" nil t)
790         (let* ((group (gnus-group-group-name))
791                (entry (gnus-group-entry group))
792                (unread (if (numberp (car entry)) (car entry) 0))
793                (active (gnus-active group))
794                (total (if active (1+ (- (cdr active) (car active))) 0))
795                (info (nth 2 entry))
796                (method (gnus-server-get-method group (gnus-info-method info)))
797                (marked (gnus-info-marks info))
798                (mailp (memq 'mail (assoc (symbol-name
799                                           (car (or method gnus-select-method)))
800                                          gnus-valid-select-methods)))
801                (level (or (gnus-info-level info) gnus-level-killed))
802                (score (or (gnus-info-score info) 0))
803                (ticked (gnus-range-length (cdr (assq 'tick marked))))
804                (group-age (gnus-group-timestamp-delta group))
805                (inhibit-read-only t)
806                (list gnus-group-icon-list)
807                (mystart (match-beginning 0))
808                (myend (match-end 0)))
809           (goto-char (point-min))
810           (while (and list
811                       (not (eval (caar list))))
812             (setq list (cdr list)))
813           (if list
814               (let* ((file (cdar list))
815                      (glyph (gnus-group-icon-create-glyph
816                              (buffer-substring mystart myend)
817                              file)))
818                 (if glyph
819                     (progn
820                       (mapcar 'delete-annotation (annotations-at myend))
821                       (let ((ext (make-extent mystart myend))
822                             (ant (make-annotation glyph myend 'text)))
823                         ;; set text extent params
824                         (set-extent-property ext 'end-open t)
825                         (set-extent-property ext 'start-open t)
826                         (set-extent-property ext 'invisible t)))
827                   (delete-region mystart myend)))
828             (delete-region mystart myend))))
829       (widen))
830     (goto-char p)))
831
832 (defun gnus-group-icon-create-glyph (substring pixmap)
833   "Create a glyph for insertion into a group line."
834   (or
835    (cdr-safe (assoc pixmap gnus-group-icon-cache))
836    (let* ((glyph (make-glyph
837                   (list
838                    (cons 'x
839                          (expand-file-name pixmap gnus-xmas-glyph-directory))
840                    (cons 'mswindows
841                          (expand-file-name pixmap gnus-xmas-glyph-directory))
842                    (cons 'tty substring)))))
843      (setq gnus-group-icon-cache
844            (cons (cons pixmap glyph) gnus-group-icon-cache))
845      (set-glyph-face glyph 'default)
846      glyph)))
847
848 (defun gnus-xmas-mailing-list-menu-add ()
849   (gnus-xmas-menu-add mailing-list
850                       gnus-mailing-list-menu))
851
852 (defun gnus-xmas-image-type-available-p (type)
853   (and window-system
854        (featurep (if (eq type 'pbm) 'xbm type))))
855
856 (defun gnus-xmas-create-image (file &optional type data-p &rest props)
857   (let ((type (if type
858                   (symbol-name type)
859                 (car (last (split-string file "[.]")))))
860         (face (plist-get props :face))
861         glyph)
862     (when (equal type "pbm")
863       (with-temp-buffer
864         (if data-p
865             (insert file)
866           (insert-file-contents-literally file))
867         (shell-command-on-region (point-min) (point-max)
868                                  "ppmtoxpm 2>/dev/null" t)
869         (setq file (buffer-string)
870               type "xpm"
871               data-p t)))
872     (setq glyph
873           (if (equal type "xbm")
874               (make-glyph (list (cons 'x file)))
875             (with-temp-buffer
876               (if data-p
877                   (insert file)
878                 (insert-file-contents-literally file))
879               (make-glyph
880                (vector
881                 (or (intern type)
882                     (mm-image-type-from-buffer))
883                 :data (buffer-string))))))
884     (when face
885       (set-glyph-face glyph face))
886     glyph))
887
888 (defun gnus-xmas-put-image (glyph &optional string category)
889   "Insert STRING, but display GLYPH.
890 Warning: Don't insert text immediately after the image."
891   (let ((begin (point))
892         extent)
893     (if (and (bobp) (not string))
894         (setq string " "))
895     (if string
896         (insert string)
897       (setq begin (1- begin)))
898     (setq extent (make-extent begin (point)))
899     (set-extent-property extent 'gnus-image category)
900     (set-extent-property extent 'duplicable t)
901     (if string
902         (set-extent-property extent 'invisible t))
903     (set-extent-property extent 'end-glyph glyph))
904   glyph)
905
906 (defun gnus-xmas-remove-image (image &optional category)
907   "Remove the image matching IMAGE and CATEGORY found first."
908   (map-extents
909    (lambda (ext unused)
910      (when (equal (extent-end-glyph ext) image)
911        (set-extent-property ext 'invisible nil)
912        (set-extent-property ext 'end-glyph nil)
913        t))
914    nil nil nil nil nil 'gnus-image category))
915
916 (defun gnus-xmas-assq-delete-all (key alist)
917   (let ((elem nil))
918     (while (setq elem (assq key alist))
919       (setq alist (delq elem alist)))
920     alist))
921
922 (provide 'gnus-xmas)
923
924 ;;; arch-tag: 4e84de3f-ea0a-4ee3-bfeb-e03d46fcacef
925 ;;; gnus-xmas.el ends here