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