Import No Gnus v0.4.
[elisp/gnus.git-] / 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,
4 ;;   2005, 2006 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-mime-security-button-menu
434     'gnus-xmas-mime-security-button-menu)
435   (defalias 'gnus-image-type-available-p 'gnus-xmas-image-type-available-p)
436   (defalias 'gnus-put-image 'gnus-xmas-put-image)
437   (defalias 'gnus-create-image 'gnus-xmas-create-image)
438   (defalias 'gnus-remove-image 'gnus-xmas-remove-image)
439
440   ;; These ones are not defcutom'ed, sometimes not even defvar'ed. They
441   ;; probably should. If that is done, the code below should then be moved
442   ;; where each variable is defined, in order not to mess with user settings.
443   ;; -- didier
444   (add-hook 'gnus-score-mode-hook 'gnus-xmas-score-menu-add)
445   (add-hook 'gnus-binary-mode-hook 'gnus-xmas-binary-menu-add)
446   (add-hook 'gnus-server-mode-hook 'gnus-xmas-server-menu-add)
447   (add-hook 'gnus-browse-mode-hook 'gnus-xmas-browse-menu-add)
448   (add-hook 'gnus-draft-mode-hook 'gnus-xmas-draft-menu-add)
449   (add-hook 'gnus-mailing-list-mode-hook 'gnus-xmas-mailing-list-menu-add))
450
451
452 ;;; XEmacs logo and toolbar.
453
454 (defun gnus-xmas-group-startup-message (&optional x y)
455   "Insert startup message in current buffer."
456   ;; Insert the message.
457   (erase-buffer)
458   (cond
459    ((and (console-on-window-system-p)
460          (or (featurep 'xpm)
461              (featurep 'xbm)))
462     (let* ((logo-xpm (expand-file-name "gnus.xpm" gnus-xmas-glyph-directory))
463            (logo-xbm (expand-file-name "gnus.xbm" gnus-xmas-glyph-directory))
464            (glyph (make-glyph
465                    (cond ((featurep 'xpm)
466                           `[xpm
467                             :file ,logo-xpm
468                             :color-symbols
469                             (("thing" . ,(car gnus-logo-colors))
470                              ("shadow" . ,(cadr gnus-logo-colors))
471                              ("oort" . "#eeeeee")
472                              ("background" . ,(face-background 'default)))])
473                          ((featurep 'xbm)
474                           `[xbm :file ,logo-xbm])
475                          (t [nothing])))))
476       (insert " ")
477       (set-extent-begin-glyph (make-extent (point) (point)) glyph)
478       (goto-char (point-min))
479       (while (not (eobp))
480         (insert (make-string (/ (max (- (window-width) (or x 35)) 0) 2)
481                              ?\ ))
482         (forward-line 1))
483       (setq gnus-simple-splash nil))
484     (goto-char (point-min))
485     (let* ((pheight (+ 20 (count-lines (point-min) (point-max))))
486            (wheight (window-height))
487            (rest (- wheight pheight)))
488       (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n))))
489    (t
490     (insert
491      (format "              %s
492           _    ___ _             _
493           _ ___ __ ___  __    _ ___
494           __   _     ___    __  ___
495               _           ___     _
496              _  _ __             _
497              ___   __            _
498                    __           _
499                     _      _   _
500                    _      _    _
501                       _  _    _
502                   __  ___
503                  _   _ _     _
504                 _   _
505               _    _
506              _    _
507             _
508           __
509
510 "
511              ""))
512     ;; And then hack it.
513     (gnus-indent-rigidly (point-min) (point-max)
514                          (/ (max (- (window-width) (or x 46)) 0) 2))
515     (goto-char (point-min))
516     (forward-line 1)
517     (let* ((pheight (count-lines (point-min) (point-max)))
518            (wheight (window-height))
519            (rest (- wheight pheight)))
520       (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
521     ;; Paint it.
522     (put-text-property (point-min) (point-max) 'face 'gnus-splash)))
523   (setq modeline-buffer-identification
524         (list (concat gnus-version ": *Group*")))
525   (set-buffer-modified-p t))
526
527
528 ;;; The toolbar.
529
530 (defun gnus-xmas-update-toolbars ()
531   "Update the toolbars' appearance."
532   (when (and (not noninteractive)
533              (featurep 'gnus-xmas))
534     (save-excursion
535       (dolist (buffer (buffer-list))
536         (set-buffer buffer)
537         (cond ((eq major-mode 'gnus-group-mode)
538                (gnus-xmas-setup-group-toolbar))
539               ((eq major-mode 'gnus-summary-mode)
540                (gnus-xmas-setup-summary-toolbar)))))))
541
542 (defcustom gnus-use-toolbar (if (featurep 'toolbar) 'default)
543   "*Position to display the toolbar.  Nil means do not use a toolbar.
544 If it is non-nil, it should be one of the symbols `default', `top',
545 `bottom', `right', and `left'.  `default' means to use the default
546 toolbar, the rest mean to display the toolbar on the place which those
547 names show."
548   :type '(choice (const default)
549                  (const top) (const bottom) (const left) (const right)
550                  (const :tag "no toolbar" nil))
551   :set (lambda (symbol value)
552          (set-default
553           symbol
554           (if (or (not value)
555                   (memq value (list 'default 'top 'bottom 'right 'left)))
556               value
557             'default))
558          (gnus-xmas-update-toolbars))
559   :group 'gnus-xmas)
560
561 (defcustom gnus-toolbar-thickness
562   (if (featurep 'toolbar)
563       (cons (specifier-instance default-toolbar-height)
564             (specifier-instance default-toolbar-width)))
565   "*Cons of the height and the width specifying the thickness of a toolbar.
566 The height is used for the toolbar displayed on the top or the bottom,
567 the width is used for the toolbar displayed on the right or the left."
568   :type '(cons :tag "height & width"
569                (integer :tag "height") (integer :tag "width"))
570   :set (lambda (symbol value)
571          (set-default
572           symbol
573           (if (and (consp value) (natnump (car value)) (natnump (cdr value)))
574               value
575             '(37 . 40)))
576          (gnus-xmas-update-toolbars))
577   :group 'gnus-xmas)
578
579 (defvar gnus-group-toolbar
580   '([gnus-group-get-new-news gnus-group-get-new-news t "Get new news"]
581     [gnus-group-get-new-news-this-group
582      gnus-group-get-new-news-this-group t "Get new news in this group"]
583     [gnus-group-catchup-current
584      gnus-group-catchup-current t "Catchup group"]
585     [gnus-group-describe-group
586      gnus-group-describe-group t "Describe group"]
587     [gnus-group-unsubscribe gnus-group-unsubscribe t "Unsubscribe group"]
588     [gnus-group-subscribe gnus-group-subscribe t "Subscribe group"]
589     [gnus-group-kill-group gnus-group-kill-group t "Kill group"]
590     [gnus-summary-mail-save
591      gnus-group-save-newsrc t "Save .newsrc files"] ; borrowed icon.
592     [gnus-group-exit gnus-group-exit t "Exit Gnus"])
593   "The group buffer toolbar.")
594
595 (defvar gnus-summary-toolbar
596   '([gnus-summary-prev-unread
597      gnus-summary-prev-page-or-article t "Page up"]
598     [gnus-summary-next-unread
599      gnus-summary-next-page t "Page down"]
600     [gnus-summary-post-news
601      gnus-summary-post-news t "Post an article"]
602     [gnus-summary-followup-with-original
603      gnus-summary-followup-with-original t
604      "Post a followup and yank the original"]
605     [gnus-summary-followup
606      gnus-summary-followup t "Post a followup"]
607     [gnus-summary-reply-with-original
608      gnus-summary-reply-with-original t "Mail a reply and yank the original"]
609     [gnus-summary-reply
610      gnus-summary-reply t "Mail a reply"]
611     [gnus-summary-caesar-message
612      gnus-summary-caesar-message t "Rot 13"]
613     [gnus-uu-decode-uu
614      gnus-uu-decode-uu t "Decode uuencoded articles"]
615     [gnus-summary-save-article-file
616      gnus-summary-save-article-file t "Save article in file"]
617     [gnus-summary-save-article
618      gnus-summary-save-article t "Save article"]
619     [gnus-uu-post-news
620      gnus-uu-post-news t "Post a uuencoded article"]
621     [gnus-summary-cancel-article
622      gnus-summary-cancel-article t "Cancel article"]
623     [gnus-summary-catchup
624      gnus-summary-catchup t "Catchup"]
625     [gnus-summary-catchup-and-exit
626      gnus-summary-catchup-and-exit t "Catchup and exit"]
627     [gnus-summary-exit gnus-summary-exit t "Exit this summary"])
628   "The summary buffer toolbar.")
629
630 (defvar gnus-summary-mail-toolbar
631   '(
632     [gnus-summary-prev-unread
633      gnus-summary-prev-unread-article t "Prev unread article"]
634     [gnus-summary-next-unread
635      gnus-summary-next-unread-article t "Next unread article"]
636     [gnus-summary-mail-reply gnus-summary-reply t "Reply"]
637     [gnus-summary-mail-originate gnus-summary-post-news t "Originate"]
638     [gnus-summary-mail-save gnus-summary-save-article t "Save"]
639     [gnus-summary-mail-copy gnus-summary-copy-article t "Copy message"]
640     [gnus-summary-mail-forward gnus-summary-mail-forward t "Forward message"]
641     [gnus-summary-caesar-message
642      gnus-summary-caesar-message t "Rot 13"]
643     [gnus-uu-decode-uu
644      gnus-uu-decode-uu t "Decode uuencoded articles"]
645     [gnus-summary-save-article-file
646      gnus-summary-save-article-file t "Save article in file"]
647     [gnus-summary-save-article
648      gnus-summary-save-article t "Save article"]
649     [gnus-summary-cancel-article ; usenet : cancellation :: mail : deletion.
650      gnus-summary-delete-article t "Delete message"]
651     [gnus-summary-catchup
652      gnus-summary-catchup t "Catchup"]
653     [gnus-summary-catchup-and-exit
654      gnus-summary-catchup-and-exit t "Catchup and exit"]
655     [gnus-summary-exit gnus-summary-exit t "Exit this summary"])
656   "The summary buffer mail toolbar.")
657
658 (defun gnus-xmas-setup-toolbar (toolbar)
659   (when (featurep 'toolbar)
660     (if (and gnus-use-toolbar
661              (message-xmas-setup-toolbar toolbar nil "gnus"))
662         (let ((bar (or (intern-soft (format "%s-toolbar" gnus-use-toolbar))
663                        'default-toolbar))
664               (height (car gnus-toolbar-thickness))
665               (width (cdr gnus-toolbar-thickness))
666               (cur (current-buffer))
667               bars)
668           (set-specifier (symbol-value bar) toolbar cur)
669           (set-specifier default-toolbar-height height cur)
670           (set-specifier default-toolbar-width width cur)
671           (set-specifier top-toolbar-height height cur)
672           (set-specifier bottom-toolbar-height height cur)
673           (set-specifier right-toolbar-width width cur)
674           (set-specifier left-toolbar-width width cur)
675           (if (eq bar 'default-toolbar)
676               (progn
677                 (remove-specifier default-toolbar-visible-p cur)
678                 (remove-specifier top-toolbar cur)
679                 (remove-specifier top-toolbar-visible-p cur)
680                 (remove-specifier bottom-toolbar cur)
681                 (remove-specifier bottom-toolbar-visible-p cur)
682                 (remove-specifier right-toolbar cur)
683                 (remove-specifier right-toolbar-visible-p cur)
684                 (remove-specifier left-toolbar cur)
685                 (remove-specifier left-toolbar-visible-p cur))
686             (set-specifier (symbol-value (intern (format "%s-visible-p" bar)))
687                            t cur)
688             (setq bars (delq bar (list 'default-toolbar
689                                        'bottom-toolbar 'top-toolbar
690                                        'right-toolbar 'left-toolbar)))
691             (while bars
692               (set-specifier (symbol-value (intern (format "%s-visible-p"
693                                                            (pop bars))))
694                              nil cur))))
695       (let ((cur (current-buffer)))
696         (set-specifier default-toolbar-visible-p nil cur)
697         (set-specifier top-toolbar-visible-p nil cur)
698         (set-specifier bottom-toolbar-visible-p nil cur)
699         (set-specifier right-toolbar-visible-p nil cur)
700         (set-specifier left-toolbar-visible-p nil cur)))))
701
702 (defun gnus-xmas-setup-group-toolbar ()
703   (gnus-xmas-setup-toolbar gnus-group-toolbar))
704
705 (defun gnus-xmas-setup-summary-toolbar ()
706   (gnus-xmas-setup-toolbar (if (gnus-news-group-p gnus-newsgroup-name)
707                                gnus-summary-toolbar
708                              gnus-summary-mail-toolbar)))
709
710 (defun gnus-xmas-mail-strip-quoted-names (address)
711   "Protect mail-strip-quoted-names from nil input.
712 XEmacs compatibility workaround."
713   (if (null address)
714       nil
715     (mail-strip-quoted-names address)))
716
717 (defun gnus-xmas-call-region (command &rest args)
718   (apply
719    'call-process-region (point-min) (point-max) command t '(t nil) nil
720    args))
721
722 (defvar gnus-xmas-modeline-left-extent
723   (let ((ext (copy-extent modeline-buffer-id-left-extent)))
724     ext))
725
726 (defvar gnus-xmas-modeline-right-extent
727   (let ((ext (copy-extent modeline-buffer-id-right-extent)))
728     ext))
729
730 (defvar gnus-xmas-modeline-glyph
731   (progn
732     (let* ((file-xpm (expand-file-name "gnus-pointer.xpm"
733                                        gnus-xmas-glyph-directory))
734            (file-xbm (expand-file-name "gnus-pointer.xbm"
735                                        gnus-xmas-glyph-directory))
736            (glyph (make-glyph
737                    ;; Gag gag gag.
738                    (cond ((featurep 'xpm)
739                           ;; Let's try a nifty XPM
740                           `[xpm :file ,file-xpm])
741                          ((featurep 'xbm)
742                           ;; Then a not-so-nifty XBM
743                           `[xbm :file ,file-xbm])
744                          ;; Then the simple string
745                          (t [string :data "Gnus:"])))))
746       (set-glyph-face glyph 'modeline-buffer-id)
747       glyph)))
748
749 (defun gnus-xmas-mode-line-buffer-identification (line)
750   (let ((line (car line))
751         chop)
752     (cond
753      ;; This is some weird type of id.
754      ((not (stringp line))
755       (list line))
756      ;; This is non-standard, so we just pass it through.
757      ((not (string-match "^Gnus:" line))
758       (list line))
759      ;; We have a standard line, so we colorize and glyphize it a bit.
760      (t
761       (setq chop (match-end 0))
762       (list
763        (if gnus-xmas-modeline-glyph
764            (cons gnus-xmas-modeline-left-extent gnus-xmas-modeline-glyph)
765          (cons gnus-xmas-modeline-left-extent (substring line 0 chop)))
766        (cons gnus-xmas-modeline-right-extent (substring line chop)))))))
767
768 (defun gnus-xmas-splash ()
769   (when (eq (device-type) 'x)
770     (gnus-splash)))
771
772 (defun gnus-xmas-annotation-in-region-p (b e)
773   (or (map-extents (lambda (e u) t) nil b e nil nil 'mm t)
774       (if (= b e)
775           (eq (cadr (memq 'gnus-undeletable (text-properties-at b))) t)
776         (text-property-any b e 'gnus-undeletable t))))
777
778 (defun gnus-xmas-mime-button-menu (event prefix)
779   "Construct a context-sensitive menu of MIME commands."
780   (interactive "e\nP")
781   (let ((response (get-popup-menu-response
782                    `("MIME Part"
783                      ,@(mapcar (lambda (c) `[,(caddr c) ,(car c) t])
784                                gnus-mime-button-commands)))))
785     (set-buffer (event-buffer event))
786     (goto-char (event-point event))
787     (funcall (event-function response) (event-object response))))
788
789 (defun gnus-xmas-mime-security-button-menu (event prefix)
790   "Construct a context-sensitive menu of security commands."
791   (interactive "e\nP")
792   (let ((response
793          (get-popup-menu-response
794           `("Security Part"
795             ,@(delq nil
796                     (mapcar (lambda (c)
797                               (unless (eq (car c) 'undefined)
798                                 `[,(caddr c) ,(car c) t]))
799                             gnus-mime-security-button-commands))))))
800     (set-buffer (event-buffer event))
801     (goto-char (event-point event))
802     (funcall (event-function response) (event-object response))))
803
804 (defun gnus-group-add-icon ()
805   "Add an icon to the current line according to `gnus-group-icon-list'."
806   (let* ((p (point))
807          (end (point-at-eol))
808          ;; now find out where the line starts and leave point there.
809          (beg (progn (beginning-of-line) (point))))
810     (save-restriction
811       (narrow-to-region beg end)
812       (goto-char beg)
813       (when (search-forward "==&&==" nil t)
814         (let* ((group (gnus-group-group-name))
815                (entry (gnus-group-entry group))
816                (unread (if (numberp (car entry)) (car entry) 0))
817                (active (gnus-active group))
818                (total (if active (1+ (- (cdr active) (car active))) 0))
819                (info (nth 2 entry))
820                (method (gnus-server-get-method group (gnus-info-method info)))
821                (marked (gnus-info-marks info))
822                (mailp (memq 'mail (assoc (symbol-name
823                                           (car (or method gnus-select-method)))
824                                          gnus-valid-select-methods)))
825                (level (or (gnus-info-level info) gnus-level-killed))
826                (score (or (gnus-info-score info) 0))
827                (ticked (gnus-range-length (cdr (assq 'tick marked))))
828                (group-age (gnus-group-timestamp-delta group))
829                (inhibit-read-only t)
830                (list gnus-group-icon-list)
831                (mystart (match-beginning 0))
832                (myend (match-end 0)))
833           (goto-char (point-min))
834           (while (and list
835                       (not (eval (caar list))))
836             (setq list (cdr list)))
837           (if list
838               (let* ((file (cdar list))
839                      (glyph (gnus-group-icon-create-glyph
840                              (buffer-substring mystart myend)
841                              file)))
842                 (if glyph
843                     (progn
844                       (mapcar 'delete-annotation (annotations-at myend))
845                       (let ((ext (make-extent mystart myend))
846                             (ant (make-annotation glyph myend 'text)))
847                         ;; set text extent params
848                         (set-extent-property ext 'end-open t)
849                         (set-extent-property ext 'start-open t)
850                         (set-extent-property ext 'invisible t)))
851                   (delete-region mystart myend)))
852             (delete-region mystart myend))))
853       (widen))
854     (goto-char p)))
855
856 (defun gnus-group-icon-create-glyph (substring pixmap)
857   "Create a glyph for insertion into a group line."
858   (or
859    (cdr-safe (assoc pixmap gnus-group-icon-cache))
860    (let* ((glyph (make-glyph
861                   (list
862                    (cons 'x
863                          (expand-file-name pixmap gnus-xmas-glyph-directory))
864                    (cons 'mswindows
865                          (expand-file-name pixmap gnus-xmas-glyph-directory))
866                    (cons 'tty substring)))))
867      (setq gnus-group-icon-cache
868            (cons (cons pixmap glyph) gnus-group-icon-cache))
869      (set-glyph-face glyph 'default)
870      glyph)))
871
872 (defun gnus-xmas-mailing-list-menu-add ()
873   (gnus-xmas-menu-add mailing-list
874                       gnus-mailing-list-menu))
875
876 (defun gnus-xmas-image-type-available-p (type)
877   (and window-system
878        (featurep (if (eq type 'pbm) 'xbm type))))
879
880 (defun gnus-xmas-create-image (file &optional type data-p &rest props)
881   (let ((type (if type
882                   (symbol-name type)
883                 (car (last (split-string file "[.]")))))
884         (face (plist-get props :face))
885         glyph)
886     (when (equal type "pbm")
887       (with-temp-buffer
888         (if data-p
889             (insert file)
890           (insert-file-contents-literally file))
891         (shell-command-on-region (point-min) (point-max)
892                                  "ppmtoxpm 2>/dev/null" t)
893         (setq file (buffer-string)
894               type "xpm"
895               data-p t)))
896     (setq glyph
897           (if (equal type "xbm")
898               (make-glyph (list (cons 'x file)))
899             (with-temp-buffer
900               (if data-p
901                   (insert file)
902                 (insert-file-contents-literally file))
903               (make-glyph
904                (vector
905                 (or (intern type)
906                     (mm-image-type-from-buffer))
907                 :data (buffer-string))))))
908     (when face
909       (set-glyph-face glyph face))
910     glyph))
911
912 (defun gnus-xmas-put-image (glyph &optional string category)
913   "Insert STRING, but display GLYPH.
914 Warning: Don't insert text immediately after the image."
915   (let ((begin (point))
916         extent)
917     (if (and (bobp) (not string))
918         (setq string " "))
919     (if string
920         (insert string)
921       (setq begin (1- begin)))
922     (setq extent (make-extent begin (point)))
923     (set-extent-property extent 'gnus-image category)
924     (set-extent-property extent 'duplicable t)
925     (if string
926         (set-extent-property extent 'invisible t))
927     (set-extent-property extent 'end-glyph glyph))
928   glyph)
929
930 (defun gnus-xmas-remove-image (image &optional category)
931   "Remove the image matching IMAGE and CATEGORY found first."
932   (map-extents
933    (lambda (ext unused)
934      (when (equal (extent-end-glyph ext) image)
935        (set-extent-property ext 'invisible nil)
936        (set-extent-property ext 'end-glyph nil)
937        t))
938    nil nil nil nil nil 'gnus-image category))
939
940 (defun gnus-xmas-assq-delete-all (key alist)
941   (let ((elem nil))
942     (while (setq elem (assq key alist))
943       (setq alist (delq elem alist)))
944     alist))
945
946 (provide 'gnus-xmas)
947
948 ;;; arch-tag: 4e84de3f-ea0a-4ee3-bfeb-e03d46fcacef
949 ;;; gnus-xmas.el ends here