aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Aspinall2002-12-11 11:13:58 +0000
committerDavid Aspinall2002-12-11 11:13:58 +0000
commit43bc9dedf86b765f7b436da546dbf2339a84242e (patch)
tree4db60d9f3a73c80d09c177ec341e19cb83d188c4
parent569606f27f38a62686664b687880ee3ade5c0291 (diff)
X-Symbol version 4.45 beta
-rw-r--r--x-symbol/lisp/x-symbol-image.el792
1 files changed, 792 insertions, 0 deletions
diff --git a/x-symbol/lisp/x-symbol-image.el b/x-symbol/lisp/x-symbol-image.el
new file mode 100644
index 00000000..33ea94b2
--- /dev/null
+++ b/x-symbol/lisp/x-symbol-image.el
@@ -0,0 +1,792 @@
+;;; x-symbol-image.el --- display glyphs at the end of image insertion commands
+
+;; Copyright (C) 1997-1999, 2001 Free Software Foundation, Inc.
+;;
+;; Author: Christoph Wedler <wedler@users.sourceforge.net>
+;; Maintainer: (Please use `M-x x-symbol-package-bug' to contact the maintainer)
+;; Version: 4.4.X
+;; Keywords: WYSIWYG, LaTeX, HTML, wp, math, internationalization
+;; X-URL: http://x-symbol.sourceforge.net/
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; If you want to use package x-symbol, please visit the URL (use
+;; \\[x-symbol-package-web]) and read the info (use \\[x-symbol-package-info]).
+
+;; This file requires file `x-symbol.el which does some initialization. Thus,
+;; do not put any `defcustom' commands into this file. If you think some
+;; variables in this files should be customized, move them to file
+;; `x-symbol-vars.el'.
+
+;;; Code:
+
+(provide 'x-symbol-image)
+(require 'x-symbol)
+(eval-when-compile (require 'cl))
+
+
+
+;;;;##########################################################################
+;;;; Main code
+;;;;##########################################################################
+
+
+(defvar x-symbol-image-process-buffer "*x-symbol-image conversion*"
+ "Name of the image conversion buffer.")
+
+(defvar x-symbol-image-process-name "Image-Conversion"
+ "Name of the image conversion process.")
+
+(defvar x-symbol-image-highlight-map
+ (let ((map (make-sparse-keymap)))
+ ;; CW: two independend `when's or one `if' or 2*2 `when's ?
+ (if (lookup-key global-map [(button2)])
+ (progn
+ ;; XEmacs bindings
+ (define-key map [(button2)] 'x-symbol-image-mouse-editor)
+ (define-key map [(button3)] 'x-symbol-image-highlight-menu))
+ ;; Emacs bindings
+ (define-key map [(mouse-2)] 'x-symbol-image-mouse-editor)
+ (define-key map [(mouse-3)] 'x-symbol-image-highlight-menu))
+ map)
+ "Keymap for mouse event over image insertion commands.")
+
+
+;;;===========================================================================
+;;; Internal variables
+;;;===========================================================================
+
+(defun x-symbol-image-try-special (image)
+ "Return image for image specification IMAGE or [nothing].
+IMAGE is an element in `x-symbol-image-special-glyphs'."
+ (or (and x-symbol-image-data-directory
+ (x-symbol-create-image
+ (expand-file-name (car image) x-symbol-image-data-directory)
+ (cdr image)))
+ (and (featurep 'xemacs) [nothing])))
+
+(defvar x-symbol-image-broken-image
+ (x-symbol-image-try-special (first x-symbol-image-special-glyphs))
+ "Image to represent broken image files.
+IMAGE is an element in `x-symbol-image-special-glyphs'.")
+
+(defvar x-symbol-image-create-image
+ (x-symbol-image-try-special (second x-symbol-image-special-glyphs))
+ "Image to represent image files which are currently converted.
+IMAGE is an element in `x-symbol-image-special-glyphs'.")
+
+(defvar x-symbol-image-design-glyph
+ (x-symbol-make-glyph (x-symbol-image-try-special
+ (third x-symbol-image-special-glyphs)))
+ "Glyph to represent image files still to be designed.
+IMAGE is an element in `x-symbol-image-special-glyphs'.")
+
+(defvar x-symbol-image-locked-glyph
+ (x-symbol-make-glyph (x-symbol-image-try-special
+ (fourth x-symbol-image-special-glyphs)))
+ "Glyph to represent locked image files.
+IMAGE is an element in `x-symbol-image-special-glyphs'.")
+
+(defvar x-symbol-image-remote-glyph
+ (x-symbol-make-glyph (x-symbol-image-try-special
+ (fifth x-symbol-image-special-glyphs)))
+ "Glyph to represent \"remote\" image files.
+IMAGE is an element in `x-symbol-image-special-glyphs'.")
+
+(defvar x-symbol-image-junk-glyph
+ (x-symbol-make-glyph (x-symbol-image-try-special
+ (sixth x-symbol-image-special-glyphs)))
+ "Glyph to represent \"junk\" image files.
+IMAGE is an element in `x-symbol-image-special-glyphs'.")
+
+(defvar x-symbol-image-buffer-extents nil
+ "Internal variable. Extents for image commands in the current buffer.")
+(make-variable-buffer-local 'x-symbol-image-buffer-extents)
+(put 'x-symbol-image-buffer-extents 'permanent-local t)
+
+(defvar x-symbol-image-memory-cache nil
+ "Internal variable. Buffer local memory cache for glyphs.
+Each element has the form (FILE FULL . GLYPH) where FILE is the given
+image file name, FULL is the full file name and GLYPH is the glyph used
+for that image file. If GLYPH is nil, it is not created yet. See also
+`x-symbol-image-use-remote'. The memory cache is flushed with
+`x-symbol-image-init-memory-cache'.")
+
+(make-variable-buffer-local 'x-symbol-image-memory-cache)
+
+(defvar x-symbol-image-all-recursive-dirs nil
+ "Internal variable. Used by `x-symbol-image-searchpath'.")
+(defvar x-symbol-image-all-dirs nil
+ "Internal variable. Used by `x-symbol-image-searchpath'.")
+
+
+;;;===========================================================================
+;;; Main functions
+;;;===========================================================================
+
+;;;###autoload
+(defun x-symbol-image-parse-buffer (&optional update-cache)
+ "*Parse buffer to find image insertion commands.
+Parse buffer to display glyphs at the end of image insertion commands.
+Image files are converted to \"image cache files\" with images not
+bigger than `x-symbol-image-max-width' and `x-symbol-image-max-height'
+having a image format XEmacs understands. The conversion is done by a
+program determined by `x-symbol-image-converter', currently you need
+\"convert\" from ImageMagick. To make this conversion fast, we use
+asynchronous processes and two cache hierarchies:
+
+ * Memory cache (`x-symbol-image-memory-cache'): buffer-local alist
+ FILE.eps -> GLYPH, see also `x-symbol-image-use-remote'.
+ * File cache: the image cache file, mentioned above, are kept, see also
+ `x-symbol-image-update-cache', which is shadowed by a non-nil
+ UPDATE-CACHE and `x-symbol-image-cache-directories'.
+
+When the mouse is over an image insertion command, it is highlighted.
+button2 starts an image editor, see `x-symbol-image-editor-alist'.
+button3 pops up a menu, see `x-symbol-image-menu'.
+
+The image insertion commands are recognized by keywords in the language
+access `x-symbol-image-keywords' whose value have the form
+ (IMAGE-REGEXP KEYWORD ...)
+IMAGE-REGEXP should match all images files and is used to initialize the
+buffer local memory cache, see `x-symbol-image-init-memory-cache'.
+
+Each KEYWORD looks like (REGEXP [FUNCTION] ARG...). Image insertion
+commands matched by REGEXP are highlighted. FUNCTION, which defaults to
+`x-symbol-image-default-file-name', is called with ARGs to get the file
+name of the corresponding image file. If FUNCTION returns nil, the
+command is not highlighted.
+
+Relative image file names are expanded in the directory returned by the
+function in the language access `x-symbol-master-directory', value nil
+means function `default-directory'. Implicitly relative image file
+names are searched in a search path, see `x-symbol-image-use-remote'."
+ (interactive)
+ (save-excursion
+ (x-symbol-image-init-memory-cache)
+ (x-symbol-image-parse-region (point-min) (point-max) update-cache)))
+
+;;;###autoload
+(defun x-symbol-image-after-change-function (beg end old-len)
+ ;; checkdoc-params: (beg end old-len)
+ "Function in `after-change-functions' for image insertion commands."
+ (if x-symbol-language
+ (save-excursion
+ (save-match-data
+ (let ((zmacs-region-stays (and (boundp 'zmacs-region-stays)
+ zmacs-region-stays)))
+ (goto-char end)
+ (end-of-line)
+ (setq end (point))
+ (goto-char beg)
+ (beginning-of-line)
+ (x-symbol-image-parse-region (point) end))))))
+
+;; Idea from package bib-cite: OK with a relatively small number of extents
+;;;###autoload
+(defun x-symbol-image-delete-extents (beg end)
+ "Delete x-symbol image extents covering text between BEG and END.
+See also `x-symbol-image-buffer-extents'."
+ (let ((extents x-symbol-image-buffer-extents) extent)
+ (setq x-symbol-image-buffer-extents nil)
+ (if (featurep 'xemacs)
+ (while extents
+ (setq extent (pop extents))
+ (if (or (extent-detached-p extent)
+ (and (> (extent-end-position extent) beg)
+ ;; If (beginning-of-line 2) instead (end-of-line) in
+ ;; `x-symbol-image-after-change-function': (> end...)
+ (>= end (extent-start-position extent))))
+ (delete-extent extent)
+ (push extent x-symbol-image-buffer-extents)))
+ (while extents
+ (setq extent (pop extents))
+ (if (and (> (overlay-end extent) beg)
+ ;; If (beginning-of-line 2) instead (end-of-line) in
+ ;; `x-symbol-image-after-change-function': (> end...)
+ (>= end (overlay-start extent)))
+ (delete-overlay extent)
+ (push extent x-symbol-image-buffer-extents))))))
+
+
+;;;===========================================================================
+;;; Main parse function
+;;;===========================================================================
+
+(defun x-symbol-image-parse-region (beg end &optional update-cache)
+ "*Parse region between BEG and END to find image insertion commands.
+If optional UPDATE-CACHE is non-nil, use it instead of
+`x-symbol-image-update-cache' to determine whether to create new image
+cache files."
+ (or update-cache (setq update-cache x-symbol-image-update-cache))
+ (let ((modified (buffer-modified-p))
+ (buffer-undo-list t) (inhibit-read-only t)
+ buffer-file-name buffer-file-truename)
+ (unwind-protect
+ (let (;;(case-fold-search nil)
+ (keywords (cdr (x-symbol-language-value
+ 'x-symbol-image-keywords)))
+ (cached-dirs (cons nil
+ (mapcar 'file-name-as-directory
+ (x-symbol-language-value
+ 'x-symbol-image-cached-dirs))))
+ (master-dir (x-symbol-language-value 'x-symbol-master-directory))
+ keyword matcher file-fn file-args
+ file extent cache-elem extent-beg extent-end)
+ (if master-dir (funcall master-dir))
+ (x-symbol-image-delete-extents beg end)
+ (while keywords
+ (setq keyword (pop keywords)
+ matcher (car keyword)
+ file-fn #'x-symbol-image-default-file-name
+ file-args (cdr keyword))
+ (if (functionp (car file-args))
+ (setq file-fn (pop file-args)))
+ (goto-char beg)
+ (while (setq extent-end (re-search-forward matcher end t))
+ (setq extent-beg (match-beginning 0))
+ (when (setq file (apply file-fn file-args))
+ (if (featurep 'xemacs)
+ (progn
+ (push (setq extent (make-extent extent-beg extent-end))
+ x-symbol-image-buffer-extents)
+ (set-extent-property extent 'start-open t)
+ (set-extent-property extent 'highlight t)
+ (set-extent-property extent 'x-symbol-image-file file)
+ (set-extent-property extent 'help-echo
+ 'x-symbol-image-help-echo)
+ (set-extent-property extent 'keymap
+ x-symbol-image-highlight-map)
+ (set-extent-end-glyph
+ extent
+ (if (member (file-name-directory file) cached-dirs)
+ (if (setq cache-elem
+ (cdr (assoc file x-symbol-image-memory-cache)))
+ (or (cdr cache-elem)
+ (setcdr cache-elem (x-symbol-image-create-glyph
+ (car cache-elem) update-cache
+ (stringp
+ x-symbol-image-temp-name))))
+ x-symbol-image-design-glyph)
+ (if x-symbol-image-use-remote
+ (x-symbol-image-create-glyph
+ (expand-file-name file master-dir) update-cache)
+ x-symbol-image-remote-glyph))))
+ (push (setq extent (make-overlay extent-beg extent-end))
+ x-symbol-image-buffer-extents)
+ (overlay-put extent 'mouse-face 'highlight)
+ (overlay-put extent 'x-symbol-image-file file)
+ (overlay-put extent 'help-echo 'x-symbol-image-help-echo)
+ (overlay-put extent 'keymap x-symbol-image-highlight-map)
+ (overlay-put
+ extent 'after-string
+ (if (member (file-name-directory file) cached-dirs)
+ (if (setq cache-elem
+ (cdr (assoc file x-symbol-image-memory-cache)))
+ (or (cdr cache-elem)
+ (setcdr cache-elem (x-symbol-image-create-glyph
+ (car cache-elem) update-cache
+ (stringp
+ x-symbol-image-temp-name))))
+ x-symbol-image-design-glyph)
+ (if x-symbol-image-use-remote
+ (x-symbol-image-create-glyph
+ (expand-file-name file master-dir) update-cache)
+ x-symbol-image-remote-glyph))))))))
+ (and (not modified) (buffer-modified-p) (set-buffer-modified-p nil)))))
+
+(defun x-symbol-image-default-file-name (num &optional regexp extension)
+ "Return image file name for last match.
+Default FUNCTION in language access `x-symbol-image-keywords', see
+`x-symbol-image-parse-buffer'. Return text matched by the NUMth regexp
+group of the corresponding keyword regexp. If REGEXP is non-nil and the
+file name does not match REGEXP, add EXTENSION to the file name."
+ (let ((file (match-string num)))
+ (if regexp
+ (if (string-match regexp file) file (concat file extension))
+ file)))
+
+
+;;;===========================================================================
+;;; Create an (empty) memory cache
+;;;===========================================================================
+
+(defun x-symbol-image-init-memory-cache ()
+ "Create an empty memory cache.
+Scan all directories in the searchpath and all subdirectories in the
+language access `x-symbol-image-cached-dirs' for files matched by
+IMAGE-REGEXP in the language access `x-symbol-image-keywords' to build
+`x-symbol-image-memory-cache' where all GLYPHs are nil."
+ (let* ((master-dir (funcall (x-symbol-language-value
+ 'x-symbol-master-directory)))
+ (cached-dirs (x-symbol-language-value 'x-symbol-image-cached-dirs))
+ (path (x-symbol-image-searchpath master-dir))
+ (suffixes (car (x-symbol-language-value 'x-symbol-image-keywords)))
+ implicit-dirs
+ dirs dir)
+ (setq x-symbol-image-memory-cache nil)
+ (while cached-dirs
+ (setq dir (file-name-as-directory (pop cached-dirs)))
+ (if (or (string-match x-symbol-image-explicitly-relative-regexp dir)
+ (file-name-absolute-p dir))
+ (x-symbol-image-init-memory-cache-1
+ (and master-dir (file-name-as-directory master-dir)) dir suffixes)
+ (push dir implicit-dirs)))
+ (while path
+ (setq dir (pop path)
+ dirs implicit-dirs)
+ (while dirs
+ (x-symbol-image-init-memory-cache-1 dir (pop dirs) suffixes))
+ (x-symbol-image-init-memory-cache-1 dir nil suffixes))))
+
+(defun x-symbol-image-init-memory-cache-1 (root subdir suffixes)
+ "Initialize memory cache for image files in ROOT/SUBDIR with SUFFIXES."
+ (let* ((dir (if subdir (expand-file-name subdir root) root))
+ (files (and (file-accessible-directory-p dir)
+ (file-readable-p dir)
+ (x-symbol-directory-files dir nil suffixes t t)))
+ file)
+ (while files
+ (setq file (pop files))
+ (push (list (concat subdir file) (expand-file-name file dir))
+ x-symbol-image-memory-cache))))
+
+(defun x-symbol-image-searchpath (master-dir)
+ "Return language dependent image searchpath in reverse order.
+Uses the language accesses `x-symbol-image-searchpath' and
+`x-symbol-master-directory' (via argument MASTER-DIR). Include all
+subdirectories of elements in the image searchpath ending with \"//\",
+except symbolic links if `x-symbol-image-searchpath-follow-symlink' is
+nil."
+ (let ((path (or (x-symbol-language-value 'x-symbol-image-searchpath)
+ '("./")))
+ (dirs nil)
+ dir truename slashslash)
+ (setq x-symbol-image-all-dirs nil)
+ (while path
+ (setq dir (pop path)
+ slashslash (and (> (length dir) 1)
+ (string-equal (substring dir -2) "//"))
+ dir (file-name-as-directory
+ (expand-file-name (if slashslash (substring dir 0 -1) dir)
+ master-dir))
+ truename (file-truename dir))
+ (unless (member truename x-symbol-image-all-dirs)
+ (push truename x-symbol-image-all-dirs)
+ (push dir dirs))
+ (when slashslash
+ (setq x-symbol-image-all-recursive-dirs (list truename))
+ (setq dirs (x-symbol-image-searchpath-1 dir dirs))))
+ dirs))
+
+(defun x-symbol-image-searchpath-1 (dir dirs)
+ "Add subdirectories of DIR to DIRS and return result."
+ (and (file-accessible-directory-p dir)
+ (file-readable-p dir)
+ (let ((subs (x-symbol-directory-files dir t "[^.]" nil 'dirs))
+ truename)
+ (while subs
+ (setq dir (pop subs))
+ (when (or x-symbol-image-searchpath-follow-symlink
+ (not (file-symlink-p dir)))
+ (setq dir (file-name-as-directory dir)
+ truename (file-truename dir))
+ (unless (member truename x-symbol-image-all-recursive-dirs)
+ (push truename x-symbol-image-all-recursive-dirs)
+ (if (member truename x-symbol-image-all-dirs)
+ (setq dirs (x-symbol-image-searchpath-1 dir dirs))
+ (push truename x-symbol-image-all-dirs)
+ (setq dirs
+ (x-symbol-image-searchpath-1 dir (cons dir dirs)))))))))
+ dirs)
+
+
+;;;===========================================================================
+;;; Highlighting the image commands: main functions
+;;;===========================================================================
+
+(defun x-symbol-image-mouse-editor (event)
+ (interactive "e")
+ (let ((file (x-symbol-image-event-file event)))
+ (if file
+ (x-symbol-image-editor file (event-buffer event))
+ (error "No image file to edit"))))
+
+;;;###autoload
+(defun x-symbol-image-editor (file &optional buffer)
+ "Start image editor for the image file FILE used in BUFFER.
+If BUFFER is nil, just return string describing the command. See
+`x-symbol-image-editor-alist' and `x-symbol-image-current-marker'."
+ (interactive (list (read-file-name "Edit image design file for: "
+ (funcall (x-symbol-language-value
+ 'x-symbol-master-directory)))
+ (current-buffer)))
+ (let ((result (and file (x-symbol-match-in-alist
+ file x-symbol-image-editor-alist))))
+ (and file buffer (setq file (x-symbol-image-active-file file buffer)))
+ (if (and result file)
+ (if (functionp (car result))
+ (apply (car result) file buffer (cdr result))
+ (setq result
+ (format (car result)
+ (if (cadr result)
+ (x-symbol-image-file-name file (cadr result))
+ file)))
+ (if buffer
+ (let ((default-directory (file-name-directory file)))
+ (shell-command result))
+ result))
+ (if buffer
+ (if file
+ (error "Do not know which image editor to use for %S" file)
+ (error "Cannot use highlighted file"))))))
+
+(defun x-symbol-image-highlight-menu (event)
+ ;; checkdoc-params: (event)
+ "Popup menu over the highlighted image insertion command.
+See `x-symbol-image-menu' and `x-symbol-image-editor-alist'."
+ (interactive "e")
+ (let ((file (x-symbol-image-event-file event)))
+ (if file
+ (popup-menu (x-symbol-image-active-file file (event-buffer event) t)))))
+
+(defun x-symbol-image-help-echo (extent &optional object pos)
+ "Return help echo for the EXTENT of the image insertion command.
+See variable `x-symbol-image-help-echo'."
+ (if object (setq extent object)) ; Emacs
+ (x-symbol-fancy-string
+ (cons (format (car x-symbol-image-help-echo)
+ (x-symbol-image-editor (extent-property extent
+ 'x-symbol-image-file)))
+ (cdr x-symbol-image-help-echo))))
+
+
+;;;===========================================================================
+;;; Get files which the image editor could work on
+;;;===========================================================================
+
+(defun x-symbol-image-file-name (file &optional extension dir)
+ "Return a name deduced from the image file name FILE.
+Use EXTENSION as the new extension. If DIR is non-nil, replace
+directory part by DIR. With a non-nil `x-symbol-image-scale-method',
+the scale factor is deleted in the file name."
+ (and file
+ (let ((edit (file-name-sans-extension (file-name-nondirectory file))))
+ (or dir (setq dir (file-name-directory file)))
+ (setq file
+ (concat (if (and x-symbol-image-scale-method
+ (string-match x-symbol-image-scale-method edit))
+ (substring edit 0 (match-beginning 0))
+ edit)
+ extension))
+ (if dir (expand-file-name file dir) file))))
+
+(defun x-symbol-image-event-file (event)
+ "Return image file name at position of mouse event EVENT."
+ (and event
+ (setq event (extent-at (if (featurep 'xemacs)
+ (or (event-point event)
+ (1- (event-closest-point event)))
+ (posn-point (event-end event)))
+ (event-buffer event)
+ 'x-symbol-image-file))
+ (extent-property event 'x-symbol-image-file)))
+
+(defun x-symbol-image-active-file (file buffer &optional menup)
+ ;; checkdoc-params: (event)
+ "Return the full name of the active image file FILE in BUFFER.
+If MENUP is non-nil, return menu specified by `x-symbol-image-menu'
+instead."
+ (save-excursion
+ (set-buffer buffer)
+ (let ((master-dir (funcall (x-symbol-language-value
+ 'x-symbol-master-directory)))
+ path)
+ (if (or (string-match x-symbol-image-explicitly-relative-regexp file)
+ (file-name-absolute-p file))
+ (setq path (list (expand-file-name (file-name-directory file)
+ master-dir))
+ file (file-name-nondirectory file))
+ (setq path (x-symbol-image-searchpath master-dir)))
+ (if menup
+ (let ((menu (cdr x-symbol-image-menu))
+ dir full exists)
+ (while path
+ (setq dir (pop path)
+ full (expand-file-name file dir)
+ exists (file-exists-p full))
+ (push (vector (if (featurep 'xemacs)
+ (abbreviate-file-name dir t)
+ (abbreviate-file-name dir))
+ (list 'x-symbol-image-editor full buffer)
+ :active (if exists
+ (file-readable-p full)
+ (file-writable-p full))
+ :keys (and exists x-symbol-image-current-marker))
+ menu))
+ (cons (format (car x-symbol-image-menu)
+ (x-symbol-image-editor file))
+ menu))
+ (let (result full)
+ (setq path (nreverse path))
+ (while path
+ (setq full (expand-file-name file (pop path)))
+ (if (file-readable-p full)
+ (setq result full
+ path nil)
+ (or result
+ (file-exists-p full) ; i.e., not readable
+ (if (file-writable-p full) (setq result full)))))
+ result)))))
+
+
+
+;;;;##########################################################################
+;;;; Glyph creation via processes
+;;;;##########################################################################
+
+
+;; A stack is better than a FIFO queue since editing the current line should
+;; have the highest priority.
+(defvar x-symbol-image-process-stack nil
+ "Internal variable. Stack of image conversion tasks.
+Each element looks like the value of `x-symbol-image-process-elem'.")
+
+(defvar x-symbol-image-process-elem nil
+ "Internal variable. Current image conversion task element.
+It has the form (CACHE GLYPH COMMAND TEMP). CACHE is the name of the
+image cache file, GLYPH is the glyph whose image will be defined by the
+finished image cache file. COMMAND is the command which starts the
+process creating CACHE, see `x-symbol-image-converter'. If TEMP is
+non-nil, the image cache file will be deleted directly after its
+usage.")
+
+
+;;;===========================================================================
+;;; Main function for glyph creation
+;;;===========================================================================
+
+(defun x-symbol-image-create-glyph (file update-cache &optional temp)
+ "Return a glyph for the image file FILE.
+Start a process to create a new image cache file. If UPDATE-CACHE is
+non-nil, use it instead of `x-symbol-image-update-cache' to determine
+whether this is really necessary. If optional TEMP is non-nil, allow
+the use of temporary cache files."
+ (let ((infile (condition-case nil
+ (file-truename file)
+ (error nil)))
+ outfile elem)
+ (cond ((null infile) x-symbol-image-locked-glyph)
+ ((null (file-readable-p infile))
+ (if (and (null (file-exists-p infile))
+ (file-writable-p infile))
+ x-symbol-image-design-glyph
+ x-symbol-image-locked-glyph))
+ ((null x-symbol-image-converter) x-symbol-image-junk-glyph)
+ ((null (setq outfile
+ (x-symbol-image-cache-name
+ infile
+ ;; TODO: temp image files don't work with Emacs
+ (and temp (featurep 'xemacs) temp))))
+ x-symbol-image-junk-glyph)
+ ((and (stringp outfile)
+ (null (file-writable-p outfile)))
+ x-symbol-image-junk-glyph)
+ ((and (equal outfile (car x-symbol-image-process-elem))
+ (get-process x-symbol-image-process-name))
+ (cadr x-symbol-image-process-elem))
+ ((setq elem (assoc outfile x-symbol-image-process-stack))
+ (prog1 (cadr elem)
+ (x-symbol-image-process-stack)))
+ (t
+ (let* ((ofile (if (symbolp outfile)
+ (concat x-symbol-image-temp-name
+ (cadr x-symbol-image-converter))
+ outfile))
+ (image (and (null (symbolp outfile))
+ (x-symbol-create-image
+ ofile (car x-symbol-image-converter))))
+ (glyph (x-symbol-make-glyph
+ (or image x-symbol-image-create-image))))
+ (when (or (null image)
+ (eq update-cache t)
+ (and update-cache
+ (file-newer-than-file-p infile outfile)))
+ (push (list ofile glyph
+ (list (cddr x-symbol-image-converter) infile ofile)
+ (symbolp outfile))
+ x-symbol-image-process-stack)
+ (x-symbol-image-process-stack))
+ glyph)))))
+
+
+;;;===========================================================================
+;;; Compute name of file cache
+;;;===========================================================================
+
+(defun x-symbol-image-cache-name (infile temp)
+ "Return the name of the image cache file for the image file INFILE.
+The directory part is determined by `x-symbol-image-cache-directories'.
+INFILE must be a fully expanded file name, the extension by
+`x-symbol-image-converter'. Return value nil means, do not convert the
+image, use `x-symbol-image-junk-glyph' instead. If optional TEMP is
+non-nil, allow the use of temporary cache files, in this case, t would
+be returned."
+ (let* ((case-fold-search (eq system-type 'vax-vms))
+ (indir (file-name-directory infile))
+ (outdir (x-symbol-match-in-alist indir x-symbol-image-cache-directories
+ nil t)))
+ (if (symbolp outdir) (and outdir temp)
+ (if (or (file-directory-p (setq outdir (expand-file-name outdir indir)))
+ (condition-case nil
+ (progn (make-directory outdir t) t)
+ (error nil)))
+ (x-symbol-image-file-name
+ infile (cadr x-symbol-image-converter) outdir)))))
+
+
+;;;===========================================================================
+;;; Process handling
+;;;===========================================================================
+
+(defun x-symbol-image-process-stack ()
+ "Handle next task in variable `x-symbol-image-process-stack'."
+ (if x-symbol-image-process-stack
+ (let ((process (get-process x-symbol-image-process-name)))
+ (unless (and process (eq (process-status process) 'run))
+ (if process (delete-process process))
+ (setq x-symbol-image-process-elem
+ (pop x-symbol-image-process-stack))
+ (setq process (apply (caaddr x-symbol-image-process-elem)
+ (cdaddr x-symbol-image-process-elem)))
+ (set-process-sentinel process 'x-symbol-image-process-sentinel)
+ ))))
+
+(defun x-symbol-image-convert-file (infile)
+ "Put prefix before INFILE if necessary for \"convert\".
+Uses `x-symbol-image-convert-file-alist'. Also put postfix \"[0]\"
+after INFILE to just use the first part of a multi-part image."
+ (concat (x-symbol-match-in-alist infile x-symbol-image-convert-file-alist)
+ infile
+ "[0]"))
+
+(defun x-symbol-image-start-convert-mono (infile outfile)
+ "Start process convert INFILE to monochrome OUTFILE.
+Used as value in `x-symbol-image-converter'."
+ (start-process x-symbol-image-process-name
+ (get-buffer-create x-symbol-image-process-buffer)
+ x-symbol-image-convert-program "+matte"
+ "-geometry" (format "%dx%d>" x-symbol-image-max-width
+ x-symbol-image-max-height)
+ "-threshold" "190" "-monochrome"
+ (x-symbol-image-convert-file infile) outfile))
+
+(defun x-symbol-image-start-convert-color (infile outfile)
+ "Start process convert INFILE to OUTFILE with restricted colors.
+Used as value in `x-symbol-image-converter'."
+ (start-process x-symbol-image-process-name
+ (get-buffer-create x-symbol-image-process-buffer)
+ x-symbol-image-convert-program "+matte"
+ "-geometry" (format "%dx%d>" x-symbol-image-max-width
+ x-symbol-image-max-height)
+ "-sharpen" "58" "-colors" "4"
+ (x-symbol-image-convert-file infile) outfile))
+
+(defun x-symbol-image-start-convert-truecolor (infile outfile)
+ "Start process convert INFILE to OUTFILE using colors.
+Used as value in `x-symbol-image-converter'."
+ (start-process x-symbol-image-process-name
+ (get-buffer-create x-symbol-image-process-buffer)
+ x-symbol-image-convert-program "+matte"
+ "-geometry" (format "%dx%d>" x-symbol-image-max-width
+ x-symbol-image-max-height)
+ (x-symbol-image-convert-file infile) outfile))
+
+(defun x-symbol-image-start-convert-mswindows (infile outfile)
+ "Start process convert INFILE to OUTFILE using colors.
+Used as value in `x-symbol-image-converter'."
+ (start-process x-symbol-image-process-name
+ (get-buffer-create x-symbol-image-process-buffer)
+ x-symbol-image-convert-program "+matte"
+ "-geometry" (format "%dx%d>" x-symbol-image-max-width
+ x-symbol-image-max-height)
+ ;; for some reason [0] at the end of the file name does not
+ ;; work under ms-windows
+ (concat (x-symbol-match-in-alist
+ infile x-symbol-image-convert-file-alist)
+ infile)
+ outfile))
+
+(defun x-symbol-image-start-convert-colormap (infile outfile)
+ "Start process convert INFILE to OUTFILE using a colormap.
+Produce OUTFILE with `x-symbol-image-convert-colormap' or monochrome
+OUTFILE if `x-symbol-image-convert-mono-regexp' matches INFILE. Used as
+value in `x-symbol-image-converter'."
+ (if (or (and x-symbol-image-convert-mono-regexp
+ (string-match x-symbol-image-convert-mono-regexp infile))
+ (null x-symbol-image-convert-colormap))
+ (x-symbol-image-start-convert-mono infile outfile)
+ (start-process x-symbol-image-process-name
+ (get-buffer-create x-symbol-image-process-buffer)
+ x-symbol-image-convert-program "+matte"
+ "-geometry" (format "%dx%d>" x-symbol-image-max-width
+ x-symbol-image-max-height)
+ "-map" x-symbol-image-convert-colormap
+ (x-symbol-image-convert-file infile) outfile)))
+
+(defun x-symbol-image-process-sentinel (process event)
+ "Set glyph image after process PROCESS has finished with value EVENT.
+Also look for more tasks in variable `x-symbol-image-process-stack'."
+ (if (memq (process-status process) '(signal exit))
+ (let ((buffer (process-buffer process)))
+ (if (buffer-live-p buffer)
+ ;; Don't follow info files, use some code from compile.el instead:
+ ;; do not let cursor movement influence output placement
+ (save-excursion
+ (set-buffer buffer)
+ (goto-char (point-max))
+ (insert-before-markers (current-time-string) ": "
+ (process-name process) " " event
+ "\"" (car x-symbol-image-process-elem)
+ (if (eq (process-status process) 'exit)
+ "\" created\n"
+ "\" failed\n"))))
+ (x-symbol-set-glyph-image
+ (cadr x-symbol-image-process-elem)
+ (or (and (eq (process-status process) 'exit)
+ (x-symbol-create-image (car x-symbol-image-process-elem)
+ (car x-symbol-image-converter)))
+ x-symbol-image-broken-image))
+ ;; TODO: in Emacs, we need `clear-image-cache' for some reason, in
+ ;; older XEmacsen, we did need something, but it wasn't really
+ ;; important, and I haven't noticed it anymore...
+ (or (featurep 'xemacs)
+ (and (boundp 'x-symbol-emacs-after-create-image-function)
+ (functionp x-symbol-emacs-after-create-image-function)
+ (funcall x-symbol-emacs-after-create-image-function)))
+;;; (redisplay-frame nil t) ; doesn't work
+;;; (sit-for 0) ; does that work?
+ (if (cadddr x-symbol-image-process-elem)
+ (condition-case nil
+ (delete-file (car x-symbol-image-process-elem))
+ (error nil)))
+ (setq x-symbol-image-process-elem nil)
+ (delete-process process)
+ (x-symbol-image-process-stack))))
+
+;;; Local IspellPersDict: .ispell_xsymb
+;;; x-symbol-image.el ends here