XEmacs 21.2-b2
[chise/xemacs-chise.git.1] / src / glyphs.c
1 /* Generic glyph/image implementation + display tables
2    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Tinker Systems
4    Copyright (C) 1995, 1996 Ben Wing
5    Copyright (C) 1995 Sun Microsystems
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not in FSF. */
25
26 /* Written by Ben Wing and Chuck Thompson */
27
28 #include <config.h>
29 #include "lisp.h"
30
31 #include "buffer.h"
32 #include "device.h"
33 #include "elhash.h"
34 #include "faces.h"
35 #include "frame.h"
36 #include "insdel.h"
37 #include "glyphs.h"
38 #include "objects.h"
39 #include "redisplay.h"
40 #include "window.h"
41
42 #ifdef HAVE_XPM
43 #include <X11/xpm.h>
44 #endif
45
46 Lisp_Object Qimage_conversion_error;
47
48 Lisp_Object Qglyphp, Qcontrib_p, Qbaseline;
49 Lisp_Object Qbuffer_glyph_p, Qpointer_glyph_p, Qicon_glyph_p;
50 Lisp_Object Qnothing_image_instance_p, Qtext_image_instance_p;
51 Lisp_Object Qmono_pixmap_image_instance_p;
52 Lisp_Object Qcolor_pixmap_image_instance_p;
53 Lisp_Object Qpointer_image_instance_p;
54 Lisp_Object Qsubwindow_image_instance_p;
55 Lisp_Object Qconst_glyph_variable;
56 Lisp_Object Qmono_pixmap, Qcolor_pixmap, Qsubwindow;
57 Lisp_Object Q_file, Q_data, Q_face;
58 Lisp_Object Qformatted_string;
59
60 Lisp_Object Vcurrent_display_table;
61 Lisp_Object Vtruncation_glyph, Vcontinuation_glyph, Voctal_escape_glyph;
62 Lisp_Object Vcontrol_arrow_glyph, Vinvisible_text_glyph, Vhscroll_glyph;
63 Lisp_Object Vxemacs_logo;
64 Lisp_Object Vthe_nothing_vector;
65 Lisp_Object Vimage_instantiator_format_list;
66 Lisp_Object Vimage_instance_type_list;
67 Lisp_Object Vglyph_type_list;
68
69 DEFINE_IMAGE_INSTANTIATOR_FORMAT (nothing);
70 DEFINE_IMAGE_INSTANTIATOR_FORMAT (inherit);
71 DEFINE_IMAGE_INSTANTIATOR_FORMAT (string);
72 DEFINE_IMAGE_INSTANTIATOR_FORMAT (formatted_string);
73
74 #ifdef HAVE_WINDOW_SYSTEM
75 DEFINE_IMAGE_INSTANTIATOR_FORMAT (xbm);
76 Lisp_Object Qxbm;
77
78 Lisp_Object Q_mask_file, Q_mask_data, Q_hotspot_x, Q_hotspot_y;
79 Lisp_Object Q_foreground, Q_background;
80 #ifndef BitmapSuccess
81 #define BitmapSuccess           0
82 #define BitmapOpenFailed        1
83 #define BitmapFileInvalid       2
84 #define BitmapNoMemory          3
85 #endif
86 #endif
87
88 #ifdef HAVE_XPM
89 DEFINE_IMAGE_INSTANTIATOR_FORMAT (xpm);
90 Lisp_Object Qxpm;
91 Lisp_Object Q_color_symbols;
92 #endif
93
94 typedef struct image_instantiator_format_entry image_instantiator_format_entry;
95 struct image_instantiator_format_entry
96 {
97   Lisp_Object symbol;
98   struct image_instantiator_methods *meths;
99 };
100
101 typedef struct
102 {
103   Dynarr_declare (struct image_instantiator_format_entry);
104 } image_instantiator_format_entry_dynarr;
105
106 image_instantiator_format_entry_dynarr *
107   the_image_instantiator_format_entry_dynarr;
108
109 static Lisp_Object allocate_image_instance (Lisp_Object device);
110 static void image_validate (Lisp_Object instantiator);
111 static void glyph_property_was_changed (Lisp_Object glyph,
112                                         Lisp_Object property,
113                                         Lisp_Object locale);
114 EXFUN (Fimage_instance_type, 1);
115 EXFUN (Fglyph_type, 1);
116
117 \f
118 /****************************************************************************
119  *                          Image Instantiators                             *
120  ****************************************************************************/
121
122 static struct image_instantiator_methods *
123 decode_image_instantiator_format (Lisp_Object format, Error_behavior errb)
124 {
125   int i;
126
127   if (!SYMBOLP (format))
128     {
129       if (ERRB_EQ (errb, ERROR_ME))
130         CHECK_SYMBOL (format);
131       return 0;
132     }
133
134   for (i = 0; i < Dynarr_length (the_image_instantiator_format_entry_dynarr);
135        i++)
136     {
137       if (EQ (format,
138               Dynarr_at (the_image_instantiator_format_entry_dynarr, i).
139               symbol))
140         return Dynarr_at (the_image_instantiator_format_entry_dynarr, i).meths;
141     }
142
143   maybe_signal_simple_error ("Invalid image-instantiator format", format,
144                              Qimage, errb);
145
146   return 0;
147 }
148
149 static int
150 valid_image_instantiator_format_p (Lisp_Object format)
151 {
152   return (decode_image_instantiator_format (format, ERROR_ME_NOT) != 0);
153 }
154
155 DEFUN ("valid-image-instantiator-format-p", Fvalid_image_instantiator_format_p,
156        1, 1, 0, /*
157 Given an IMAGE-INSTANTIATOR-FORMAT, return non-nil if it is valid.
158 Valid formats are some subset of 'nothing, 'string, 'formatted-string,
159 'xpm, 'xbm, 'xface, 'gif, 'jpeg, 'png, 'tiff, 'cursor-font, 'font,
160 'autodetect, and 'subwindow, depending on how XEmacs was compiled.
161 */
162        (image_instantiator_format))
163 {
164   return valid_image_instantiator_format_p (image_instantiator_format) ?
165     Qt : Qnil;
166 }
167
168 DEFUN ("image-instantiator-format-list", Fimage_instantiator_format_list,
169        0, 0, 0, /*
170 Return a list of valid image-instantiator formats.
171 */
172        ())
173 {
174   return Fcopy_sequence (Vimage_instantiator_format_list);
175 }
176
177 void
178 add_entry_to_image_instantiator_format_list (Lisp_Object symbol,
179                                              struct
180                                              image_instantiator_methods *meths)
181 {
182   struct image_instantiator_format_entry entry;
183
184   entry.symbol = symbol;
185   entry.meths = meths;
186   Dynarr_add (the_image_instantiator_format_entry_dynarr, entry);
187   Vimage_instantiator_format_list =
188     Fcons (symbol, Vimage_instantiator_format_list);
189 }
190
191 static Lisp_Object *
192 get_image_conversion_list (Lisp_Object console_type)
193 {
194   return &decode_console_type (console_type, ERROR_ME)->image_conversion_list;
195 }
196
197 DEFUN ("set-console-type-image-conversion-list", Fset_console_type_image_conversion_list,
198        2, 2, 0, /*
199 Set the image-conversion-list for consoles of the given TYPE.
200 The image-conversion-list specifies how image instantiators that
201 are strings should be interpreted.  Each element of the list should be
202 a list of two elements (a regular expression string and a vector) or
203 a list of three elements (the preceding two plus an integer index into
204 the vector).  The string is converted to the vector associated with the
205 first matching regular expression.  If a vector index is specified, the
206 string itself is substituted into that position in the vector.
207
208 Note: The conversion above is applied when the image instantiator is
209 added to an image specifier, not when the specifier is actually
210 instantiated.  Therefore, changing the image-conversion-list only affects
211 newly-added instantiators.  Existing instantiators in glyphs and image
212 specifiers will not be affected.
213 */
214        (console_type, list))
215 {
216   Lisp_Object tail;
217   Lisp_Object *imlist = get_image_conversion_list (console_type);
218
219   /* Check the list to make sure that it only has valid entries. */
220
221   EXTERNAL_LIST_LOOP (tail, list)
222     {
223       Lisp_Object mapping = XCAR (tail);
224
225       /* Mapping form should be (STRING VECTOR) or (STRING VECTOR INTEGER) */
226       if (!CONSP (mapping) ||
227           !CONSP (XCDR (mapping)) ||
228           (!NILP (XCDR (XCDR (mapping))) &&
229            (!CONSP (XCDR (XCDR (mapping))) ||
230             !NILP (XCDR (XCDR (XCDR (mapping)))))))
231         signal_simple_error ("Invalid mapping form", mapping);
232       else
233         {
234           Lisp_Object exp = XCAR (mapping);
235           Lisp_Object typevec = XCAR (XCDR (mapping));
236           Lisp_Object pos = Qnil;
237           Lisp_Object newvec;
238           struct gcpro gcpro1;
239
240           CHECK_STRING (exp);
241           CHECK_VECTOR (typevec);
242           if (!NILP (XCDR (XCDR (mapping))))
243             {
244               pos = XCAR (XCDR (XCDR (mapping)));
245               CHECK_INT (pos);
246               if (XINT (pos) < 0 ||
247                   XINT (pos) >= XVECTOR_LENGTH (typevec))
248                 args_out_of_range_3
249                   (pos, Qzero, make_int (XVECTOR_LENGTH (typevec) - 1));
250             }
251
252           newvec = Fcopy_sequence (typevec);
253           if (INTP (pos))
254             XVECTOR_DATA (newvec)[XINT (pos)] = exp;
255           GCPRO1 (newvec);
256           image_validate (newvec);
257           UNGCPRO;
258         }
259     }
260
261   *imlist = Fcopy_tree (list, Qt);
262   return list;
263 }
264
265 DEFUN ("console-type-image-conversion-list", Fconsole_type_image_conversion_list,
266        1, 1, 0, /*
267 Return the image-conversion-list for devices of the given TYPE.
268 The image-conversion-list specifies how to interpret image string
269 instantiators for the specified console type.  See
270 `set-console-type-image-conversion-list' for a description of its syntax.
271 */
272        (console_type))
273 {
274   return Fcopy_tree (*get_image_conversion_list (console_type), Qt);
275 }
276
277 /* Process a string instantiator according to the image-conversion-list for
278    CONSOLE_TYPE.  Returns a vector. */
279
280 static Lisp_Object
281 process_image_string_instantiator (Lisp_Object data,
282                                    Lisp_Object console_type,
283                                    int dest_mask)
284 {
285   Lisp_Object tail;
286
287   LIST_LOOP (tail, *get_image_conversion_list (console_type))
288     {
289       Lisp_Object mapping = XCAR (tail);
290       Lisp_Object exp = XCAR (mapping);
291       Lisp_Object typevec = XCAR (XCDR (mapping));
292
293       /* if the result is of a type that can't be instantiated
294          (e.g. a string when we're dealing with a pointer glyph),
295          skip it. */
296       if (!(dest_mask &
297             IIFORMAT_METH (decode_image_instantiator_format
298                            (XVECTOR_DATA (typevec)[0], ERROR_ME),
299                            possible_dest_types, ())))
300         continue;
301       if (fast_string_match (exp, 0, data, 0, -1, 0, ERROR_ME, 0) >= 0)
302         {
303           if (!NILP (XCDR (XCDR (mapping))))
304             {
305               int pos = XINT (XCAR (XCDR (XCDR (mapping))));
306               Lisp_Object newvec = Fcopy_sequence (typevec);
307               XVECTOR_DATA (newvec)[pos] = data;
308               return newvec;
309             }
310           else
311             return typevec;
312         }
313     }
314
315   /* Oh well. */
316   signal_simple_error ("Unable to interpret glyph instantiator",
317                        data);
318
319   return Qnil;
320 }
321
322 Lisp_Object
323 find_keyword_in_vector_or_given (Lisp_Object vector, Lisp_Object keyword,
324                                  Lisp_Object default_)
325 {
326   Lisp_Object *elt;
327   int instantiator_len;
328
329   elt = XVECTOR_DATA (vector);
330   instantiator_len = XVECTOR_LENGTH (vector);
331
332   elt++;
333   instantiator_len--;
334
335   while (instantiator_len > 0)
336     {
337       if (EQ (elt[0], keyword))
338         return elt[1];
339       elt += 2;
340       instantiator_len -= 2;
341     }
342
343   return default_;
344 }
345
346 Lisp_Object
347 find_keyword_in_vector (Lisp_Object vector, Lisp_Object keyword)
348 {
349   return find_keyword_in_vector_or_given (vector, keyword, Qnil);
350 }
351
352 void
353 check_valid_string (Lisp_Object data)
354 {
355   CHECK_STRING (data);
356 }
357
358 static void
359 check_valid_face (Lisp_Object data)
360 {
361   Fget_face (data);
362 }
363
364 void
365 check_valid_int (Lisp_Object data)
366 {
367   CHECK_INT (data);
368 }
369
370 void
371 file_or_data_must_be_present (Lisp_Object instantiator)
372 {
373   if (NILP (find_keyword_in_vector (instantiator, Q_file)) &&
374       NILP (find_keyword_in_vector (instantiator, Q_data)))
375     signal_simple_error ("Must supply either :file or :data",
376                          instantiator);
377 }
378
379 void
380 data_must_be_present (Lisp_Object instantiator)
381 {
382   if (NILP (find_keyword_in_vector (instantiator, Q_data)))
383     signal_simple_error ("Must supply :data", instantiator);
384 }
385
386 static void
387 face_must_be_present (Lisp_Object instantiator)
388 {
389   if (NILP (find_keyword_in_vector (instantiator, Q_face)))
390     signal_simple_error ("Must supply :face", instantiator);
391 }
392
393 /* utility function useful in retrieving data from a file. */
394
395 Lisp_Object
396 make_string_from_file (Lisp_Object file)
397 {
398   /* This function can call lisp */
399   int count = specpdl_depth ();
400   Lisp_Object temp_buffer;
401   struct gcpro gcpro1;
402   Lisp_Object data;
403
404   specbind (Qinhibit_quit, Qt);
405   record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
406   temp_buffer = Fget_buffer_create (build_string (" *pixmap conversion*"));
407   GCPRO1 (temp_buffer);
408   set_buffer_internal (XBUFFER (temp_buffer));
409   Ferase_buffer (Qnil);
410   specbind (intern ("format-alist"), Qnil);
411   Finsert_file_contents_internal (file, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil);
412   data = Fbuffer_substring (Qnil, Qnil, Qnil);
413   unbind_to (count, Qnil);
414   UNGCPRO;
415   return data;
416 }
417
418 /* The following two functions are provided to make it easier for
419    the normalize methods to work with keyword-value vectors.
420    Hash tables are kind of heavyweight for this purpose.
421    (If vectors were resizable, we could avoid this problem;
422    but they're not.) An alternative approach that might be
423    more efficient but require more work is to use a type of
424    assoc-Dynarr and provide primitives for deleting elements out
425    of it. (However, you'd also have to add an unwind-protect
426    to make sure the Dynarr got freed in case of an error in
427    the normalization process.) */
428
429 Lisp_Object
430 tagged_vector_to_alist (Lisp_Object vector)
431 {
432   Lisp_Object *elt = XVECTOR_DATA (vector);
433   int len = XVECTOR_LENGTH (vector);
434   Lisp_Object result = Qnil;
435
436   assert (len & 1);
437   for (len -= 2; len >= 1; len -= 2)
438     result = Fcons (Fcons (elt[len], elt[len+1]), result);
439
440   return result;
441 }
442
443 Lisp_Object
444 alist_to_tagged_vector (Lisp_Object tag, Lisp_Object alist)
445 {
446   int len = 1 + 2 * XINT (Flength (alist));
447   Lisp_Object *elt = alloca_array (Lisp_Object, len);
448   int i;
449   Lisp_Object rest;
450
451   i = 0;
452   elt[i++] = tag;
453   LIST_LOOP (rest, alist)
454     {
455       Lisp_Object pair = XCAR (rest);
456       elt[i] = XCAR (pair);
457       elt[i+1] = XCDR (pair);
458       i += 2;
459     }
460
461   return Fvector (len, elt);
462 }
463
464 static Lisp_Object
465 normalize_image_instantiator (Lisp_Object instantiator,
466                               Lisp_Object contype,
467                               Lisp_Object dest_mask)
468 {
469   if (IMAGE_INSTANCEP (instantiator))
470     return instantiator;
471
472   if (STRINGP (instantiator))
473     instantiator = process_image_string_instantiator (instantiator, contype,
474                                                       XINT (dest_mask));
475
476   assert (VECTORP (instantiator));
477   /* We have to always store the actual pixmap data and not the
478      filename even though this is a potential memory pig.  We have to
479      do this because it is quite possible that we will need to
480      instantiate a new instance of the pixmap and the file will no
481      longer exist (e.g. w3 pixmaps are almost always from temporary
482      files). */
483   {
484     struct image_instantiator_methods * meths =
485       decode_image_instantiator_format (XVECTOR_DATA (instantiator)[0],
486                                         ERROR_ME);
487     return IIFORMAT_METH_OR_GIVEN (meths, normalize,
488                                    (instantiator, contype),
489                                    instantiator);
490   }
491 }
492
493 static Lisp_Object
494 instantiate_image_instantiator (Lisp_Object device, Lisp_Object domain,
495                                 Lisp_Object instantiator,
496                                 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
497                                 int dest_mask)
498 {
499   Lisp_Object ii = allocate_image_instance (device);
500   struct image_instantiator_methods *meths;
501   struct gcpro gcpro1;
502
503   GCPRO1 (ii);
504   meths = decode_image_instantiator_format (XVECTOR_DATA (instantiator)[0],
505                                             ERROR_ME);
506   if (!HAS_IIFORMAT_METH_P (meths, instantiate))
507     signal_simple_error
508       ("Don't know how to instantiate this image instantiator?",
509        instantiator);
510   IIFORMAT_METH (meths, instantiate, (ii, instantiator, pointer_fg,
511                                       pointer_bg, dest_mask, domain));
512   UNGCPRO;
513
514   return ii;
515 }
516
517 \f
518 /****************************************************************************
519  *                          Image-Instance Object                           *
520  ****************************************************************************/
521
522 Lisp_Object Qimage_instancep;
523
524 static Lisp_Object
525 mark_image_instance (Lisp_Object obj, void (*markobj) (Lisp_Object))
526 {
527   struct Lisp_Image_Instance *i = XIMAGE_INSTANCE (obj);
528
529   (markobj) (i->name);
530   switch (IMAGE_INSTANCE_TYPE (i))
531     {
532     case IMAGE_TEXT:
533       (markobj) (IMAGE_INSTANCE_TEXT_STRING (i));
534       break;
535     case IMAGE_MONO_PIXMAP:
536     case IMAGE_COLOR_PIXMAP:
537       (markobj) (IMAGE_INSTANCE_PIXMAP_FILENAME (i));
538       (markobj) (IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (i));
539       (markobj) (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (i));
540       (markobj) (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (i));
541       (markobj) (IMAGE_INSTANCE_PIXMAP_FG (i));
542       (markobj) (IMAGE_INSTANCE_PIXMAP_BG (i));
543       break;
544     case IMAGE_SUBWINDOW:
545       /* #### implement me */
546       break;
547     default:
548       break;
549     }
550
551   MAYBE_DEVMETH (XDEVICE (i->device), mark_image_instance, (i, markobj));
552
553   return i->device;
554 }
555
556 static void
557 print_image_instance (Lisp_Object obj, Lisp_Object printcharfun,
558                       int escapeflag)
559 {
560   char buf[100];
561   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (obj);
562
563   if (print_readably)
564     error ("printing unreadable object #<image-instance 0x%x>",
565            ii->header.uid);
566   write_c_string ("#<image-instance (", printcharfun);
567   print_internal (Fimage_instance_type (obj), printcharfun, 0);
568   write_c_string (") ", printcharfun);
569   if (!NILP (ii->name))
570     {
571       print_internal (ii->name, printcharfun, 1);
572       write_c_string (" ", printcharfun);
573     }
574   write_c_string ("on ", printcharfun);
575   print_internal (ii->device, printcharfun, 0);
576   write_c_string (" ", printcharfun);
577   switch (IMAGE_INSTANCE_TYPE (ii))
578     {
579     case IMAGE_NOTHING:
580       break;
581
582     case IMAGE_TEXT:
583       print_internal (IMAGE_INSTANCE_TEXT_STRING (ii), printcharfun, 1);
584       break;
585
586     case IMAGE_MONO_PIXMAP:
587     case IMAGE_COLOR_PIXMAP:
588     case IMAGE_POINTER:
589       if (STRINGP (IMAGE_INSTANCE_PIXMAP_FILENAME (ii)))
590         {
591           char *s;
592           Lisp_Object filename = IMAGE_INSTANCE_PIXMAP_FILENAME (ii);
593           s = strrchr ((char *) XSTRING_DATA (filename), '/');
594           if (s)
595             print_internal (build_string (s + 1), printcharfun, 1);
596           else
597             print_internal (filename, printcharfun, 1);
598         }
599       if (IMAGE_INSTANCE_PIXMAP_DEPTH (ii) > 1)
600         sprintf (buf, " %dx%dx%d", IMAGE_INSTANCE_PIXMAP_WIDTH (ii),
601                  IMAGE_INSTANCE_PIXMAP_HEIGHT (ii),
602                  IMAGE_INSTANCE_PIXMAP_DEPTH (ii));
603       else
604         sprintf (buf, " %dx%d", IMAGE_INSTANCE_PIXMAP_WIDTH (ii),
605                  IMAGE_INSTANCE_PIXMAP_HEIGHT (ii));
606       write_c_string (buf, printcharfun);
607       if (!NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)) ||
608           !NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)))
609         {
610           write_c_string (" @", printcharfun);
611           if (!NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)))
612             {
613               long_to_string (buf, XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)));
614               write_c_string (buf, printcharfun);
615             }
616           else
617             write_c_string ("??", printcharfun);
618           write_c_string (",", printcharfun);
619           if (!NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)))
620             {
621               long_to_string (buf, XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)));
622               write_c_string (buf, printcharfun);
623             }
624           else
625             write_c_string ("??", printcharfun);
626         }
627       if (!NILP (IMAGE_INSTANCE_PIXMAP_FG (ii)) ||
628           !NILP (IMAGE_INSTANCE_PIXMAP_BG (ii)))
629         {
630           write_c_string (" (", printcharfun);
631           if (!NILP (IMAGE_INSTANCE_PIXMAP_FG (ii)))
632             {
633               print_internal
634                 (XCOLOR_INSTANCE
635                  (IMAGE_INSTANCE_PIXMAP_FG (ii))->name, printcharfun, 0);
636             }
637           write_c_string ("/", printcharfun);
638           if (!NILP (IMAGE_INSTANCE_PIXMAP_BG (ii)))
639             {
640               print_internal
641                 (XCOLOR_INSTANCE
642                  (IMAGE_INSTANCE_PIXMAP_BG (ii))->name, printcharfun, 0);
643             }
644           write_c_string (")", printcharfun);
645         }
646       break;
647
648     case IMAGE_SUBWINDOW:
649       /* #### implement me */
650       break;
651
652     default:
653       abort ();
654     }
655
656   MAYBE_DEVMETH (XDEVICE (ii->device), print_image_instance,
657                  (ii, printcharfun, escapeflag));
658   sprintf (buf, " 0x%x>", ii->header.uid);
659   write_c_string (buf, printcharfun);
660 }
661
662 static void
663 finalize_image_instance (void *header, int for_disksave)
664 {
665   struct Lisp_Image_Instance *i = (struct Lisp_Image_Instance *) header;
666
667   if (IMAGE_INSTANCE_TYPE (i) == IMAGE_NOTHING)
668     /* objects like this exist at dump time, so don't bomb out. */
669     return;
670   if (for_disksave) finalose (i);
671
672   MAYBE_DEVMETH (XDEVICE (i->device), finalize_image_instance, (i));
673 }
674
675 static int
676 image_instance_equal (Lisp_Object o1, Lisp_Object o2, int depth)
677 {
678   struct Lisp_Image_Instance *i1 = XIMAGE_INSTANCE (o1);
679   struct Lisp_Image_Instance *i2 = XIMAGE_INSTANCE (o2);
680   struct device *d1 = XDEVICE (i1->device);
681   struct device *d2 = XDEVICE (i2->device);
682
683   if (d1 != d2)
684     return 0;
685   if (IMAGE_INSTANCE_TYPE (i1) != IMAGE_INSTANCE_TYPE (i2))
686     return 0;
687   if (!internal_equal (IMAGE_INSTANCE_NAME (i1), IMAGE_INSTANCE_NAME (i2),
688                        depth + 1))
689     return 0;
690
691   switch (IMAGE_INSTANCE_TYPE (i1))
692     {
693     case IMAGE_NOTHING:
694       break;
695
696     case IMAGE_TEXT:
697       if (!internal_equal (IMAGE_INSTANCE_TEXT_STRING (i1),
698                            IMAGE_INSTANCE_TEXT_STRING (i2),
699                            depth + 1))
700         return 0;
701       break;
702
703     case IMAGE_MONO_PIXMAP:
704     case IMAGE_COLOR_PIXMAP:
705     case IMAGE_POINTER:
706       if (!(IMAGE_INSTANCE_PIXMAP_WIDTH (i1) ==
707             IMAGE_INSTANCE_PIXMAP_WIDTH (i2) &&
708             IMAGE_INSTANCE_PIXMAP_HEIGHT (i1) ==
709             IMAGE_INSTANCE_PIXMAP_HEIGHT (i2) &&
710             IMAGE_INSTANCE_PIXMAP_DEPTH (i1) ==
711             IMAGE_INSTANCE_PIXMAP_DEPTH (i2) &&
712             EQ (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (i1),
713                 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (i2)) &&
714             EQ (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (i1),
715                 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (i2)) &&
716             internal_equal (IMAGE_INSTANCE_PIXMAP_FILENAME (i1),
717                             IMAGE_INSTANCE_PIXMAP_FILENAME (i2),
718                             depth + 1) &&
719             internal_equal (IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (i1),
720                             IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (i2),
721                             depth + 1)))
722         return 0;
723       break;
724
725     case IMAGE_SUBWINDOW:
726       /* #### implement me */
727       break;
728
729     default:
730       abort ();
731     }
732
733   return DEVMETH_OR_GIVEN (d1, image_instance_equal, (i1, i2, depth), 1);
734 }
735
736 static unsigned long
737 image_instance_hash (Lisp_Object obj, int depth)
738 {
739   struct Lisp_Image_Instance *i = XIMAGE_INSTANCE (obj);
740   struct device *d = XDEVICE (i->device);
741   unsigned long hash = (unsigned long) d;
742
743   switch (IMAGE_INSTANCE_TYPE (i))
744     {
745     case IMAGE_NOTHING:
746       break;
747
748     case IMAGE_TEXT:
749       hash = HASH2 (hash, internal_hash (IMAGE_INSTANCE_TEXT_STRING (i),
750                                          depth + 1));
751       break;
752
753     case IMAGE_MONO_PIXMAP:
754     case IMAGE_COLOR_PIXMAP:
755     case IMAGE_POINTER:
756       hash = HASH5 (hash, IMAGE_INSTANCE_PIXMAP_WIDTH (i),
757                     IMAGE_INSTANCE_PIXMAP_HEIGHT (i),
758                     IMAGE_INSTANCE_PIXMAP_DEPTH (i),
759                     internal_hash (IMAGE_INSTANCE_PIXMAP_FILENAME (i),
760                                    depth + 1));
761       break;
762
763     case IMAGE_SUBWINDOW:
764       /* #### implement me */
765       break;
766
767     default:
768       abort ();
769     }
770
771   return HASH2 (hash, DEVMETH_OR_GIVEN (d, image_instance_hash, (i, depth),
772                                         0));
773 }
774
775 DEFINE_LRECORD_IMPLEMENTATION ("image-instance", image_instance,
776                                mark_image_instance, print_image_instance,
777                                finalize_image_instance, image_instance_equal,
778                                image_instance_hash,
779                                struct Lisp_Image_Instance);
780
781 static Lisp_Object
782 allocate_image_instance (Lisp_Object device)
783 {
784   struct Lisp_Image_Instance *lp =
785     alloc_lcrecord_type (struct Lisp_Image_Instance, lrecord_image_instance);
786   Lisp_Object val;
787
788   zero_lcrecord (lp);
789   lp->device = device;
790   lp->type = IMAGE_NOTHING;
791   lp->name = Qnil;
792   XSETIMAGE_INSTANCE (val, lp);
793   return val;
794 }
795
796 static enum image_instance_type
797 decode_image_instance_type (Lisp_Object type, Error_behavior errb)
798 {
799   if (ERRB_EQ (errb, ERROR_ME))
800     CHECK_SYMBOL (type);
801
802   if (EQ (type, Qnothing))      return IMAGE_NOTHING;
803   if (EQ (type, Qtext))         return IMAGE_TEXT;
804   if (EQ (type, Qmono_pixmap))  return IMAGE_MONO_PIXMAP;
805   if (EQ (type, Qcolor_pixmap)) return IMAGE_COLOR_PIXMAP;
806   if (EQ (type, Qpointer))      return IMAGE_POINTER;
807   if (EQ (type, Qsubwindow))    return IMAGE_SUBWINDOW;
808
809   maybe_signal_simple_error ("Invalid image-instance type", type,
810                              Qimage, errb);
811
812   return IMAGE_UNKNOWN; /* not reached */
813 }
814
815 static Lisp_Object
816 encode_image_instance_type (enum image_instance_type type)
817 {
818   switch (type)
819     {
820     case IMAGE_NOTHING:      return Qnothing;
821     case IMAGE_TEXT:         return Qtext;
822     case IMAGE_MONO_PIXMAP:  return Qmono_pixmap;
823     case IMAGE_COLOR_PIXMAP: return Qcolor_pixmap;
824     case IMAGE_POINTER:      return Qpointer;
825     case IMAGE_SUBWINDOW:    return Qsubwindow;
826     default:
827       abort ();
828     }
829
830   return Qnil; /* not reached */
831 }
832
833 static int
834 image_instance_type_to_mask (enum image_instance_type type)
835 {
836   /* This depends on the fact that enums are assigned consecutive
837      integers starting at 0. (Remember that IMAGE_UNKNOWN is the
838      first enum.) I'm fairly sure this behavior in ANSI-mandated,
839      so there should be no portability problems here. */
840   return (1 << ((int) (type) - 1));
841 }
842
843 static int
844 decode_image_instance_type_list (Lisp_Object list)
845 {
846   Lisp_Object rest;
847   int mask = 0;
848
849   if (NILP (list))
850     return ~0;
851
852   if (!CONSP (list))
853     {
854       enum image_instance_type type =
855         decode_image_instance_type (list, ERROR_ME);
856       return image_instance_type_to_mask (type);
857     }
858
859   EXTERNAL_LIST_LOOP (rest, list)
860     {
861       enum image_instance_type type =
862         decode_image_instance_type (XCAR (rest), ERROR_ME);
863       mask |= image_instance_type_to_mask (type);
864     }
865
866   return mask;
867 }
868
869 static Lisp_Object
870 encode_image_instance_type_list (int mask)
871 {
872   int count = 0;
873   Lisp_Object result = Qnil;
874
875   while (mask)
876     {
877       count++;
878       if (mask & 1)
879         result = Fcons (encode_image_instance_type
880                         ((enum image_instance_type) count), result);
881       mask >>= 1;
882     }
883
884   return Fnreverse (result);
885 }
886
887 DOESNT_RETURN
888 incompatible_image_types (Lisp_Object instantiator, int given_dest_mask,
889                           int desired_dest_mask)
890 {
891   signal_error
892     (Qerror,
893      list2
894      (emacs_doprnt_string_lisp_2
895       ((CONST Bufbyte *)
896        "No compatible image-instance types given: wanted one of %s, got %s",
897        Qnil, -1, 2,
898        encode_image_instance_type_list (desired_dest_mask),
899        encode_image_instance_type_list (given_dest_mask)),
900       instantiator));
901 }
902
903 static int
904 valid_image_instance_type_p (Lisp_Object type)
905 {
906   return !NILP (memq_no_quit (type, Vimage_instance_type_list));
907 }
908
909 DEFUN ("valid-image-instance-type-p", Fvalid_image_instance_type_p, 1, 1, 0, /*
910 Given an IMAGE-INSTANCE-TYPE, return non-nil if it is valid.
911 Valid types are some subset of 'nothing, 'text, 'mono-pixmap, 'color-pixmap,
912 'pointer, and 'subwindow, depending on how XEmacs was compiled.
913 */
914        (image_instance_type))
915 {
916   return valid_image_instance_type_p (image_instance_type) ? Qt : Qnil;
917 }
918
919 DEFUN ("image-instance-type-list", Fimage_instance_type_list, 0, 0, 0, /*
920 Return a list of valid image-instance types.
921 */
922        ())
923 {
924   return Fcopy_sequence (Vimage_instance_type_list);
925 }
926
927 Error_behavior
928 decode_error_behavior_flag (Lisp_Object no_error)
929 {
930   if (NILP (no_error))        return ERROR_ME;
931   else if (EQ (no_error, Qt)) return ERROR_ME_NOT;
932   else                        return ERROR_ME_WARN;
933 }
934
935 Lisp_Object
936 encode_error_behavior_flag (Error_behavior errb)
937 {
938   if (ERRB_EQ (errb, ERROR_ME))
939     return Qnil;
940   else if (ERRB_EQ (errb, ERROR_ME_NOT))
941     return Qt;
942   else
943     {
944       assert (ERRB_EQ (errb, ERROR_ME_WARN));
945       return Qwarning;
946     }
947 }
948
949 static Lisp_Object
950 make_image_instance_1 (Lisp_Object data, Lisp_Object device,
951                        Lisp_Object dest_types)
952 {
953   Lisp_Object ii;
954   struct gcpro gcpro1;
955   int dest_mask;
956
957   XSETDEVICE (device, decode_device (device));
958   /* instantiate_image_instantiator() will abort if given an
959      image instance ... */
960   if (IMAGE_INSTANCEP (data))
961     signal_simple_error ("image instances not allowed here", data);
962   image_validate (data);
963   dest_mask = decode_image_instance_type_list (dest_types);
964   data = normalize_image_instantiator (data, DEVICE_TYPE (XDEVICE (device)),
965                                        make_int (dest_mask));
966   GCPRO1 (data);
967   if (VECTORP (data) && EQ (XVECTOR_DATA (data)[0], Qinherit))
968     signal_simple_error ("inheritance not allowed here", data);
969   ii = instantiate_image_instantiator (device, device, data,
970                                        Qnil, Qnil, dest_mask);
971   RETURN_UNGCPRO (ii);
972 }
973
974 DEFUN ("make-image-instance", Fmake_image_instance, 1, 4, 0, /*
975 Return a new `image-instance' object.
976
977 Image-instance objects encapsulate the way a particular image (pixmap,
978 etc.) is displayed on a particular device.  In most circumstances, you
979 do not need to directly create image instances; use a glyph instead.
980 However, it may occasionally be useful to explicitly create image
981 instances, if you want more control over the instantiation process.
982
983 DATA is an image instantiator, which describes the image; see
984 `image-specifier-p' for a description of the allowed values.
985
986 DEST-TYPES should be a list of allowed image instance types that can
987 be generated.  The recognized image instance types are
988
989 'nothing
990   Nothing is displayed.
991 'text
992   Displayed as text.  The foreground and background colors and the
993   font of the text are specified independent of the pixmap.  Typically
994   these attributes will come from the face of the surrounding text,
995   unless a face is specified for the glyph in which the image appears.
996 'mono-pixmap
997   Displayed as a mono pixmap (a pixmap with only two colors where the
998   foreground and background can be specified independent of the pixmap;
999   typically the pixmap assumes the foreground and background colors of
1000   the text around it, unless a face is specified for the glyph in which
1001   the image appears).
1002 'color-pixmap
1003   Displayed as a color pixmap.
1004 'pointer
1005   Used as the mouse pointer for a window.
1006 'subwindow
1007   A child window that is treated as an image.  This allows (e.g.)
1008   another program to be responsible for drawing into the window.
1009   Not currently implemented.
1010
1011 The DEST-TYPES list is unordered.  If multiple destination types
1012 are possible for a given instantiator, the "most natural" type
1013 for the instantiator's format is chosen. (For XBM, the most natural
1014 types are `mono-pixmap', followed by `color-pixmap', followed by
1015 `pointer'.  For the other normal image formats, the most natural
1016 types are `color-pixmap', followed by `mono-pixmap', followed by
1017 `pointer'.  For the string and formatted-string formats, the most
1018 natural types are `text', followed by `mono-pixmap' (not currently
1019 implemented), followed by `color-pixmap' (not currently implemented).
1020 The other formats can only be instantiated as one type. (If you
1021 want to control more specifically the order of the types into which
1022 an image is instantiated, just call `make-image-instance' repeatedly
1023 until it succeeds, passing less and less preferred destination types
1024 each time.
1025
1026 If DEST-TYPES is omitted, all possible types are allowed.
1027
1028 NO-ERROR controls what happens when the image cannot be generated.
1029 If nil, an error message is generated.  If t, no messages are
1030 generated and this function returns nil.  If anything else, a warning
1031 message is generated and this function returns nil.
1032 */
1033        (data, device, dest_types, no_error))
1034 {
1035   Error_behavior errb = decode_error_behavior_flag (no_error);
1036
1037   return call_with_suspended_errors ((lisp_fn_t) make_image_instance_1,
1038                                      Qnil, Qimage, errb,
1039                                      3, data, device, dest_types);
1040 }
1041
1042 DEFUN ("image-instance-p", Fimage_instance_p, 1, 1, 0, /*
1043 Return non-nil if OBJECT is an image instance.
1044 */
1045        (object))
1046 {
1047   return IMAGE_INSTANCEP (object) ? Qt : Qnil;
1048 }
1049
1050 DEFUN ("image-instance-type", Fimage_instance_type, 1, 1, 0, /*
1051 Return the type of the given image instance.
1052 The return value will be one of 'nothing, 'text, 'mono-pixmap,
1053 'color-pixmap, 'pointer, or 'subwindow.
1054 */
1055        (image_instance))
1056 {
1057   CHECK_IMAGE_INSTANCE (image_instance);
1058   return encode_image_instance_type (XIMAGE_INSTANCE_TYPE (image_instance));
1059 }
1060
1061 DEFUN ("image-instance-name", Fimage_instance_name, 1, 1, 0, /*
1062 Return the name of the given image instance.
1063 */
1064        (image_instance))
1065 {
1066   CHECK_IMAGE_INSTANCE (image_instance);
1067   return XIMAGE_INSTANCE_NAME (image_instance);
1068 }
1069
1070 DEFUN ("image-instance-string", Fimage_instance_string, 1, 1, 0, /*
1071 Return the string of the given image instance.
1072 This will only be non-nil for text image instances.
1073 */
1074        (image_instance))
1075 {
1076   CHECK_IMAGE_INSTANCE (image_instance);
1077   if (XIMAGE_INSTANCE_TYPE (image_instance) == IMAGE_TEXT)
1078     return XIMAGE_INSTANCE_TEXT_STRING (image_instance);
1079   else
1080     return Qnil;
1081 }
1082
1083 DEFUN ("image-instance-file-name", Fimage_instance_file_name, 1, 1, 0, /*
1084 Return the file name from which IMAGE-INSTANCE was read, if known.
1085 */
1086        (image_instance))
1087 {
1088   CHECK_IMAGE_INSTANCE (image_instance);
1089
1090   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1091     {
1092     case IMAGE_MONO_PIXMAP:
1093     case IMAGE_COLOR_PIXMAP:
1094     case IMAGE_POINTER:
1095       return XIMAGE_INSTANCE_PIXMAP_FILENAME (image_instance);
1096
1097     default:
1098       return Qnil;
1099     }
1100 }
1101
1102 DEFUN ("image-instance-mask-file-name", Fimage_instance_mask_file_name, 1, 1, 0, /*
1103 Return the file name from which IMAGE-INSTANCE's mask was read, if known.
1104 */
1105        (image_instance))
1106 {
1107   CHECK_IMAGE_INSTANCE (image_instance);
1108
1109   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1110     {
1111     case IMAGE_MONO_PIXMAP:
1112     case IMAGE_COLOR_PIXMAP:
1113     case IMAGE_POINTER:
1114       return XIMAGE_INSTANCE_PIXMAP_MASK_FILENAME (image_instance);
1115
1116     default:
1117       return Qnil;
1118     }
1119 }
1120
1121 DEFUN ("image-instance-depth", Fimage_instance_depth, 1, 1, 0, /*
1122 Return the depth of the image instance.
1123 This is 0 for a bitmap, or a positive integer for a pixmap.
1124 */
1125        (image_instance))
1126 {
1127   CHECK_IMAGE_INSTANCE (image_instance);
1128
1129   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1130     {
1131     case IMAGE_MONO_PIXMAP:
1132     case IMAGE_COLOR_PIXMAP:
1133     case IMAGE_POINTER:
1134       return make_int (XIMAGE_INSTANCE_PIXMAP_DEPTH (image_instance));
1135
1136     default:
1137       return Qnil;
1138     }
1139 }
1140
1141 DEFUN ("image-instance-height", Fimage_instance_height, 1, 1, 0, /*
1142 Return the height of the image instance, in pixels.
1143 */
1144        (image_instance))
1145 {
1146   CHECK_IMAGE_INSTANCE (image_instance);
1147
1148   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1149     {
1150     case IMAGE_MONO_PIXMAP:
1151     case IMAGE_COLOR_PIXMAP:
1152     case IMAGE_POINTER:
1153       return make_int (XIMAGE_INSTANCE_PIXMAP_HEIGHT (image_instance));
1154
1155     default:
1156       return Qnil;
1157     }
1158 }
1159
1160 DEFUN ("image-instance-width", Fimage_instance_width, 1, 1, 0, /*
1161 Return the width of the image instance, in pixels.
1162 */
1163        (image_instance))
1164 {
1165   CHECK_IMAGE_INSTANCE (image_instance);
1166
1167   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1168     {
1169     case IMAGE_MONO_PIXMAP:
1170     case IMAGE_COLOR_PIXMAP:
1171     case IMAGE_POINTER:
1172       return make_int (XIMAGE_INSTANCE_PIXMAP_WIDTH (image_instance));
1173
1174     default:
1175       return Qnil;
1176     }
1177 }
1178
1179 DEFUN ("image-instance-hotspot-x", Fimage_instance_hotspot_x, 1, 1, 0, /*
1180 Return the X coordinate of the image instance's hotspot, if known.
1181 This is a point relative to the origin of the pixmap.  When an image is
1182  used as a mouse pointer, the hotspot is the point on the image that sits
1183  over the location that the pointer points to.  This is, for example, the
1184  tip of the arrow or the center of the crosshairs.
1185 This will always be nil for a non-pointer image instance.
1186 */
1187        (image_instance))
1188 {
1189   CHECK_IMAGE_INSTANCE (image_instance);
1190
1191   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1192     {
1193     case IMAGE_MONO_PIXMAP:
1194     case IMAGE_COLOR_PIXMAP:
1195     case IMAGE_POINTER:
1196       return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_X (image_instance);
1197
1198     default:
1199       return Qnil;
1200     }
1201 }
1202
1203 DEFUN ("image-instance-hotspot-y", Fimage_instance_hotspot_y, 1, 1, 0, /*
1204 Return the Y coordinate of the image instance's hotspot, if known.
1205 This is a point relative to the origin of the pixmap.  When an image is
1206  used as a mouse pointer, the hotspot is the point on the image that sits
1207  over the location that the pointer points to.  This is, for example, the
1208  tip of the arrow or the center of the crosshairs.
1209 This will always be nil for a non-pointer image instance.
1210 */
1211        (image_instance))
1212 {
1213   CHECK_IMAGE_INSTANCE (image_instance);
1214
1215   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1216     {
1217     case IMAGE_MONO_PIXMAP:
1218     case IMAGE_COLOR_PIXMAP:
1219     case IMAGE_POINTER:
1220       return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (image_instance);
1221
1222     default:
1223       return Qnil;
1224     }
1225 }
1226
1227 DEFUN ("image-instance-foreground", Fimage_instance_foreground, 1, 1, 0, /*
1228 Return the foreground color of IMAGE-INSTANCE, if applicable.
1229 This will be a color instance or nil. (It will only be non-nil for
1230 colorized mono pixmaps and for pointers.)
1231 */
1232        (image_instance))
1233 {
1234   CHECK_IMAGE_INSTANCE (image_instance);
1235
1236   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1237     {
1238     case IMAGE_MONO_PIXMAP:
1239     case IMAGE_COLOR_PIXMAP:
1240     case IMAGE_POINTER:
1241       return XIMAGE_INSTANCE_PIXMAP_FG (image_instance);
1242
1243     default:
1244       return Qnil;
1245     }
1246 }
1247
1248 DEFUN ("image-instance-background", Fimage_instance_background, 1, 1, 0, /*
1249 Return the background color of IMAGE-INSTANCE, if applicable.
1250 This will be a color instance or nil. (It will only be non-nil for
1251 colorized mono pixmaps and for pointers.)
1252 */
1253        (image_instance))
1254 {
1255   CHECK_IMAGE_INSTANCE (image_instance);
1256
1257   switch (XIMAGE_INSTANCE_TYPE (image_instance))
1258     {
1259     case IMAGE_MONO_PIXMAP:
1260     case IMAGE_COLOR_PIXMAP:
1261     case IMAGE_POINTER:
1262       return XIMAGE_INSTANCE_PIXMAP_BG (image_instance);
1263
1264     default:
1265       return Qnil;
1266     }
1267 }
1268
1269
1270 DEFUN ("colorize-image-instance", Fcolorize_image_instance, 3, 3, 0, /*
1271 Make the image instance be displayed in the given colors.
1272 This function returns a new image instance that is exactly like the
1273 specified one except that (if possible) the foreground and background
1274 colors and as specified.  Currently, this only does anything if the image
1275 instance is a mono pixmap; otherwise, the same image instance is returned.
1276 */
1277        (image_instance, foreground, background))
1278 {
1279   Lisp_Object new;
1280   Lisp_Object device;
1281
1282   CHECK_IMAGE_INSTANCE (image_instance);
1283   CHECK_COLOR_INSTANCE (foreground);
1284   CHECK_COLOR_INSTANCE (background);
1285
1286   device = XIMAGE_INSTANCE_DEVICE (image_instance);
1287   if (!HAS_DEVMETH_P (XDEVICE (device), colorize_image_instance))
1288     return image_instance;
1289
1290   new = allocate_image_instance (device);
1291   copy_lcrecord (XIMAGE_INSTANCE (new), XIMAGE_INSTANCE (image_instance));
1292   /* note that if this method returns non-zero, this method MUST
1293      copy any window-system resources, so that when one image instance is
1294      freed, the other one is not hosed. */
1295   if (!DEVMETH (XDEVICE (device), colorize_image_instance, (new, foreground,
1296                                                             background)))
1297     return image_instance;
1298   return new;
1299 }
1300
1301 \f
1302 /************************************************************************/
1303 /*                              error helpers                           */
1304 /************************************************************************/
1305 DOESNT_RETURN
1306 signal_image_error (CONST char *reason, Lisp_Object frob)
1307 {
1308   signal_error (Qimage_conversion_error,
1309                 list2 (build_translated_string (reason), frob));
1310 }
1311
1312 DOESNT_RETURN
1313 signal_image_error_2 (CONST char *reason, Lisp_Object frob0, Lisp_Object frob1)
1314 {
1315   signal_error (Qimage_conversion_error,
1316                 list3 (build_translated_string (reason), frob0, frob1));
1317 }
1318
1319 /****************************************************************************
1320  *                                  nothing                                 *
1321  ****************************************************************************/
1322
1323 static int
1324 nothing_possible_dest_types (void)
1325 {
1326   return IMAGE_NOTHING_MASK;
1327 }
1328
1329 static void
1330 nothing_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1331                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1332                      int dest_mask, Lisp_Object domain)
1333 {
1334   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1335
1336   if (dest_mask & IMAGE_NOTHING_MASK)
1337     IMAGE_INSTANCE_TYPE (ii) = IMAGE_NOTHING;
1338   else
1339     incompatible_image_types (instantiator, dest_mask, IMAGE_NOTHING_MASK);
1340 }
1341
1342 \f
1343 /****************************************************************************
1344  *                                  inherit                                 *
1345  ****************************************************************************/
1346
1347 static void
1348 inherit_validate (Lisp_Object instantiator)
1349 {
1350   face_must_be_present (instantiator);
1351 }
1352
1353 static Lisp_Object
1354 inherit_normalize (Lisp_Object inst, Lisp_Object console_type)
1355 {
1356   Lisp_Object face;
1357
1358   assert (XVECTOR_LENGTH (inst) == 3);
1359   face = XVECTOR_DATA (inst)[2];
1360   if (!FACEP (face))
1361     inst = vector3 (Qinherit, Q_face, Fget_face (face));
1362   return inst;
1363 }
1364
1365 static int
1366 inherit_possible_dest_types (void)
1367 {
1368   return IMAGE_MONO_PIXMAP_MASK;
1369 }
1370
1371 static void
1372 inherit_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1373                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1374                      int dest_mask, Lisp_Object domain)
1375 {
1376   /* handled specially in image_instantiate */
1377   abort ();
1378 }
1379
1380 \f
1381 /****************************************************************************
1382  *                                  string                                  *
1383  ****************************************************************************/
1384
1385 static void
1386 string_validate (Lisp_Object instantiator)
1387 {
1388   data_must_be_present (instantiator);
1389 }
1390
1391 static int
1392 string_possible_dest_types (void)
1393 {
1394   return IMAGE_TEXT_MASK;
1395 }
1396
1397 /* called from autodetect_instantiate() */
1398 void
1399 string_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1400                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1401                     int dest_mask, Lisp_Object domain)
1402 {
1403   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1404   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1405
1406   assert (!NILP (data));
1407   if (dest_mask & IMAGE_TEXT_MASK)
1408     {
1409       IMAGE_INSTANCE_TYPE (ii) = IMAGE_TEXT;
1410       IMAGE_INSTANCE_TEXT_STRING (ii) = data;
1411     }
1412   else
1413     incompatible_image_types (instantiator, dest_mask, IMAGE_TEXT_MASK);
1414 }
1415
1416 \f
1417 /****************************************************************************
1418  *                             formatted-string                             *
1419  ****************************************************************************/
1420
1421 static void
1422 formatted_string_validate (Lisp_Object instantiator)
1423 {
1424   data_must_be_present (instantiator);
1425 }
1426
1427 static int
1428 formatted_string_possible_dest_types (void)
1429 {
1430   return IMAGE_TEXT_MASK;
1431 }
1432
1433 static void
1434 formatted_string_instantiate (Lisp_Object image_instance,
1435                               Lisp_Object instantiator,
1436                               Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1437                               int dest_mask, Lisp_Object domain)
1438 {
1439   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1440   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1441
1442   assert (!NILP (data));
1443   /* #### implement this */
1444   warn_when_safe (Qunimplemented, Qnotice,
1445                   "`formatted-string' not yet implemented; assuming `string'");
1446   if (dest_mask & IMAGE_TEXT_MASK)
1447     {
1448       IMAGE_INSTANCE_TYPE (ii) = IMAGE_TEXT;
1449       IMAGE_INSTANCE_TEXT_STRING (ii) = data;
1450     }
1451   else
1452     incompatible_image_types (instantiator, dest_mask, IMAGE_TEXT_MASK);
1453 }
1454
1455 \f
1456 /************************************************************************/
1457 /*                        pixmap file functions                         */
1458 /************************************************************************/
1459
1460 /* If INSTANTIATOR refers to inline data, return Qnil.
1461    If INSTANTIATOR refers to data in a file, return the full filename
1462    if it exists; otherwise, return a cons of (filename).
1463
1464    FILE_KEYWORD and DATA_KEYWORD are symbols specifying the
1465    keywords used to look up the file and inline data,
1466    respectively, in the instantiator.  Normally these would
1467    be Q_file and Q_data, but might be different for mask data. */
1468
1469 Lisp_Object
1470 potential_pixmap_file_instantiator (Lisp_Object instantiator,
1471                                     Lisp_Object file_keyword,
1472                                     Lisp_Object data_keyword,
1473                                     Lisp_Object console_type)
1474 {
1475   Lisp_Object file;
1476   Lisp_Object data;
1477
1478   assert (VECTORP (instantiator));
1479
1480   data = find_keyword_in_vector (instantiator, data_keyword);
1481   file = find_keyword_in_vector (instantiator, file_keyword);
1482
1483   if (!NILP (file) && NILP (data))
1484     {
1485       Lisp_Object retval = MAYBE_LISP_CONTYPE_METH
1486         (decode_console_type(console_type, ERROR_ME), 
1487          locate_pixmap_file, (file));
1488
1489       if (!NILP (retval))
1490         return retval;
1491       else
1492         return Fcons (file, Qnil); /* should have been file */
1493     }
1494   
1495   return Qnil;
1496 }
1497
1498 Lisp_Object
1499 simple_image_type_normalize (Lisp_Object inst, Lisp_Object console_type,
1500                              Lisp_Object image_type_tag)
1501 {
1502   /* This function can call lisp */
1503   Lisp_Object file = Qnil;
1504   struct gcpro gcpro1, gcpro2;
1505   Lisp_Object alist = Qnil;
1506
1507   GCPRO2 (file, alist);
1508
1509   /* Now, convert any file data into inline data.  At the end of this,
1510      `data' will contain the inline data (if any) or Qnil, and `file'
1511      will contain the name this data was derived from (if known) or
1512      Qnil.
1513
1514      Note that if we cannot generate any regular inline data, we
1515      skip out. */
1516
1517   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data, 
1518                                              console_type);
1519
1520   if (CONSP (file)) /* failure locating filename */
1521     signal_double_file_error ("Opening pixmap file",
1522                               "no such file or directory",
1523                               Fcar (file));
1524
1525   if (NILP (file)) /* no conversion necessary */
1526     RETURN_UNGCPRO (inst);
1527
1528   alist = tagged_vector_to_alist (inst);
1529
1530   {
1531     Lisp_Object data = make_string_from_file (file);
1532     alist = remassq_no_quit (Q_file, alist);
1533     /* there can't be a :data at this point. */
1534     alist = Fcons (Fcons (Q_file, file),
1535                    Fcons (Fcons (Q_data, data), alist));
1536   }
1537
1538   {
1539     Lisp_Object result = alist_to_tagged_vector (image_type_tag, alist);
1540     free_alist (alist);
1541     RETURN_UNGCPRO (result);
1542   }
1543 }
1544
1545 \f
1546 #ifdef HAVE_WINDOW_SYSTEM
1547 /**********************************************************************
1548  *                             XBM                                    *
1549  **********************************************************************/
1550
1551 /* Check if DATA represents a valid inline XBM spec (i.e. a list
1552    of (width height bits), with checking done on the dimensions).
1553    If not, signal an error. */
1554
1555 static void
1556 check_valid_xbm_inline (Lisp_Object data)
1557 {
1558   Lisp_Object width, height, bits;
1559
1560   if (!CONSP (data) ||
1561       !CONSP (XCDR (data)) ||
1562       !CONSP (XCDR (XCDR (data))) ||
1563       !NILP (XCDR (XCDR (XCDR (data)))))
1564     signal_simple_error ("Must be list of 3 elements", data);
1565
1566   width  = XCAR (data);
1567   height = XCAR (XCDR (data));
1568   bits   = XCAR (XCDR (XCDR (data)));
1569
1570   CHECK_STRING (bits);
1571
1572   if (!NATNUMP (width))
1573     signal_simple_error ("Width must be a natural number", width);
1574
1575   if (!NATNUMP (height))
1576     signal_simple_error ("Height must be a natural number", height);
1577
1578   if (((XINT (width) * XINT (height)) / 8) > XSTRING_CHAR_LENGTH (bits))
1579     signal_simple_error ("data is too short for width and height",
1580                          vector3 (width, height, bits));
1581 }
1582
1583 /* Validate method for XBM's. */
1584
1585 static void
1586 xbm_validate (Lisp_Object instantiator)
1587 {
1588   file_or_data_must_be_present (instantiator);
1589 }
1590
1591 /* Given a filename that is supposed to contain XBM data, return
1592    the inline representation of it as (width height bits).  Return
1593    the hotspot through XHOT and YHOT, if those pointers are not 0.
1594    If there is no hotspot, XHOT and YHOT will contain -1.
1595
1596    If the function fails:
1597
1598    -- if OK_IF_DATA_INVALID is set and the data was invalid,
1599       return Qt.
1600    -- maybe return an error, or return Qnil.
1601  */
1602
1603 #ifndef HAVE_X_WINDOWS
1604 #define XFree(data) free(data)
1605 #endif
1606
1607 Lisp_Object
1608 bitmap_to_lisp_data (Lisp_Object name, int *xhot, int *yhot,
1609                      int ok_if_data_invalid)
1610 {
1611   unsigned int w, h;
1612   Extbyte *data;
1613   int result;
1614   CONST char *filename_ext;
1615
1616   GET_C_STRING_FILENAME_DATA_ALLOCA (name, filename_ext);
1617   result = read_bitmap_data_from_file (filename_ext, &w, &h, 
1618                                        &data, xhot, yhot);
1619
1620   if (result == BitmapSuccess)
1621     {
1622       Lisp_Object retval;
1623       int len = (w + 7) / 8 * h;
1624
1625       retval = list3 (make_int (w), make_int (h),
1626                       make_ext_string (data, len, FORMAT_BINARY));
1627       XFree ((char *) data);
1628       return retval;
1629     }
1630
1631   switch (result)
1632     {
1633     case BitmapOpenFailed:
1634       {
1635         /* should never happen */
1636         signal_double_file_error ("Opening bitmap file",
1637                                   "no such file or directory",
1638                                   name);
1639       }
1640     case BitmapFileInvalid:
1641       {
1642         if (ok_if_data_invalid)
1643           return Qt;
1644         signal_double_file_error ("Reading bitmap file",
1645                                   "invalid data in file",
1646                                   name);
1647       }
1648     case BitmapNoMemory:
1649       {
1650         signal_double_file_error ("Reading bitmap file",
1651                                   "out of memory",
1652                                   name);
1653       }
1654     default:
1655       {
1656         signal_double_file_error_2 ("Reading bitmap file",
1657                                     "unknown error code",
1658                                     make_int (result), name);
1659       }
1660     }
1661
1662   return Qnil; /* not reached */
1663 }
1664
1665 Lisp_Object
1666 xbm_mask_file_munging (Lisp_Object alist, Lisp_Object file,
1667                        Lisp_Object mask_file, Lisp_Object console_type)
1668 {
1669   /* This is unclean but it's fairly standard -- a number of the
1670      bitmaps in /usr/include/X11/bitmaps use it -- so we support
1671      it. */
1672   if (NILP (mask_file)
1673       /* don't override explicitly specified mask data. */
1674       && NILP (assq_no_quit (Q_mask_data, alist))
1675       && !NILP (file))
1676     {
1677       mask_file = MAYBE_LISP_CONTYPE_METH
1678         (decode_console_type(console_type, ERROR_ME), 
1679          locate_pixmap_file, (concat2 (file, build_string ("Mask"))));
1680       if (NILP (mask_file))
1681         mask_file = MAYBE_LISP_CONTYPE_METH
1682           (decode_console_type(console_type, ERROR_ME), 
1683            locate_pixmap_file, (concat2 (file, build_string ("msk"))));
1684     }
1685
1686   if (!NILP (mask_file))
1687     {
1688       Lisp_Object mask_data =
1689         bitmap_to_lisp_data (mask_file, 0, 0, 0);
1690       alist = remassq_no_quit (Q_mask_file, alist);
1691       /* there can't be a :mask-data at this point. */
1692       alist = Fcons (Fcons (Q_mask_file, mask_file),
1693                      Fcons (Fcons (Q_mask_data, mask_data), alist));
1694     }
1695
1696   return alist;
1697 }
1698
1699 /* Normalize method for XBM's. */
1700
1701 static Lisp_Object
1702 xbm_normalize (Lisp_Object inst, Lisp_Object console_type)
1703 {
1704   Lisp_Object file = Qnil, mask_file = Qnil;
1705   struct gcpro gcpro1, gcpro2, gcpro3;
1706   Lisp_Object alist = Qnil;
1707
1708   GCPRO3 (file, mask_file, alist);
1709
1710   /* Now, convert any file data into inline data for both the regular
1711      data and the mask data.  At the end of this, `data' will contain
1712      the inline data (if any) or Qnil, and `file' will contain
1713      the name this data was derived from (if known) or Qnil.
1714      Likewise for `mask_file' and `mask_data'.
1715
1716      Note that if we cannot generate any regular inline data, we
1717      skip out. */
1718
1719   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data,
1720                                              console_type);
1721   mask_file = potential_pixmap_file_instantiator (inst, Q_mask_file,
1722                                                   Q_mask_data, console_type);
1723
1724   if (CONSP (file)) /* failure locating filename */
1725     signal_double_file_error ("Opening bitmap file",
1726                               "no such file or directory",
1727                               Fcar (file));
1728
1729   if (NILP (file) && NILP (mask_file)) /* no conversion necessary */
1730     RETURN_UNGCPRO (inst);
1731
1732   alist = tagged_vector_to_alist (inst);
1733
1734   if (!NILP (file))
1735     {
1736       int xhot, yhot;
1737       Lisp_Object data = bitmap_to_lisp_data (file, &xhot, &yhot, 0);
1738       alist = remassq_no_quit (Q_file, alist);
1739       /* there can't be a :data at this point. */
1740       alist = Fcons (Fcons (Q_file, file),
1741                      Fcons (Fcons (Q_data, data), alist));
1742
1743       if (xhot != -1 && NILP (assq_no_quit (Q_hotspot_x, alist)))
1744         alist = Fcons (Fcons (Q_hotspot_x, make_int (xhot)),
1745                        alist);
1746       if (yhot != -1 && NILP (assq_no_quit (Q_hotspot_y, alist)))
1747         alist = Fcons (Fcons (Q_hotspot_y, make_int (yhot)),
1748                        alist);
1749     }
1750
1751   alist = xbm_mask_file_munging (alist, file, mask_file, console_type);
1752
1753   {
1754     Lisp_Object result = alist_to_tagged_vector (Qxbm, alist);
1755     free_alist (alist);
1756     RETURN_UNGCPRO (result);
1757   }
1758 }
1759
1760 \f
1761 static int
1762 xbm_possible_dest_types (void)
1763 {
1764   return
1765     IMAGE_MONO_PIXMAP_MASK  |
1766     IMAGE_COLOR_PIXMAP_MASK |
1767     IMAGE_POINTER_MASK;
1768 }
1769
1770 static void
1771 xbm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1772                  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1773                  int dest_mask, Lisp_Object domain)
1774 {
1775   Lisp_Object device= IMAGE_INSTANCE_DEVICE (XIMAGE_INSTANCE (image_instance));
1776
1777   MAYBE_DEVMETH (XDEVICE (device), 
1778                  xbm_instantiate,
1779                  (image_instance, instantiator, pointer_fg, 
1780                   pointer_bg, dest_mask, domain));
1781 }
1782
1783 #endif
1784
1785 \f
1786 #ifdef HAVE_XPM
1787
1788 /**********************************************************************
1789  *                             XPM                                    *
1790  **********************************************************************/
1791
1792 Lisp_Object
1793 pixmap_to_lisp_data (Lisp_Object name, int ok_if_data_invalid)
1794 {
1795   char **data;
1796   int result;
1797
1798   result = XpmReadFileToData ((char *) XSTRING_DATA (name), &data);
1799
1800   if (result == XpmSuccess)
1801     {
1802       Lisp_Object retval = Qnil;
1803       struct buffer *old_buffer = current_buffer;
1804       Lisp_Object temp_buffer =
1805         Fget_buffer_create (build_string (" *pixmap conversion*"));
1806       int elt;
1807       int height, width, ncolors;
1808       struct gcpro gcpro1, gcpro2, gcpro3;
1809       int speccount = specpdl_depth ();
1810
1811       GCPRO3 (name, retval, temp_buffer);
1812
1813       specbind (Qinhibit_quit, Qt);
1814       set_buffer_internal (XBUFFER (temp_buffer));
1815       Ferase_buffer (Qnil);
1816
1817       buffer_insert_c_string (current_buffer, "/* XPM */\r");
1818       buffer_insert_c_string (current_buffer, "static char *pixmap[] = {\r");
1819
1820       sscanf (data[0], "%d %d %d", &height, &width, &ncolors);
1821       for (elt = 0; elt <= width + ncolors; elt++)
1822         {
1823           buffer_insert_c_string (current_buffer, "\"");
1824           buffer_insert_c_string (current_buffer, data[elt]);
1825
1826           if (elt < width + ncolors)
1827             buffer_insert_c_string (current_buffer, "\",\r");
1828           else
1829             buffer_insert_c_string (current_buffer, "\"};\r");
1830         }
1831
1832       retval = Fbuffer_substring (Qnil, Qnil, Qnil);
1833       XpmFree (data);
1834
1835       set_buffer_internal (old_buffer);
1836       unbind_to (speccount, Qnil);
1837
1838       RETURN_UNGCPRO (retval);
1839     }
1840
1841   switch (result)
1842     {
1843     case XpmFileInvalid:
1844       {
1845         if (ok_if_data_invalid)
1846           return Qt;
1847         signal_image_error ("invalid XPM data in file", name);
1848       }
1849     case XpmNoMemory:
1850       {
1851         signal_double_file_error ("Reading pixmap file",
1852                                   "out of memory", name);
1853       }
1854     case XpmOpenFailed:
1855       {
1856         /* should never happen? */
1857         signal_double_file_error ("Opening pixmap file",
1858                                   "no such file or directory", name);
1859       }
1860     default:
1861       {
1862         signal_double_file_error_2 ("Parsing pixmap file",
1863                                     "unknown error code",
1864                                     make_int (result), name);
1865         break;
1866       }
1867     }
1868
1869   return Qnil; /* not reached */
1870 }
1871
1872 static void
1873 check_valid_xpm_color_symbols (Lisp_Object data)
1874 {
1875   Lisp_Object rest;
1876
1877   for (rest = data; !NILP (rest); rest = XCDR (rest))
1878     {
1879       if (!CONSP (rest) ||
1880           !CONSP (XCAR (rest)) ||
1881           !STRINGP (XCAR (XCAR (rest))) ||
1882           (!STRINGP (XCDR (XCAR (rest))) &&
1883            !COLOR_SPECIFIERP (XCDR (XCAR (rest)))))
1884         signal_simple_error ("Invalid color symbol alist", data);
1885     }
1886 }
1887
1888 static void
1889 xpm_validate (Lisp_Object instantiator)
1890 {
1891   file_or_data_must_be_present (instantiator);
1892 }
1893
1894 Lisp_Object Vxpm_color_symbols;
1895
1896 Lisp_Object
1897 evaluate_xpm_color_symbols (void)
1898 {
1899   Lisp_Object rest, results = Qnil;
1900   struct gcpro gcpro1, gcpro2;
1901
1902   GCPRO2 (rest, results);
1903   for (rest = Vxpm_color_symbols; !NILP (rest); rest = XCDR (rest))
1904     {
1905       Lisp_Object name, value, cons;
1906
1907       CHECK_CONS (rest);
1908       cons = XCAR (rest);
1909       CHECK_CONS (cons);
1910       name = XCAR (cons);
1911       CHECK_STRING (name);
1912       value = XCDR (cons);
1913       CHECK_CONS (value);
1914       value = XCAR (value);
1915       value = Feval (value);
1916       if (NILP (value))
1917         continue;
1918       if (!STRINGP (value) && !COLOR_SPECIFIERP (value))
1919         signal_simple_error
1920           ("Result from xpm-color-symbols eval must be nil, string, or color",
1921            value);
1922       results = Fcons (Fcons (name, value), results);
1923     }
1924   UNGCPRO;                      /* no more evaluation */
1925   return results;
1926 }
1927
1928 static Lisp_Object
1929 xpm_normalize (Lisp_Object inst, Lisp_Object console_type)
1930 {
1931   Lisp_Object file = Qnil;
1932   Lisp_Object color_symbols;
1933   struct gcpro gcpro1, gcpro2;
1934   Lisp_Object alist = Qnil;
1935
1936   GCPRO2 (file, alist);
1937
1938   /* Now, convert any file data into inline data.  At the end of this,
1939      `data' will contain the inline data (if any) or Qnil, and
1940      `file' will contain the name this data was derived from (if
1941      known) or Qnil.
1942
1943      Note that if we cannot generate any regular inline data, we
1944      skip out. */
1945
1946   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data, 
1947                                              console_type);
1948
1949   if (CONSP (file)) /* failure locating filename */
1950     signal_double_file_error ("Opening pixmap file",
1951                               "no such file or directory",
1952                               Fcar (file));
1953
1954   color_symbols = find_keyword_in_vector_or_given (inst, Q_color_symbols,
1955                                                    Qunbound);
1956
1957   if (NILP (file) && !UNBOUNDP (color_symbols))
1958     /* no conversion necessary */
1959     RETURN_UNGCPRO (inst);
1960   
1961   alist = tagged_vector_to_alist (inst);
1962
1963   if (!NILP (file))
1964     {
1965       Lisp_Object data = pixmap_to_lisp_data (file, 0);
1966       alist = remassq_no_quit (Q_file, alist);
1967       /* there can't be a :data at this point. */
1968       alist = Fcons (Fcons (Q_file, file),
1969                      Fcons (Fcons (Q_data, data), alist));
1970     }
1971   
1972   if (UNBOUNDP (color_symbols))
1973     {
1974       color_symbols = evaluate_xpm_color_symbols ();
1975       alist = Fcons (Fcons (Q_color_symbols, color_symbols),
1976                      alist);
1977     }
1978
1979   {
1980     Lisp_Object result = alist_to_tagged_vector (Qxpm, alist);
1981     free_alist (alist);
1982     RETURN_UNGCPRO (result);
1983   }
1984 }
1985
1986 static int
1987 xpm_possible_dest_types (void)
1988 {
1989   return
1990     IMAGE_MONO_PIXMAP_MASK  |
1991     IMAGE_COLOR_PIXMAP_MASK |
1992     IMAGE_POINTER_MASK;
1993 }
1994
1995 static void
1996 xpm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1997                  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1998                  int dest_mask, Lisp_Object domain)
1999 {
2000   Lisp_Object device= IMAGE_INSTANCE_DEVICE (XIMAGE_INSTANCE (image_instance));
2001
2002   MAYBE_DEVMETH (XDEVICE (device), 
2003                  xpm_instantiate,
2004                  (image_instance, instantiator, pointer_fg, 
2005                   pointer_bg, dest_mask, domain));
2006 }
2007
2008 #endif /* HAVE_XPM */
2009
2010 \f
2011 /****************************************************************************
2012  *                         Image Specifier Object                           *
2013  ****************************************************************************/
2014
2015 DEFINE_SPECIFIER_TYPE (image);
2016
2017 static void
2018 image_create (Lisp_Object obj)
2019 {
2020   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2021
2022   IMAGE_SPECIFIER_ALLOWED (image) = ~0; /* all are allowed */
2023   IMAGE_SPECIFIER_ATTACHEE (image) = Qnil;
2024   IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image) = Qnil;
2025 }
2026
2027 static void
2028 image_mark (Lisp_Object obj, void (*markobj) (Lisp_Object))
2029 {
2030   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2031
2032   ((markobj) (IMAGE_SPECIFIER_ATTACHEE (image)));
2033   ((markobj) (IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image)));
2034 }
2035
2036 static Lisp_Object
2037 image_instantiate_cache_result (Lisp_Object locative)
2038 {
2039   /* locative = (instance instantiator . subtable) */
2040   Fputhash (XCAR (XCDR (locative)), XCAR (locative), XCDR (XCDR (locative)));
2041   free_cons (XCONS (XCDR (locative)));
2042   free_cons (XCONS (locative));
2043   return Qnil;
2044 }
2045
2046 /* Given a specification for an image, return an instance of
2047    the image which matches the given instantiator and which can be
2048    displayed in the given domain. */
2049
2050 static Lisp_Object
2051 image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
2052                    Lisp_Object domain, Lisp_Object instantiator,
2053                    Lisp_Object depth)
2054 {
2055   Lisp_Object device = DFW_DEVICE (domain);
2056   struct device *d = XDEVICE (device);
2057   int dest_mask = XIMAGE_SPECIFIER_ALLOWED (specifier);
2058   int pointerp = dest_mask & image_instance_type_to_mask (IMAGE_POINTER);
2059
2060   if (IMAGE_INSTANCEP (instantiator))
2061     {
2062       /* make sure that the image instance's device and type are
2063          matching. */
2064
2065       if (EQ (device, XIMAGE_INSTANCE_DEVICE (instantiator)))
2066         {
2067           int mask =
2068             image_instance_type_to_mask (XIMAGE_INSTANCE_TYPE (instantiator));
2069           if (mask & dest_mask)
2070             return instantiator;
2071           else
2072             signal_simple_error ("Type of image instance not allowed here",
2073                                  instantiator);
2074         }
2075       else
2076         signal_simple_error_2 ("Wrong device for image instance",
2077                                instantiator, device);
2078     }
2079   else if (VECTORP (instantiator)
2080            && EQ (XVECTOR_DATA (instantiator)[0], Qinherit))
2081     {
2082       assert (XVECTOR_LENGTH (instantiator) == 3);
2083       return (FACE_PROPERTY_INSTANCE
2084               (Fget_face (XVECTOR_DATA (instantiator)[2]),
2085                Qbackground_pixmap, domain, 0, depth));
2086     }
2087   else
2088     {
2089       Lisp_Object instance;
2090       Lisp_Object subtable;
2091       Lisp_Object ls3 = Qnil;
2092       Lisp_Object pointer_fg = Qnil;
2093       Lisp_Object pointer_bg = Qnil;
2094
2095       if (pointerp)
2096         {
2097           pointer_fg = FACE_FOREGROUND (Vpointer_face, domain);
2098           pointer_bg = FACE_BACKGROUND (Vpointer_face, domain);
2099           ls3 = list3 (instantiator, pointer_fg, pointer_bg);
2100         }
2101
2102       /* First look in the hash table. */
2103       subtable = Fgethash (make_int (dest_mask), d->image_instance_cache,
2104                            Qunbound);
2105       if (UNBOUNDP (subtable))
2106         {
2107           /* For the image instance cache, we do comparisons with EQ rather
2108              than with EQUAL, as we do for color and font names.
2109              The reasons are:
2110
2111              1) pixmap data can be very long, and thus the hashing and
2112              comparing will take awhile.
2113              2) It's not so likely that we'll run into things that are EQUAL
2114              but not EQ (that can happen a lot with faces, because their
2115              specifiers are copied around); but pixmaps tend not to be
2116              in faces.
2117
2118              However, if the image-instance could be a pointer, we have to
2119              use EQUAL because we massaged the instantiator into a cons3
2120              also containing the foreground and background of the
2121              pointer face.
2122            */
2123
2124           subtable = make_lisp_hashtable (20,
2125                                           pointerp ? HASHTABLE_KEY_CAR_WEAK
2126                                           : HASHTABLE_KEY_WEAK,
2127                                           pointerp ? HASHTABLE_EQUAL
2128                                           : HASHTABLE_EQ);
2129           Fputhash (make_int (dest_mask), subtable,
2130                     d->image_instance_cache);
2131           instance = Qunbound;
2132         }
2133       else
2134         instance = Fgethash (pointerp ? ls3 : instantiator,
2135                              subtable, Qunbound);
2136
2137       if (UNBOUNDP (instance))
2138         {
2139           Lisp_Object locative =
2140             noseeum_cons (Qnil,
2141                           noseeum_cons (pointerp ? ls3 : instantiator,
2142                                         subtable));
2143           int speccount = specpdl_depth ();
2144
2145           /* make sure we cache the failures, too.
2146              Use an unwind-protect to catch such errors.
2147              If we fail, the unwind-protect records nil in
2148              the hash table.  If we succeed, we change the
2149              car of the locative to the resulting instance,
2150              which gets recorded instead. */
2151           record_unwind_protect (image_instantiate_cache_result,
2152                                  locative);
2153           instance = instantiate_image_instantiator (device,
2154                                                      domain,
2155                                                      instantiator,
2156                                                      pointer_fg, pointer_bg,
2157                                                      dest_mask);
2158           Fsetcar (locative, instance);
2159           unbind_to (speccount, Qnil);
2160         }
2161       else
2162         free_list (ls3);
2163
2164       if (NILP (instance))
2165         signal_simple_error ("Can't instantiate image (probably cached)",
2166                              instantiator);
2167       return instance;
2168     }
2169
2170   abort ();
2171   return Qnil; /* not reached */
2172 }
2173
2174 /* Validate an image instantiator. */
2175
2176 static void
2177 image_validate (Lisp_Object instantiator)
2178 {
2179   if (IMAGE_INSTANCEP (instantiator) || STRINGP (instantiator))
2180     return;
2181   else if (VECTORP (instantiator))
2182     {
2183       Lisp_Object *elt = XVECTOR_DATA (instantiator);
2184       int instantiator_len = XVECTOR_LENGTH (instantiator);
2185       struct image_instantiator_methods *meths;
2186       Lisp_Object already_seen = Qnil;
2187       struct gcpro gcpro1;
2188       int i;
2189
2190       if (instantiator_len < 1)
2191         signal_simple_error ("Vector length must be at least 1",
2192                              instantiator);
2193
2194       meths = decode_image_instantiator_format (elt[0], ERROR_ME);
2195       if (!(instantiator_len & 1))
2196         signal_simple_error
2197           ("Must have alternating keyword/value pairs", instantiator);
2198
2199       GCPRO1 (already_seen);
2200
2201       for (i = 1; i < instantiator_len; i += 2)
2202         {
2203           Lisp_Object keyword = elt[i];
2204           Lisp_Object value = elt[i+1];
2205           int j;
2206
2207           CHECK_SYMBOL (keyword);
2208           if (!SYMBOL_IS_KEYWORD (keyword))
2209             signal_simple_error ("Symbol must begin with a colon", keyword);
2210
2211           for (j = 0; j < Dynarr_length (meths->keywords); j++)
2212             if (EQ (keyword, Dynarr_at (meths->keywords, j).keyword))
2213               break;
2214
2215           if (j == Dynarr_length (meths->keywords))
2216             signal_simple_error ("Unrecognized keyword", keyword);
2217
2218           if (!Dynarr_at (meths->keywords, j).multiple_p)
2219             {
2220               if (!NILP (memq_no_quit (keyword, already_seen)))
2221                 signal_simple_error
2222                   ("Keyword may not appear more than once", keyword);
2223               already_seen = Fcons (keyword, already_seen);
2224             }
2225
2226           (Dynarr_at (meths->keywords, j).validate) (value);
2227         }
2228
2229       UNGCPRO;
2230
2231       MAYBE_IIFORMAT_METH (meths, validate, (instantiator));
2232     }
2233   else
2234     signal_simple_error ("Must be string or vector", instantiator);
2235 }
2236
2237 static void
2238 image_after_change (Lisp_Object specifier, Lisp_Object locale)
2239 {
2240   Lisp_Object attachee =
2241     IMAGE_SPECIFIER_ATTACHEE (XIMAGE_SPECIFIER (specifier));
2242   Lisp_Object property =
2243     IMAGE_SPECIFIER_ATTACHEE_PROPERTY (XIMAGE_SPECIFIER (specifier));
2244   if (FACEP (attachee))
2245     face_property_was_changed (attachee, property, locale);
2246   else if (GLYPHP (attachee))
2247     glyph_property_was_changed (attachee, property, locale);
2248 }
2249
2250 void
2251 set_image_attached_to (Lisp_Object obj, Lisp_Object face_or_glyph,
2252                        Lisp_Object property)
2253 {
2254   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2255
2256   IMAGE_SPECIFIER_ATTACHEE (image) = face_or_glyph;
2257   IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image) = property;
2258 }
2259
2260 static Lisp_Object
2261 image_going_to_add (Lisp_Object specifier, Lisp_Object locale,
2262                     Lisp_Object tag_set, Lisp_Object instantiator)
2263 {
2264   Lisp_Object possible_console_types = Qnil;
2265   Lisp_Object rest;
2266   Lisp_Object retlist = Qnil;
2267   struct gcpro gcpro1, gcpro2;
2268
2269   LIST_LOOP (rest, Vconsole_type_list)
2270     {
2271       Lisp_Object contype = XCAR (rest);
2272       if (!NILP (memq_no_quit (contype, tag_set)))
2273         possible_console_types = Fcons (contype, possible_console_types);
2274     }
2275
2276   if (XINT (Flength (possible_console_types)) > 1)
2277     /* two conflicting console types specified */
2278     return Qnil;
2279
2280   if (NILP (possible_console_types))
2281     possible_console_types = Vconsole_type_list;
2282
2283   GCPRO2 (retlist, possible_console_types);
2284
2285   LIST_LOOP (rest, possible_console_types)
2286     {
2287       Lisp_Object contype = XCAR (rest);
2288       Lisp_Object newinst = call_with_suspended_errors
2289         ((lisp_fn_t) normalize_image_instantiator,
2290          Qnil, Qimage, ERROR_ME_NOT, 3, instantiator, contype,
2291          make_int (XIMAGE_SPECIFIER_ALLOWED (specifier)));
2292
2293       if (!NILP (newinst))
2294         {
2295           Lisp_Object newtag;
2296           if (NILP (memq_no_quit (contype, tag_set)))
2297             newtag = Fcons (contype, tag_set);
2298           else
2299             newtag = tag_set;
2300           retlist = Fcons (Fcons (newtag, newinst), retlist);
2301         }
2302     }
2303
2304   UNGCPRO;
2305
2306   return retlist;
2307 }
2308
2309 DEFUN ("image-specifier-p", Fimage_specifier_p, 1, 1, 0, /*
2310 Return non-nil if OBJECT is an image specifier.
2311
2312 An image specifier is used for images (pixmaps and the like).  It is used
2313 to describe the actual image in a glyph.  It is instanced as an image-
2314 instance.
2315
2316 Image instantiators come in many formats: `xbm', `xpm', `gif', `jpeg',
2317 etc.  This describes the format of the data describing the image.  The
2318 resulting image instances also come in many types -- `mono-pixmap',
2319 `color-pixmap', `text', `pointer', etc.  This refers to the behavior of
2320 the image and the sorts of places it can appear. (For example, a
2321 color-pixmap image has fixed colors specified for it, while a
2322 mono-pixmap image comes in two unspecified shades "foreground" and
2323 "background" that are determined from the face of the glyph or
2324 surrounding text; a text image appears as a string of text and has an
2325 unspecified foreground, background, and font; a pointer image behaves
2326 like a mono-pixmap image but can only be used as a mouse pointer
2327 \[mono-pixmap images cannot be used as mouse pointers]; etc.) It is
2328 important to keep the distinction between image instantiator format and
2329 image instance type in mind.  Typically, a given image instantiator
2330 format can result in many different image instance types (for example,
2331 `xpm' can be instanced as `color-pixmap', `mono-pixmap', or `pointer';
2332 whereas `cursor-font' can be instanced only as `pointer'), and a
2333 particular image instance type can be generated by many different
2334 image instantiator formats (e.g.  `color-pixmap' can be generated by `xpm',
2335 `gif', `jpeg', etc.).
2336
2337 See `make-image-instance' for a more detailed discussion of image
2338 instance types.
2339
2340 An image instantiator should be a string or a vector of the form
2341
2342  [FORMAT :KEYWORD VALUE ...]
2343
2344 i.e. a format symbol followed by zero or more alternating keyword-value
2345 pairs.  FORMAT should be one of
2346
2347 'nothing
2348   (Don't display anything; no keywords are valid for this.
2349    Can only be instanced as `nothing'.)
2350 'string
2351   (Display this image as a text string.  Can only be instanced
2352    as `text', although support for instancing as `mono-pixmap'
2353    should be added.)
2354 'formatted-string
2355   (Display this image as a text string, with replaceable fields;
2356   not currently implemented.)
2357 'xbm
2358   (An X bitmap; only if X support was compiled into this XEmacs.
2359    Can be instanced as `mono-pixmap', `color-pixmap', or `pointer'.)
2360 'xpm
2361   (An XPM pixmap; only if XPM support was compiled into this XEmacs.
2362    Can be instanced as `color-pixmap', `mono-pixmap', or `pointer'.)
2363 'xface
2364   (An X-Face bitmap, used to encode people's faces in e-mail messages;
2365   only if X-Face support was compiled into this XEmacs.  Can be
2366   instanced as `mono-pixmap', `color-pixmap', or `pointer'.)
2367 'gif
2368   (A GIF87 or GIF89 image; only if GIF support was compiled into this
2369    XEmacs.  NOTE: only the first frame of animated gifs will be displayed.
2370    Can be instanced as `color-pixmap'.)
2371 'jpeg
2372   (A JPEG image; only if JPEG support was compiled into this XEmacs.
2373    Can be instanced as `color-pixmap'.)
2374 'png
2375   (A PNG image; only if PNG support was compiled into this XEmacs.
2376    Can be instanced as `color-pixmap'.)
2377 'tiff
2378   (A TIFF image; only if TIFF support was compiled into this XEmacs.
2379    Can be instanced as `color-pixmap'.)
2380 'cursor-font
2381   (One of the standard cursor-font names, such as "watch" or
2382    "right_ptr" under X.  Under X, this is, more specifically, any
2383    of the standard cursor names from appendix B of the Xlib manual
2384    [also known as the file <X11/cursorfont.h>] minus the XC_ prefix.
2385    On other window systems, the valid names will be specific to the
2386    type of window system.  Can only be instanced as `pointer'.)
2387 'font
2388   (A glyph from a font; i.e. the name of a font, and glyph index into it
2389    of the form "FONT fontname index [[mask-font] mask-index]".
2390    Currently can only be instanced as `pointer', although this should
2391    probably be fixed.)
2392 'subwindow
2393   (An embedded X window; not currently implemented.)
2394 'autodetect
2395   (XEmacs tries to guess what format the data is in.  If X support
2396   exists, the data string will be checked to see if it names a filename.
2397   If so, and this filename contains XBM or XPM data, the appropriate
2398   sort of pixmap or pointer will be created. [This includes picking up
2399   any specified hotspot or associated mask file.] Otherwise, if `pointer'
2400   is one of the allowable image-instance types and the string names a
2401   valid cursor-font name, the image will be created as a pointer.
2402   Otherwise, the image will be displayed as text.  If no X support
2403   exists, the image will always be displayed as text.)
2404 'inherit
2405   Inherit from the background-pixmap property of a face.
2406
2407 The valid keywords are:
2408
2409 :data
2410   (Inline data.  For most formats above, this should be a string.  For
2411   XBM images, this should be a list of three elements: width, height, and
2412   a string of bit data.  This keyword is not valid for instantiator
2413   formats `nothing' and `inherit'.)
2414 :file
2415   (Data is contained in a file.  The value is the name of this file.
2416   If both :data and :file are specified, the image is created from
2417   what is specified in :data and the string in :file becomes the
2418   value of the `image-instance-file-name' function when applied to
2419   the resulting image-instance.  This keyword is not valid for
2420   instantiator formats `nothing', `string', `formatted-string',
2421   `cursor-font', `font', `autodetect', and `inherit'.)
2422 :foreground
2423 :background
2424   (For `xbm', `xface', `cursor-font', and `font'.  These keywords
2425   allow you to explicitly specify foreground and background colors.
2426   The argument should be anything acceptable to `make-color-instance'.
2427   This will cause what would be a `mono-pixmap' to instead be colorized
2428   as a two-color color-pixmap, and specifies the foreground and/or
2429   background colors for a pointer instead of black and white.)
2430 :mask-data
2431   (For `xbm' and `xface'.  This specifies a mask to be used with the
2432   bitmap.  The format is a list of width, height, and bits, like for
2433   :data.)
2434 :mask-file
2435   (For `xbm' and `xface'.  This specifies a file containing the mask data.
2436   If neither a mask file nor inline mask data is given for an XBM image,
2437   and the XBM image comes from a file, XEmacs will look for a mask file
2438   with the same name as the image file but with "Mask" or "msk"
2439   appended.  For example, if you specify the XBM file "left_ptr"
2440   [usually located in "/usr/include/X11/bitmaps"], the associated
2441   mask file "left_ptrmsk" will automatically be picked up.)
2442 :hotspot-x
2443 :hotspot-y
2444   (For `xbm' and `xface'.  These keywords specify a hotspot if the image
2445   is instantiated as a `pointer'.  Note that if the XBM image file
2446   specifies a hotspot, it will automatically be picked up if no
2447   explicit hotspot is given.)
2448 :color-symbols
2449   (Only for `xpm'.  This specifies an alist that maps strings
2450   that specify symbolic color names to the actual color to be used
2451   for that symbolic color (in the form of a string or a color-specifier
2452   object).  If this is not specified, the contents of `xpm-color-symbols'
2453   are used to generate the alist.)
2454 :face
2455   (Only for `inherit'.  This specifies the face to inherit from.)
2456
2457 If instead of a vector, the instantiator is a string, it will be
2458 converted into a vector by looking it up according to the specs in the
2459 `console-type-image-conversion-list' (q.v.) for the console type of
2460 the domain (usually a window; sometimes a frame or device) over which
2461 the image is being instantiated.
2462
2463 If the instantiator specifies data from a file, the data will be read
2464 in at the time that the instantiator is added to the image (which may
2465 be well before when the image is actually displayed), and the
2466 instantiator will be converted into one of the inline-data forms, with
2467 the filename retained using a :file keyword.  This implies that the
2468 file must exist when the instantiator is added to the image, but does
2469 not need to exist at any other time (e.g. it may safely be a temporary
2470 file).
2471 */
2472        (object))
2473 {
2474   return IMAGE_SPECIFIERP (object) ? Qt : Qnil;
2475 }
2476
2477 \f
2478 /****************************************************************************
2479  *                             Glyph Object                                 *
2480  ****************************************************************************/
2481
2482 static Lisp_Object
2483 mark_glyph (Lisp_Object obj, void (*markobj) (Lisp_Object))
2484 {
2485   struct Lisp_Glyph *glyph = XGLYPH (obj);
2486
2487   ((markobj) (glyph->image));
2488   ((markobj) (glyph->contrib_p));
2489   ((markobj) (glyph->baseline));
2490   ((markobj) (glyph->face));
2491
2492   return glyph->plist;
2493 }
2494
2495 static void
2496 print_glyph (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
2497 {
2498   struct Lisp_Glyph *glyph = XGLYPH (obj);
2499   char buf[20];
2500
2501   if (print_readably)
2502     error ("printing unreadable object #<glyph 0x%x>", glyph->header.uid);
2503
2504   write_c_string ("#<glyph (", printcharfun);
2505   print_internal (Fglyph_type (obj), printcharfun, 0);
2506   write_c_string (") ", printcharfun);
2507   print_internal (glyph->image, printcharfun, 1);
2508   sprintf (buf, "0x%x>", glyph->header.uid);
2509   write_c_string (buf, printcharfun);
2510 }
2511
2512 /* Glyphs are equal if all of their display attributes are equal.  We
2513    don't compare names or doc-strings, because that would make equal
2514    be eq.
2515
2516    This isn't concerned with "unspecified" attributes, that's what
2517    #'glyph-differs-from-default-p is for. */
2518 static int
2519 glyph_equal (Lisp_Object o1, Lisp_Object o2, int depth)
2520 {
2521   struct Lisp_Glyph *g1 = XGLYPH (o1);
2522   struct Lisp_Glyph *g2 = XGLYPH (o2);
2523
2524   depth++;
2525
2526   return (internal_equal (g1->image,     g2->image,     depth) &&
2527           internal_equal (g1->contrib_p, g2->contrib_p, depth) &&
2528           internal_equal (g1->baseline,  g2->baseline,  depth) &&
2529           internal_equal (g1->face,      g2->face,      depth) &&
2530           !plists_differ (g1->plist,     g2->plist, 0, 0, depth + 1));
2531 }
2532
2533 static unsigned long
2534 glyph_hash (Lisp_Object obj, int depth)
2535 {
2536   depth++;
2537
2538   /* No need to hash all of the elements; that would take too long.
2539      Just hash the most common ones. */
2540   return HASH2 (internal_hash (XGLYPH (obj)->image, depth),
2541                 internal_hash (XGLYPH (obj)->face,  depth));
2542 }
2543
2544 static Lisp_Object
2545 glyph_getprop (Lisp_Object obj, Lisp_Object prop)
2546 {
2547   struct Lisp_Glyph *g = XGLYPH (obj);
2548
2549   if (EQ (prop, Qimage))     return g->image;
2550   if (EQ (prop, Qcontrib_p)) return g->contrib_p;
2551   if (EQ (prop, Qbaseline))  return g->baseline;
2552   if (EQ (prop, Qface))      return g->face;
2553
2554   return external_plist_get (&g->plist, prop, 0, ERROR_ME);
2555 }
2556
2557 static int
2558 glyph_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
2559 {
2560   if ((EQ (prop, Qimage))     ||
2561       (EQ (prop, Qcontrib_p)) ||
2562       (EQ (prop, Qbaseline)))
2563     return 0;
2564
2565   if (EQ (prop, Qface))
2566     {
2567       XGLYPH (obj)->face = Fget_face (value);
2568       return 1;
2569     }
2570
2571   external_plist_put (&XGLYPH (obj)->plist, prop, value, 0, ERROR_ME);
2572   return 1;
2573 }
2574
2575 static int
2576 glyph_remprop (Lisp_Object obj, Lisp_Object prop)
2577 {
2578   if ((EQ (prop, Qimage))     ||
2579       (EQ (prop, Qcontrib_p)) ||
2580       (EQ (prop, Qbaseline)))
2581     return -1;
2582
2583   if (EQ (prop, Qface))
2584     {
2585       XGLYPH (obj)->face = Qnil;
2586       return 1;
2587     }
2588
2589   return external_remprop (&XGLYPH (obj)->plist, prop, 0, ERROR_ME);
2590 }
2591
2592 static Lisp_Object
2593 glyph_plist (Lisp_Object obj)
2594 {
2595   struct Lisp_Glyph *glyph = XGLYPH (obj);
2596   Lisp_Object result = glyph->plist;
2597
2598   result = cons3 (Qface,      glyph->face,      result);
2599   result = cons3 (Qbaseline,  glyph->baseline,  result);
2600   result = cons3 (Qcontrib_p, glyph->contrib_p, result);
2601   result = cons3 (Qimage,     glyph->image,     result);
2602
2603   return result;
2604 }
2605
2606 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("glyph", glyph,
2607                                           mark_glyph, print_glyph, 0,
2608                                           glyph_equal, glyph_hash,
2609                                           glyph_getprop, glyph_putprop,
2610                                           glyph_remprop, glyph_plist,
2611                                           struct Lisp_Glyph);
2612 \f
2613 Lisp_Object
2614 allocate_glyph (enum glyph_type type,
2615                 void (*after_change) (Lisp_Object glyph, Lisp_Object property,
2616                                       Lisp_Object locale))
2617 {
2618   /* This function can GC */
2619   Lisp_Object obj = Qnil;
2620   struct Lisp_Glyph *g =
2621     alloc_lcrecord_type (struct Lisp_Glyph, lrecord_glyph);
2622
2623   g->type = type;
2624   g->image = Fmake_specifier (Qimage); /* This function can GC */
2625   switch (g->type)
2626     {
2627     case GLYPH_BUFFER:
2628       XIMAGE_SPECIFIER_ALLOWED (g->image) =
2629         IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK | IMAGE_MONO_PIXMAP_MASK |
2630           IMAGE_COLOR_PIXMAP_MASK | IMAGE_SUBWINDOW_MASK;
2631       break;
2632     case GLYPH_POINTER:
2633       XIMAGE_SPECIFIER_ALLOWED (g->image) =
2634         IMAGE_NOTHING_MASK | IMAGE_POINTER_MASK;
2635       break;
2636     case GLYPH_ICON:
2637       XIMAGE_SPECIFIER_ALLOWED (g->image) =
2638         IMAGE_NOTHING_MASK | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK;
2639       break;
2640     default:
2641       abort ();
2642     }
2643
2644   /* I think Fmake_specifier can GC.  I think set_specifier_fallback can GC. */
2645   /* We're getting enough reports of odd behavior in this area it seems */
2646   /* best to GCPRO everything. */
2647   {
2648     Lisp_Object tem1 = list1 (Fcons (Qnil, Vthe_nothing_vector));
2649     Lisp_Object tem2 = list1 (Fcons (Qnil, Qt));
2650     Lisp_Object tem3 = list1 (Fcons (Qnil, Qnil));
2651     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2652
2653     GCPRO4 (obj, tem1, tem2, tem3);
2654
2655     set_specifier_fallback (g->image, tem1);
2656     g->contrib_p = Fmake_specifier (Qboolean);
2657     set_specifier_fallback (g->contrib_p, tem2);
2658     /* #### should have a specifier for the following */
2659     g->baseline = Fmake_specifier (Qgeneric);
2660     set_specifier_fallback (g->baseline, tem3);
2661     g->face = Qnil;
2662     g->plist = Qnil;
2663     g->after_change = after_change;
2664     XSETGLYPH (obj, g);
2665
2666     set_image_attached_to (g->image, obj, Qimage);
2667     UNGCPRO;
2668   }
2669
2670   return obj;
2671 }
2672
2673 static enum glyph_type
2674 decode_glyph_type (Lisp_Object type, Error_behavior errb)
2675 {
2676   if (NILP (type))
2677     return GLYPH_BUFFER;
2678
2679   if (ERRB_EQ (errb, ERROR_ME))
2680     CHECK_SYMBOL (type);
2681
2682   if (EQ (type, Qbuffer))  return GLYPH_BUFFER;
2683   if (EQ (type, Qpointer)) return GLYPH_POINTER;
2684   if (EQ (type, Qicon))    return GLYPH_ICON;
2685
2686   maybe_signal_simple_error ("Invalid glyph type", type, Qimage, errb);
2687
2688   return GLYPH_UNKNOWN;
2689 }
2690
2691 static int
2692 valid_glyph_type_p (Lisp_Object type)
2693 {
2694   return !NILP (memq_no_quit (type, Vglyph_type_list));
2695 }
2696
2697 DEFUN ("valid-glyph-type-p", Fvalid_glyph_type_p, 1, 1, 0, /*
2698 Given a GLYPH-TYPE, return non-nil if it is valid.
2699 Valid types are `buffer', `pointer', and `icon'.
2700 */
2701        (glyph_type))
2702 {
2703   return valid_glyph_type_p (glyph_type) ? Qt : Qnil;
2704 }
2705
2706 DEFUN ("glyph-type-list", Fglyph_type_list, 0, 0, 0, /*
2707 Return a list of valid glyph types.
2708 */
2709        ())
2710 {
2711   return Fcopy_sequence (Vglyph_type_list);
2712 }
2713
2714 DEFUN ("make-glyph-internal", Fmake_glyph_internal, 0, 1, 0, /*
2715 Create and return a new uninitialized glyph or type TYPE.
2716
2717 TYPE specifies the type of the glyph; this should be one of `buffer',
2718 `pointer', or `icon', and defaults to `buffer'.  The type of the glyph
2719 specifies in which contexts the glyph can be used, and controls the
2720 allowable image types into which the glyph's image can be
2721 instantiated.
2722
2723 `buffer' glyphs can be used as the begin-glyph or end-glyph of an
2724 extent, in the modeline, and in the toolbar.  Their image can be
2725 instantiated as `nothing', `mono-pixmap', `color-pixmap', `text',
2726 and `subwindow'.
2727
2728 `pointer' glyphs can be used to specify the mouse pointer.  Their
2729 image can be instantiated as `pointer'.
2730
2731 `icon' glyphs can be used to specify the icon used when a frame is
2732 iconified.  Their image can be instantiated as `mono-pixmap' and
2733 `color-pixmap'.
2734 */
2735        (type))
2736 {
2737   enum glyph_type typeval = decode_glyph_type (type, ERROR_ME);
2738   return allocate_glyph (typeval, 0);
2739 }
2740
2741 DEFUN ("glyphp", Fglyphp, 1, 1, 0, /*
2742 Return non-nil if OBJECT is a glyph.
2743
2744 A glyph is an object used for pixmaps and the like.  It is used
2745 in begin-glyphs and end-glyphs attached to extents, in marginal and textual
2746 annotations, in overlay arrows (overlay-arrow-* variables), in toolbar
2747 buttons, and the like.  Its image is described using an image specifier --
2748 see `image-specifier-p'.
2749 */
2750        (object))
2751 {
2752   return GLYPHP (object) ? Qt : Qnil;
2753 }
2754
2755 DEFUN ("glyph-type", Fglyph_type, 1, 1, 0, /*
2756 Return the type of the given glyph.
2757 The return value will be one of 'buffer, 'pointer, or 'icon.
2758 */
2759        (glyph))
2760 {
2761   CHECK_GLYPH (glyph);
2762   switch (XGLYPH_TYPE (glyph))
2763     {
2764     case GLYPH_BUFFER:  return Qbuffer;
2765     case GLYPH_POINTER: return Qpointer;
2766     case GLYPH_ICON:    return Qicon;
2767     default:
2768       abort ();
2769       return Qnil; /* not reached */
2770     }
2771 }
2772
2773 /*****************************************************************************
2774  glyph_width
2775
2776  Return the width of the given GLYPH on the given WINDOW.  If the
2777  instance is a string then the width is calculated using the font of
2778  the given FACE, unless a face is defined by the glyph itself.
2779  ****************************************************************************/
2780 unsigned short
2781 glyph_width (Lisp_Object glyph, Lisp_Object frame_face,
2782              face_index window_findex, Lisp_Object window)
2783 {
2784   Lisp_Object instance;
2785   Lisp_Object frame = XWINDOW (window)->frame;
2786
2787   /* #### We somehow need to distinguish between the user causing this
2788      error condition and a bug causing it. */
2789   if (!GLYPHP (glyph))
2790     return 0;
2791   else
2792     instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
2793
2794   if (!IMAGE_INSTANCEP (instance))
2795     return 0;
2796
2797   switch (XIMAGE_INSTANCE_TYPE (instance))
2798     {
2799     case IMAGE_TEXT:
2800       {
2801         Lisp_Object str = XIMAGE_INSTANCE_TEXT_STRING (instance);
2802         Lisp_Object private_face = XGLYPH_FACE(glyph);
2803
2804         if (!NILP (private_face))
2805           return redisplay_frame_text_width_string (XFRAME (frame),
2806                                                     private_face,
2807                                                     0, str, 0, -1);
2808         else
2809         if (!NILP (frame_face))
2810           return redisplay_frame_text_width_string (XFRAME (frame),
2811                                                     frame_face,
2812                                                     0, str, 0, -1);
2813         else
2814           return redisplay_text_width_string (XWINDOW (window),
2815                                               window_findex,
2816                                               0, str, 0, -1);
2817       }
2818
2819     case IMAGE_MONO_PIXMAP:
2820     case IMAGE_COLOR_PIXMAP:
2821     case IMAGE_POINTER:
2822       return XIMAGE_INSTANCE_PIXMAP_WIDTH (instance);
2823
2824     case IMAGE_NOTHING:
2825       return 0;
2826
2827     case IMAGE_SUBWINDOW:
2828       /* #### implement me */
2829       return 0;
2830
2831     default:
2832       abort ();
2833       return 0;
2834     }
2835 }
2836
2837 DEFUN ("glyph-width", Fglyph_width, 1, 2, 0, /*
2838 Return the width of GLYPH on WINDOW.
2839 This may not be exact as it does not take into account all of the context
2840 that redisplay will.
2841 */
2842        (glyph, window))
2843 {
2844   XSETWINDOW (window, decode_window (window));
2845   CHECK_GLYPH (glyph);
2846
2847   return make_int (glyph_width (glyph, Qnil, DEFAULT_INDEX, window));
2848 }
2849
2850 #define RETURN_ASCENT   0
2851 #define RETURN_DESCENT  1
2852 #define RETURN_HEIGHT   2
2853
2854 Lisp_Object
2855 glyph_image_instance (Lisp_Object glyph, Lisp_Object domain,
2856                       Error_behavior errb, int no_quit)
2857 {
2858   Lisp_Object specifier = GLYPH_IMAGE (XGLYPH (glyph));
2859
2860   /* This can never return Qunbound.  All glyphs have 'nothing as
2861      a fallback. */
2862   return specifier_instance (specifier, Qunbound, domain, errb, no_quit, 0,
2863                              Qzero);
2864 }
2865
2866 static unsigned short
2867 glyph_height_internal (Lisp_Object glyph, Lisp_Object frame_face,
2868                        face_index window_findex, Lisp_Object window,
2869                        int function)
2870 {
2871   Lisp_Object instance;
2872   Lisp_Object frame = XWINDOW (window)->frame;
2873
2874   if (!GLYPHP (glyph))
2875     return 0;
2876   else
2877     instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
2878
2879   if (!IMAGE_INSTANCEP (instance))
2880     return 0;
2881
2882   switch (XIMAGE_INSTANCE_TYPE (instance))
2883     {
2884     case IMAGE_TEXT:
2885       {
2886         struct font_metric_info fm;
2887         Lisp_Object string = XIMAGE_INSTANCE_TEXT_STRING (instance);
2888         unsigned char charsets[NUM_LEADING_BYTES];
2889         struct face_cachel frame_cachel;
2890         struct face_cachel *cachel;
2891
2892         find_charsets_in_bufbyte_string (charsets,
2893                                          XSTRING_DATA   (string),
2894                                          XSTRING_LENGTH (string));
2895
2896         if (!NILP (frame_face))
2897           {
2898             reset_face_cachel (&frame_cachel);
2899             update_face_cachel_data (&frame_cachel, frame, frame_face);
2900             cachel = &frame_cachel;
2901           }
2902         else
2903           cachel = WINDOW_FACE_CACHEL (XWINDOW (window), window_findex);
2904         ensure_face_cachel_complete (cachel, window, charsets);
2905
2906         face_cachel_charset_font_metric_info (cachel, charsets, &fm);
2907
2908         switch (function)
2909           {
2910           case RETURN_ASCENT:  return fm.ascent;
2911           case RETURN_DESCENT: return fm.descent;
2912           case RETURN_HEIGHT:  return fm.ascent + fm.descent;
2913           default:
2914             abort ();
2915             return 0; /* not reached */
2916           }
2917       }
2918
2919     case IMAGE_MONO_PIXMAP:
2920     case IMAGE_COLOR_PIXMAP:
2921     case IMAGE_POINTER:
2922       /* #### Ugh ugh ugh -- temporary crap */
2923       if (function == RETURN_ASCENT || function == RETURN_HEIGHT)
2924         return XIMAGE_INSTANCE_PIXMAP_HEIGHT (instance);
2925       else
2926         return 0;
2927
2928     case IMAGE_NOTHING:
2929       return 0;
2930
2931     case IMAGE_SUBWINDOW:
2932       /* #### implement me */
2933       return 0;
2934
2935     default:
2936       abort ();
2937       return 0;
2938     }
2939 }
2940
2941 unsigned short
2942 glyph_ascent (Lisp_Object glyph, Lisp_Object frame_face,
2943               face_index window_findex, Lisp_Object window)
2944 {
2945   return glyph_height_internal (glyph, frame_face, window_findex, window,
2946                                 RETURN_ASCENT);
2947 }
2948
2949 unsigned short
2950 glyph_descent (Lisp_Object glyph, Lisp_Object frame_face,
2951                face_index window_findex, Lisp_Object window)
2952 {
2953   return glyph_height_internal (glyph, frame_face, window_findex, window,
2954                                 RETURN_DESCENT);
2955 }
2956
2957 /* strictly a convenience function. */
2958 unsigned short
2959 glyph_height (Lisp_Object glyph, Lisp_Object frame_face,
2960               face_index window_findex, Lisp_Object window)
2961 {
2962   return glyph_height_internal (glyph, frame_face, window_findex, window,
2963                                 RETURN_HEIGHT);
2964 }
2965
2966 DEFUN ("glyph-ascent", Fglyph_ascent, 1, 2, 0, /*
2967 Return the ascent value of GLYPH on WINDOW.
2968 This may not be exact as it does not take into account all of the context
2969 that redisplay will.
2970 */
2971        (glyph, window))
2972 {
2973   XSETWINDOW (window, decode_window (window));
2974   CHECK_GLYPH (glyph);
2975
2976   return make_int (glyph_ascent (glyph, Qnil, DEFAULT_INDEX, window));
2977 }
2978
2979 DEFUN ("glyph-descent", Fglyph_descent, 1, 2, 0, /*
2980 Return the descent value of GLYPH on WINDOW.
2981 This may not be exact as it does not take into account all of the context
2982 that redisplay will.
2983 */
2984        (glyph, window))
2985 {
2986   XSETWINDOW (window, decode_window (window));
2987   CHECK_GLYPH (glyph);
2988
2989   return make_int (glyph_descent (glyph, Qnil, DEFAULT_INDEX, window));
2990 }
2991
2992 /* This is redundant but I bet a lot of people expect it to exist. */
2993 DEFUN ("glyph-height", Fglyph_height, 1, 2, 0, /*
2994 Return the height of GLYPH on WINDOW.
2995 This may not be exact as it does not take into account all of the context
2996 that redisplay will.
2997 */
2998        (glyph, window))
2999 {
3000   XSETWINDOW (window, decode_window (window));
3001   CHECK_GLYPH (glyph);
3002
3003   return make_int (glyph_height (glyph, Qnil, DEFAULT_INDEX, window));
3004 }
3005
3006 #undef RETURN_ASCENT
3007 #undef RETURN_DESCENT
3008 #undef RETURN_HEIGHT
3009
3010 /* #### do we need to cache this info to speed things up? */
3011
3012 Lisp_Object
3013 glyph_baseline (Lisp_Object glyph, Lisp_Object domain)
3014 {
3015   if (!GLYPHP (glyph))
3016     return Qnil;
3017   else
3018     {
3019       Lisp_Object retval =
3020         specifier_instance_no_quit (GLYPH_BASELINE (XGLYPH (glyph)),
3021                                     /* #### look into ERROR_ME_NOT */
3022                                     Qunbound, domain, ERROR_ME_NOT,
3023                                     0, Qzero);
3024       if (!NILP (retval) && !INTP (retval))
3025         retval = Qnil;
3026       else if (INTP (retval))
3027         {
3028           if (XINT (retval) < 0)
3029             retval = Qzero;
3030           if (XINT (retval) > 100)
3031             retval = make_int (100);
3032         }
3033       return retval;
3034     }
3035 }
3036
3037 Lisp_Object
3038 glyph_face (Lisp_Object glyph, Lisp_Object domain)
3039 {
3040   /* #### Domain parameter not currently used but it will be */
3041   return GLYPHP (glyph) ? GLYPH_FACE (XGLYPH (glyph)) : Qnil;
3042 }
3043
3044 int
3045 glyph_contrib_p (Lisp_Object glyph, Lisp_Object domain)
3046 {
3047   if (!GLYPHP (glyph))
3048     return 0;
3049   else
3050     return !NILP (specifier_instance_no_quit
3051                   (GLYPH_CONTRIB_P (XGLYPH (glyph)), Qunbound, domain,
3052                    /* #### look into ERROR_ME_NOT */
3053                    ERROR_ME_NOT, 0, Qzero));
3054 }
3055
3056 static void
3057 glyph_property_was_changed (Lisp_Object glyph, Lisp_Object property,
3058                             Lisp_Object locale)
3059 {
3060   if (XGLYPH (glyph)->after_change)
3061     (XGLYPH (glyph)->after_change) (glyph, property, locale);
3062 }
3063
3064 \f
3065 /*****************************************************************************
3066  *                     glyph cachel functions                                *
3067  *****************************************************************************/
3068
3069 /*
3070  #### All of this is 95% copied from face cachels.
3071       Consider consolidating.
3072  #### We need to add a dirty flag to the glyphs.
3073  */
3074
3075 void
3076 mark_glyph_cachels (glyph_cachel_dynarr *elements,
3077                     void (*markobj) (Lisp_Object))
3078 {
3079   int elt;
3080
3081   if (!elements)
3082     return;
3083
3084   for (elt = 0; elt < Dynarr_length (elements); elt++)
3085     {
3086       struct glyph_cachel *cachel = Dynarr_atp (elements, elt);
3087       ((markobj) (cachel->glyph));
3088     }
3089 }
3090
3091 static void
3092 update_glyph_cachel_data (struct window *w, Lisp_Object glyph,
3093                           struct glyph_cachel *cachel)
3094 {
3095   /* #### This should be || !cachel->updated */
3096   if (NILP (cachel->glyph) || !EQ (cachel->glyph, glyph))
3097     {
3098       Lisp_Object window;
3099
3100       XSETWINDOW (window, w);
3101
3102     /* #### This could be sped up if we redid things to grab the glyph
3103        instantiation and passed it to the size functions. */
3104       cachel->glyph   = glyph;
3105       cachel->width   = glyph_width   (glyph, Qnil, DEFAULT_INDEX, window);
3106       cachel->ascent  = glyph_ascent  (glyph, Qnil, DEFAULT_INDEX, window);
3107       cachel->descent = glyph_descent (glyph, Qnil, DEFAULT_INDEX, window);
3108     }
3109
3110   cachel->updated = 1;
3111 }
3112
3113 static void
3114 add_glyph_cachel (struct window *w, Lisp_Object glyph)
3115 {
3116   struct glyph_cachel new_cachel;
3117
3118   xzero (new_cachel);
3119   new_cachel.glyph = Qnil;
3120
3121   update_glyph_cachel_data (w, glyph, &new_cachel);
3122   Dynarr_add (w->glyph_cachels, new_cachel);
3123 }
3124
3125 static glyph_index
3126 get_glyph_cachel_index (struct window *w, Lisp_Object glyph)
3127 {
3128   int elt;
3129
3130   if (noninteractive)
3131     return 0;
3132
3133   for (elt = 0; elt < Dynarr_length (w->glyph_cachels); elt++)
3134     {
3135       struct glyph_cachel *cachel =
3136         Dynarr_atp (w->glyph_cachels, elt);
3137
3138       if (EQ (cachel->glyph, glyph) && !NILP (glyph))
3139         {
3140           if (!cachel->updated)
3141             update_glyph_cachel_data (w, glyph, cachel);
3142           return elt;
3143         }
3144     }
3145
3146   /* If we didn't find the glyph, add it and then return its index. */
3147   add_glyph_cachel (w, glyph);
3148   return elt;
3149 }
3150
3151 void
3152 reset_glyph_cachels (struct window *w)
3153 {
3154   Dynarr_reset (w->glyph_cachels);
3155   get_glyph_cachel_index (w, Vcontinuation_glyph);
3156   get_glyph_cachel_index (w, Vtruncation_glyph);
3157   get_glyph_cachel_index (w, Vhscroll_glyph);
3158   get_glyph_cachel_index (w, Vcontrol_arrow_glyph);
3159   get_glyph_cachel_index (w, Voctal_escape_glyph);
3160   get_glyph_cachel_index (w, Vinvisible_text_glyph);
3161 }
3162
3163 void
3164 mark_glyph_cachels_as_not_updated (struct window *w)
3165 {
3166   int elt;
3167
3168   /* We need to have a dirty flag to tell if the glyph has changed.
3169      We can check to see if each glyph variable is actually a
3170      completely different glyph, though. */
3171 #define FROB(glyph_obj, gindex)                                         \
3172   update_glyph_cachel_data (w, glyph_obj,                               \
3173                               Dynarr_atp (w->glyph_cachels, gindex))
3174
3175   FROB (Vcontinuation_glyph, CONT_GLYPH_INDEX);
3176   FROB (Vtruncation_glyph, TRUN_GLYPH_INDEX);
3177   FROB (Vhscroll_glyph, HSCROLL_GLYPH_INDEX);
3178   FROB (Vcontrol_arrow_glyph, CONTROL_GLYPH_INDEX);
3179   FROB (Voctal_escape_glyph, OCT_ESC_GLYPH_INDEX);
3180   FROB (Vinvisible_text_glyph, INVIS_GLYPH_INDEX);
3181 #undef FROB
3182
3183   for (elt = 0; elt < Dynarr_length (w->glyph_cachels); elt++)
3184     Dynarr_atp (w->glyph_cachels, elt)->updated = 0;
3185 }
3186
3187 #ifdef MEMORY_USAGE_STATS
3188
3189 int
3190 compute_glyph_cachel_usage (glyph_cachel_dynarr *glyph_cachels,
3191                             struct overhead_stats *ovstats)
3192 {
3193   int total = 0;
3194
3195   if (glyph_cachels)
3196     total += Dynarr_memory_usage (glyph_cachels, ovstats);
3197
3198   return total;
3199 }
3200
3201 #endif /* MEMORY_USAGE_STATS */
3202
3203 \f
3204 /*****************************************************************************
3205  *                              display tables                               *
3206  *****************************************************************************/
3207
3208 /* Get the display table for use currently on window W with face FACE.
3209    Precedence:
3210
3211    -- FACE's display table
3212    -- W's display table (comes from specifier `current-display-table')
3213
3214    Ignore the specified tables if they are not valid;
3215    if no valid table is specified, return 0.  */
3216
3217 struct Lisp_Vector *
3218 get_display_table (struct window *w, face_index findex)
3219 {
3220   Lisp_Object tem;
3221
3222   tem = WINDOW_FACE_CACHEL_DISPLAY_TABLE (w, findex);
3223   if (VECTORP (tem) && XVECTOR_LENGTH (tem) == DISP_TABLE_SIZE)
3224     return XVECTOR (tem);
3225
3226   tem = w->display_table;
3227   if (VECTORP (tem) && XVECTOR_LENGTH (tem) == DISP_TABLE_SIZE)
3228     return XVECTOR (tem);
3229
3230   return 0;
3231 }
3232
3233 \f
3234 /*****************************************************************************
3235  *                              initialization                               *
3236  *****************************************************************************/
3237
3238 void
3239 syms_of_glyphs (void)
3240 {
3241   /* image instantiators */
3242
3243   DEFSUBR (Fimage_instantiator_format_list);
3244   DEFSUBR (Fvalid_image_instantiator_format_p);
3245   DEFSUBR (Fset_console_type_image_conversion_list);
3246   DEFSUBR (Fconsole_type_image_conversion_list);
3247
3248   defkeyword (&Q_file, ":file");
3249   defkeyword (&Q_data, ":data");
3250   defkeyword (&Q_face, ":face");
3251
3252 #ifdef HAVE_XPM
3253   defkeyword (&Q_color_symbols, ":color-symbols");
3254 #endif
3255 #ifdef HAVE_WINDOW_SYSTEM
3256   defkeyword (&Q_mask_file, ":mask-file");
3257   defkeyword (&Q_mask_data, ":mask-data");
3258   defkeyword (&Q_hotspot_x, ":hotspot-x");
3259   defkeyword (&Q_hotspot_y, ":hotspot-y");
3260   defkeyword (&Q_foreground, ":foreground");
3261   defkeyword (&Q_background, ":background");
3262 #endif
3263   /* image specifiers */
3264
3265   DEFSUBR (Fimage_specifier_p);
3266   /* Qimage in general.c */
3267
3268   /* image instances */
3269
3270   defsymbol (&Qimage_instancep, "image-instance-p");
3271
3272   defsymbol (&Qnothing_image_instance_p, "nothing-image-instance-p");
3273   defsymbol (&Qtext_image_instance_p, "text-image-instance-p");
3274   defsymbol (&Qmono_pixmap_image_instance_p, "mono-pixmap-image-instance-p");
3275   defsymbol (&Qcolor_pixmap_image_instance_p, "color-pixmap-image-instance-p");
3276   defsymbol (&Qpointer_image_instance_p, "pointer-image-instance-p");
3277   defsymbol (&Qsubwindow_image_instance_p, "subwindow-image-instance-p");
3278
3279   DEFSUBR (Fmake_image_instance);
3280   DEFSUBR (Fimage_instance_p);
3281   DEFSUBR (Fimage_instance_type);
3282   DEFSUBR (Fvalid_image_instance_type_p);
3283   DEFSUBR (Fimage_instance_type_list);
3284   DEFSUBR (Fimage_instance_name);
3285   DEFSUBR (Fimage_instance_string);
3286   DEFSUBR (Fimage_instance_file_name);
3287   DEFSUBR (Fimage_instance_mask_file_name);
3288   DEFSUBR (Fimage_instance_depth);
3289   DEFSUBR (Fimage_instance_height);
3290   DEFSUBR (Fimage_instance_width);
3291   DEFSUBR (Fimage_instance_hotspot_x);
3292   DEFSUBR (Fimage_instance_hotspot_y);
3293   DEFSUBR (Fimage_instance_foreground);
3294   DEFSUBR (Fimage_instance_background);
3295   DEFSUBR (Fcolorize_image_instance);
3296
3297   /* Qnothing defined as part of the "nothing" image-instantiator
3298      type. */
3299   /* Qtext defined in general.c */
3300   defsymbol (&Qmono_pixmap, "mono-pixmap");
3301   defsymbol (&Qcolor_pixmap, "color-pixmap");
3302   /* Qpointer defined in general.c */
3303   defsymbol (&Qsubwindow, "subwindow");
3304
3305   /* glyphs */
3306
3307   defsymbol (&Qglyphp, "glyphp");
3308   defsymbol (&Qcontrib_p, "contrib-p");
3309   defsymbol (&Qbaseline, "baseline");
3310
3311   defsymbol (&Qbuffer_glyph_p, "buffer-glyph-p");
3312   defsymbol (&Qpointer_glyph_p, "pointer-glyph-p");
3313   defsymbol (&Qicon_glyph_p, "icon-glyph-p");
3314
3315   defsymbol (&Qconst_glyph_variable, "const-glyph-variable");
3316
3317   DEFSUBR (Fglyph_type);
3318   DEFSUBR (Fvalid_glyph_type_p);
3319   DEFSUBR (Fglyph_type_list);
3320   DEFSUBR (Fglyphp);
3321   DEFSUBR (Fmake_glyph_internal);
3322   DEFSUBR (Fglyph_width);
3323   DEFSUBR (Fglyph_ascent);
3324   DEFSUBR (Fglyph_descent);
3325   DEFSUBR (Fglyph_height);
3326
3327   /* Qbuffer defined in general.c. */
3328   /* Qpointer defined above */
3329
3330   /* Errors */
3331   deferror (&Qimage_conversion_error,
3332             "image-conversion-error",
3333             "image-conversion error", Qio_error);
3334
3335 }
3336
3337 void
3338 specifier_type_create_image (void)
3339 {
3340   /* image specifiers */
3341
3342   INITIALIZE_SPECIFIER_TYPE_WITH_DATA (image, "image", "imagep");
3343
3344   SPECIFIER_HAS_METHOD (image, create);
3345   SPECIFIER_HAS_METHOD (image, mark);
3346   SPECIFIER_HAS_METHOD (image, instantiate);
3347   SPECIFIER_HAS_METHOD (image, validate);
3348   SPECIFIER_HAS_METHOD (image, after_change);
3349   SPECIFIER_HAS_METHOD (image, going_to_add);
3350 }
3351
3352 void
3353 image_instantiator_format_create (void)
3354 {
3355   /* image instantiators */
3356
3357   the_image_instantiator_format_entry_dynarr =
3358     Dynarr_new (image_instantiator_format_entry);
3359
3360   Vimage_instantiator_format_list = Qnil;
3361   staticpro (&Vimage_instantiator_format_list);
3362
3363   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (nothing, "nothing");
3364
3365   IIFORMAT_HAS_METHOD (nothing, possible_dest_types);
3366   IIFORMAT_HAS_METHOD (nothing, instantiate);
3367
3368   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (inherit, "inherit");
3369
3370   IIFORMAT_HAS_METHOD (inherit, validate);
3371   IIFORMAT_HAS_METHOD (inherit, normalize);
3372   IIFORMAT_HAS_METHOD (inherit, possible_dest_types);
3373   IIFORMAT_HAS_METHOD (inherit, instantiate);
3374
3375   IIFORMAT_VALID_KEYWORD (inherit, Q_face, check_valid_face);
3376
3377   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (string, "string");
3378
3379   IIFORMAT_HAS_METHOD (string, validate);
3380   IIFORMAT_HAS_METHOD (string, possible_dest_types);
3381   IIFORMAT_HAS_METHOD (string, instantiate);
3382
3383   IIFORMAT_VALID_KEYWORD (string, Q_data, check_valid_string);
3384
3385   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (formatted_string, "formatted-string");
3386
3387   IIFORMAT_HAS_METHOD (formatted_string, validate);
3388   IIFORMAT_HAS_METHOD (formatted_string, possible_dest_types);
3389   IIFORMAT_HAS_METHOD (formatted_string, instantiate);
3390
3391   IIFORMAT_VALID_KEYWORD (formatted_string, Q_data, check_valid_string);
3392
3393 #ifdef HAVE_WINDOW_SYSTEM
3394   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (xbm, "xbm");
3395
3396   IIFORMAT_HAS_METHOD (xbm, validate);
3397   IIFORMAT_HAS_METHOD (xbm, normalize);
3398   IIFORMAT_HAS_METHOD (xbm, possible_dest_types);
3399   IIFORMAT_HAS_METHOD (xbm, instantiate);
3400
3401   IIFORMAT_VALID_KEYWORD (xbm, Q_data, check_valid_xbm_inline);
3402   IIFORMAT_VALID_KEYWORD (xbm, Q_file, check_valid_string);
3403   IIFORMAT_VALID_KEYWORD (xbm, Q_mask_data, check_valid_xbm_inline);
3404   IIFORMAT_VALID_KEYWORD (xbm, Q_mask_file, check_valid_string);
3405   IIFORMAT_VALID_KEYWORD (xbm, Q_hotspot_x, check_valid_int);
3406   IIFORMAT_VALID_KEYWORD (xbm, Q_hotspot_y, check_valid_int);
3407   IIFORMAT_VALID_KEYWORD (xbm, Q_foreground, check_valid_string);
3408   IIFORMAT_VALID_KEYWORD (xbm, Q_background, check_valid_string);
3409 #endif /* HAVE_WINDOW_SYSTEM */
3410
3411 #ifdef HAVE_XPM
3412   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (xpm, "xpm");
3413
3414   IIFORMAT_HAS_METHOD (xpm, validate);
3415   IIFORMAT_HAS_METHOD (xpm, normalize);
3416   IIFORMAT_HAS_METHOD (xpm, possible_dest_types);
3417   IIFORMAT_HAS_METHOD (xpm, instantiate);
3418
3419   IIFORMAT_VALID_KEYWORD (xpm, Q_data, check_valid_string);
3420   IIFORMAT_VALID_KEYWORD (xpm, Q_file, check_valid_string);
3421   IIFORMAT_VALID_KEYWORD (xpm, Q_color_symbols, check_valid_xpm_color_symbols);
3422 #endif /* HAVE_XPM */
3423 }
3424
3425 void
3426 vars_of_glyphs (void)
3427 {
3428   Vthe_nothing_vector = vector1 (Qnothing);
3429   staticpro (&Vthe_nothing_vector);
3430
3431   /* image instances */
3432
3433   Vimage_instance_type_list = list6 (Qnothing, Qtext, Qmono_pixmap,
3434                                      Qcolor_pixmap, Qpointer, Qsubwindow);
3435   staticpro (&Vimage_instance_type_list);
3436
3437   /* glyphs */
3438
3439   Vglyph_type_list = list3 (Qbuffer, Qpointer, Qicon);
3440   staticpro (&Vglyph_type_list);
3441
3442   /* The octal-escape glyph, control-arrow-glyph and
3443      invisible-text-glyph are completely initialized in glyphs.el */
3444
3445   DEFVAR_LISP ("octal-escape-glyph", &Voctal_escape_glyph /*
3446 What to prefix character codes displayed in octal with.
3447 */);
3448   Voctal_escape_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
3449
3450   DEFVAR_LISP ("control-arrow-glyph", &Vcontrol_arrow_glyph /*
3451 What to use as an arrow for control characters.
3452 */);
3453   Vcontrol_arrow_glyph = allocate_glyph (GLYPH_BUFFER,
3454                                          redisplay_glyph_changed);
3455
3456   DEFVAR_LISP ("invisible-text-glyph", &Vinvisible_text_glyph /*
3457 What to use to indicate the presence of invisible text.
3458 This is the glyph that is displayed when an ellipsis is called for
3459 \(see `selective-display-ellipses' and `buffer-invisibility-spec').
3460 Normally this is three dots ("...").
3461 */);
3462   Vinvisible_text_glyph = allocate_glyph (GLYPH_BUFFER,
3463                                           redisplay_glyph_changed);
3464
3465   /* Partially initialized in glyphs.el */
3466   DEFVAR_LISP ("hscroll-glyph", &Vhscroll_glyph /*
3467 What to display at the beginning of horizontally scrolled lines.
3468 */);
3469   Vhscroll_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
3470
3471 #ifdef HAVE_XPM
3472   Fprovide (Qxpm);
3473
3474   DEFVAR_LISP ("xpm-color-symbols", &Vxpm_color_symbols /*
3475 Definitions of logical color-names used when reading XPM files.
3476 Elements of this list should be of the form (COLOR-NAME FORM-TO-EVALUATE).
3477 The COLOR-NAME should be a string, which is the name of the color to define;
3478 the FORM should evaluate to a `color' specifier object, or a string to be
3479 passed to `make-color-instance'.  If a loaded XPM file references a symbolic
3480 color called COLOR-NAME, it will display as the computed color instead.
3481
3482 The default value of this variable defines the logical color names
3483 \"foreground\" and \"background\" to be the colors of the `default' face.
3484 */ );
3485   Vxpm_color_symbols = Qnil; /* initialized in x-faces.el */
3486 #endif /* HAVE_XPM */
3487 }
3488
3489 void
3490 specifier_vars_of_glyphs (void)
3491 {
3492   /* #### Can we GC here? The set_specifier_* calls definitely need */
3493   /* protection. */
3494   /* display tables */
3495
3496   DEFVAR_SPECIFIER ("current-display-table", &Vcurrent_display_table /*
3497 *The display table currently in use.
3498 This is a specifier; use `set-specifier' to change it.
3499 The display table is a vector created with `make-display-table'.
3500 The 256 elements control how to display each possible text character.
3501 Each value should be a string, a glyph, a vector or nil.
3502 If a value is a vector it must be composed only of strings and glyphs.
3503 nil means display the character in the default fashion.
3504 Faces can have their own, overriding display table.
3505 */ );
3506   Vcurrent_display_table = Fmake_specifier (Qdisplay_table);
3507   set_specifier_fallback (Vcurrent_display_table,
3508                           list1 (Fcons (Qnil, Qnil)));
3509   set_specifier_caching (Vcurrent_display_table,
3510                          slot_offset (struct window,
3511                                       display_table),
3512                          some_window_value_changed,
3513                          0, 0);
3514 }
3515
3516 void
3517 complex_vars_of_glyphs (void)
3518 {
3519   /* Partially initialized in glyphs-x.c, glyphs.el */
3520   DEFVAR_LISP ("truncation-glyph", &Vtruncation_glyph /*
3521 What to display at the end of truncated lines.
3522 */ );
3523   Vtruncation_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
3524
3525   /* Partially initialized in glyphs-x.c, glyphs.el */
3526   DEFVAR_LISP ("continuation-glyph", &Vcontinuation_glyph /*
3527 What to display at the end of wrapped lines.
3528 */ );
3529   Vcontinuation_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
3530
3531   /* Partially initialized in glyphs-x.c, glyphs.el */
3532   DEFVAR_LISP ("xemacs-logo", &Vxemacs_logo /*
3533 The glyph used to display the XEmacs logo at startup.
3534 */ );
3535   Vxemacs_logo = allocate_glyph (GLYPH_BUFFER, 0);
3536 }