Synch with Gnus.
[elisp/gnus.git-] / lisp / gnus-ems.el
1 ;;; gnus-ems.el --- functions for making Semi-gnus work under different Emacsen
2 ;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000
3 ;;        Free Software Foundation, Inc.
4
5 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
6 ;;         Tatsuya Ichikawa <t-ichi@niagara.shiojiri.ne.jp>
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., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25
26 ;;; Commentary:
27
28 ;;; Code:
29
30 (eval-when-compile (require 'cl))
31
32 ;;; Function aliases later to be redefined for XEmacs usage.
33
34 (eval-and-compile
35   (defvar gnus-xemacs (featurep 'xemacs)
36     "Non-nil if running under XEmacs."))
37
38 (defvar gnus-mouse-2 [mouse-2])
39 (defvar gnus-down-mouse-3 [down-mouse-3])
40 (defvar gnus-down-mouse-2 [down-mouse-2])
41 (defvar gnus-widget-button-keymap nil)
42 (defvar gnus-mode-line-modified
43   (if (or gnus-xemacs
44           (< emacs-major-version 20))
45       '("--**-" . "-----")
46     '("**" "--")))
47
48 (eval-and-compile
49   (autoload 'gnus-xmas-define "gnus-xmas")
50   (autoload 'gnus-xmas-redefine "gnus-xmas")
51   (autoload 'appt-select-lowest-window "appt"))
52
53 (or (fboundp 'mail-file-babyl-p)
54     (fset 'mail-file-babyl-p 'rmail-file-p))
55
56 ;;; Mule functions.
57
58 (eval-and-compile
59   (if gnus-xemacs
60       (gnus-xmas-define)
61     (defvar gnus-mouse-face-prop 'mouse-face
62       "Property used for highlighting mouse regions.")))
63
64 (eval-and-compile
65   (cond
66    ((not window-system)
67     (let ((funcs '(mouse-set-point set-face-foreground
68                                    set-face-background x-popup-menu)))
69       (while funcs
70         (unless (fboundp (car funcs))
71           (defalias (car funcs) 'ignore))
72         (setq funcs (cdr funcs)))))))
73
74 (eval-and-compile
75   (let ((case-fold-search t))
76     (cond
77      ((string-match "windows-nt\\|os/2\\|emx\\|cygwin32"
78                     (symbol-name system-type))
79       (setq nnheader-file-name-translation-alist
80             (append nnheader-file-name-translation-alist
81                     (mapcar (lambda (c) (cons c ?_))
82                             '(?: ?* ?\" ?< ?> ??))
83                     '((?+ . ?-))))))))
84
85 (defvar gnus-tmp-unread)
86 (defvar gnus-tmp-replied)
87 (defvar gnus-tmp-score-char)
88 (defvar gnus-tmp-indentation)
89 (defvar gnus-tmp-opening-bracket)
90 (defvar gnus-tmp-lines)
91 (defvar gnus-tmp-name)
92 (defvar gnus-tmp-closing-bracket)
93 (defvar gnus-tmp-subject-or-nil)
94
95 (defun gnus-ems-redefine ()
96   (cond
97    (gnus-xemacs
98     (gnus-xmas-redefine))
99
100    ((featurep 'mule)
101     ;; Mule and new Emacs definitions
102
103     ;; [Note] Now there are three kinds of mule implementations,
104     ;; original MULE, XEmacs/mule and Emacs 20+ including
105     ;; MULE features.  Unfortunately these API are different.  In
106     ;; particular, Emacs (including original MULE) and XEmacs are
107     ;; quite different.  However, this version of Gnus doesn't support
108     ;; anything other than XEmacs 20+ and Emacs 20.3+.
109
110     ;; Predicates to check are following:
111     ;; (boundp 'MULE) is t only if MULE (original; anything older than
112     ;;                     Mule 2.3) is running.
113     ;; (featurep 'mule) is t when every mule variants are running.
114
115     ;; It is possible to detect XEmacs/mule by (featurep 'mule) and
116     ;; checking `emacs-version'.  In this case, the implementation for
117     ;; XEmacs/mule may be shareable between XEmacs and XEmacs/mule.
118
119     (defvar gnus-summary-display-table nil
120       "Display table used in summary mode buffers.")
121
122     (if (fboundp 'truncate-string-to-width)
123         (fset 'gnus-truncate-string 'truncate-string-to-width)
124       (fset 'gnus-truncate-string 'truncate-string))
125
126     (when (boundp 'gnus-check-before-posting)
127       (setq gnus-check-before-posting
128             (delq 'long-lines
129                   (delq 'control-chars gnus-check-before-posting))))
130     ))
131   (when (featurep 'mule)
132     (defun gnus-tilde-max-form (el max-width)
133       "Return a form that limits EL to MAX-WIDTH."
134       (let ((max (abs max-width)))
135         (if (symbolp el)
136             (if (< max-width 0)
137                 `(let ((width (string-width ,el)))
138                    (gnus-truncate-string ,el width (- width ,max)))
139               `(gnus-truncate-string ,el ,max))
140           (if (< max-width 0)
141               `(let* ((val (eval ,el))
142                       (width (string-width val)))
143                  (gnus-truncate-string val width (- width ,max)))
144             `(let ((val (eval ,el)))
145                (gnus-truncate-string val ,max))))))
146
147     (defun gnus-tilde-cut-form (el cut-width)
148       "Return a form that cuts CUT-WIDTH off of EL."
149       (let ((cut (abs cut-width)))
150         (if (symbolp el)
151             (if (< cut-width 0)
152                 `(gnus-truncate-string ,el (- (string-width ,el) ,cut))
153               `(gnus-truncate-string ,el (string-width ,el) ,cut))
154           (if (< cut-width 0)
155               `(let ((val (eval ,el)))
156                  (gnus-truncate-string val (- (string-width val) ,cut)))
157             `(let ((val (eval ,el)))
158                (gnus-truncate-string val (string-width val) ,cut))))))
159     ))
160
161 (defun gnus-region-active-p ()
162   "Say whether the region is active."
163   (and (boundp 'transient-mark-mode)
164        transient-mark-mode
165        (boundp 'mark-active)
166        mark-active))
167
168 (if (fboundp 'add-minor-mode)
169     (defalias 'gnus-add-minor-mode 'add-minor-mode)
170   (defun gnus-add-minor-mode (mode name map &rest rest)
171     (set (make-local-variable mode) t)
172     (unless (assq mode minor-mode-alist)
173       (push `(,mode ,name) minor-mode-alist))
174     (unless (assq mode minor-mode-map-alist)
175       (push (cons mode map)
176             minor-mode-map-alist))))
177
178 (defun gnus-x-splash ()
179   "Show a splash screen using a pixmap in the current buffer."
180   (let ((dir (nnheader-find-etc-directory "gnus"))
181         pixmap file height beg i)
182     (save-excursion
183       (switch-to-buffer (gnus-get-buffer-create gnus-group-buffer))
184       (let ((buffer-read-only nil))
185         (erase-buffer)
186         (when (and dir
187                    (file-exists-p (setq file
188                                         (expand-file-name "x-splash" dir))))
189           (with-temp-buffer
190             (insert-file-contents-as-binary file)
191             (goto-char (point-min))
192             (ignore-errors
193               (setq pixmap (read (current-buffer))))))
194         (when pixmap
195           (make-face 'gnus-splash)
196           (setq height (/ (car pixmap) (frame-char-height))
197                 width (/ (cadr pixmap) (frame-char-width)))
198           (set-face-foreground 'gnus-splash "Brown")
199           (set-face-stipple 'gnus-splash pixmap)
200           (insert-char ?\n (* (/ (window-height) 2 height) height))
201           (setq i height)
202           (while (> i 0)
203             (insert-char ?\  (* (/ (window-width) 2 width) width))
204             (setq beg (point))
205             (insert-char ?\  width)
206             (set-text-properties beg (point) '(face gnus-splash))
207             (insert ?\n)
208             (decf i))
209           (goto-char (point-min))
210           (sit-for 0))))))
211
212 (defvar gnus-article-xface-ring-internal nil
213   "Cache for face data.")
214
215 ;; Worth customizing?
216 (defvar gnus-article-xface-ring-size 6
217   "Length of the ring used for `gnus-article-xface-ring-internal'.")
218
219 (defun gnus-article-display-xface (beg end)
220   "Display an XFace header from between BEG and END in the current article.
221 Requires support for images in your Emacs and the external programs
222 `uncompface', `icontopbm' and `ppmtoxbm'.  On a GNU/Linux system these
223 might be in packages with names like `compface' or `faces-xface' and
224 `netpbm' or `libgr-progs', for instance.
225
226 This function is for Emacs 21+.  See `gnus-xmas-article-display-xface'
227 for XEmacs."
228   ;; It might be worth converting uncompface's output in Lisp.
229
230   (unless gnus-article-xface-ring-internal ; Only load ring when needed.
231     (setq gnus-article-xface-ring-internal
232           (make-ring gnus-article-xface-ring-size)))
233   (save-excursion
234     (let* ((cur (current-buffer))
235            (data (buffer-substring beg end))
236            (image (cdr-safe (assoc data (ring-elements
237                                          gnus-article-xface-ring-internal)))))
238       (when (if (fboundp 'display-graphic-p)
239                 (display-graphic-p))
240         (unless image
241           (let ((coding-system-for-read 'binary)
242                 (coding-system-for-write 'binary))
243             (with-temp-buffer
244               (insert data)
245               (and (eq 0 (call-process-region (point-min) (point-max)
246                                               "uncompface"
247                                               'delete '(t nil)))
248                    (goto-char (point-min))
249                    (progn (insert "/* Width=48, Height=48 */\n") t)
250                    (eq 0 (call-process-region (point-min) (point-max)
251                                               "icontopbm"
252                                               'delete '(t nil)))
253                    (eq 0 (call-process-region (point-min) (point-max)
254                                               "pbmtoxbm"
255                                               'delete '(t nil)))
256                    ;; Miles Bader says that faces don't look right as
257                    ;; light on dark.
258                    (if (eq 'dark (cdr-safe (assq 'background-mode
259                                                  (frame-parameters))))
260                        (setq image (create-image (buffer-string) 'xbm t
261                                                  :ascent 'center
262                                                  :foreground "black"
263                                                  :background "white"))
264                      (setq image (create-image (buffer-string) 'xbm t
265                                                :ascent 'center))))))
266           (ring-insert gnus-article-xface-ring-internal (cons data image))))
267       (when image
268         (goto-char (point-min))
269         (re-search-forward "^From:" nil 'move)
270         (insert-image image)))))
271
272 (defun-maybe assoc-ignore-case (key alist)
273   "Like `assoc', but assumes KEY is a string and ignores case when comparing."
274   (setq key (downcase key))
275   (let (element)
276     (while (and alist (not element))
277       (if (equal key (downcase (car (car alist))))
278           (setq element (car alist)))
279       (setq alist (cdr alist)))
280     element))
281
282 \f
283 ;;; Language support staffs.
284
285 (defvar-maybe current-language-environment "English"
286   "The language environment.")
287
288 (defvar-maybe language-info-alist nil
289   "Alist of language environment definitions.")
290
291 (defun-maybe get-language-info (lang-env key)
292   "Return information listed under KEY for language environment LANG-ENV."
293   (if (symbolp lang-env)
294       (setq lang-env (symbol-name lang-env)))
295   (let ((lang-slot (assoc-ignore-case lang-env language-info-alist)))
296     (if lang-slot
297         (cdr (assq key (cdr lang-slot))))))
298
299 (defun-maybe set-language-info (lang-env key info)
300   "Modify part of the definition of language environment LANG-ENV."
301   (if (symbolp lang-env)
302       (setq lang-env (symbol-name lang-env)))
303   (let (lang-slot key-slot)
304     (setq lang-slot (assoc lang-env language-info-alist))
305     (if (null lang-slot)                ; If no slot for the language, add it.
306         (setq lang-slot (list lang-env)
307               language-info-alist (cons lang-slot language-info-alist)))
308     (setq key-slot (assq key lang-slot))
309     (if (null key-slot)                 ; If no slot for the key, add it.
310         (progn
311           (setq key-slot (list key))
312           (setcdr lang-slot (cons key-slot (cdr lang-slot)))))
313     (setcdr key-slot info)))
314
315 (provide 'gnus-ems)
316
317 ;; Local Variables:
318 ;; byte-compile-warnings: '(redefine callargs)
319 ;; End:
320
321 ;;; gnus-ems.el ends here