8444f4a6d35e23095bf79fcf296f6c4c69e882d2
[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 obj1, Lisp_Object obj2, int depth)
677 {
678   struct Lisp_Image_Instance *i1 = XIMAGE_INSTANCE (obj1);
679   struct Lisp_Image_Instance *i2 = XIMAGE_INSTANCE (obj2);
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 #ifdef HAVE_X_WINDOWS
1604 #include <X11/Xlib.h>
1605 #else
1606 #define XFree(data) free(data)
1607 #endif
1608
1609 Lisp_Object
1610 bitmap_to_lisp_data (Lisp_Object name, int *xhot, int *yhot,
1611                      int ok_if_data_invalid)
1612 {
1613   unsigned int w, h;
1614   Extbyte *data;
1615   int result;
1616   CONST char *filename_ext;
1617
1618   GET_C_STRING_FILENAME_DATA_ALLOCA (name, filename_ext);
1619   result = read_bitmap_data_from_file (filename_ext, &w, &h,
1620                                        &data, xhot, yhot);
1621
1622   if (result == BitmapSuccess)
1623     {
1624       Lisp_Object retval;
1625       int len = (w + 7) / 8 * h;
1626
1627       retval = list3 (make_int (w), make_int (h),
1628                       make_ext_string (data, len, FORMAT_BINARY));
1629       XFree ((char *) data);
1630       return retval;
1631     }
1632
1633   switch (result)
1634     {
1635     case BitmapOpenFailed:
1636       {
1637         /* should never happen */
1638         signal_double_file_error ("Opening bitmap file",
1639                                   "no such file or directory",
1640                                   name);
1641       }
1642     case BitmapFileInvalid:
1643       {
1644         if (ok_if_data_invalid)
1645           return Qt;
1646         signal_double_file_error ("Reading bitmap file",
1647                                   "invalid data in file",
1648                                   name);
1649       }
1650     case BitmapNoMemory:
1651       {
1652         signal_double_file_error ("Reading bitmap file",
1653                                   "out of memory",
1654                                   name);
1655       }
1656     default:
1657       {
1658         signal_double_file_error_2 ("Reading bitmap file",
1659                                     "unknown error code",
1660                                     make_int (result), name);
1661       }
1662     }
1663
1664   return Qnil; /* not reached */
1665 }
1666
1667 Lisp_Object
1668 xbm_mask_file_munging (Lisp_Object alist, Lisp_Object file,
1669                        Lisp_Object mask_file, Lisp_Object console_type)
1670 {
1671   /* This is unclean but it's fairly standard -- a number of the
1672      bitmaps in /usr/include/X11/bitmaps use it -- so we support
1673      it. */
1674   if (NILP (mask_file)
1675       /* don't override explicitly specified mask data. */
1676       && NILP (assq_no_quit (Q_mask_data, alist))
1677       && !NILP (file))
1678     {
1679       mask_file = MAYBE_LISP_CONTYPE_METH
1680         (decode_console_type(console_type, ERROR_ME),
1681          locate_pixmap_file, (concat2 (file, build_string ("Mask"))));
1682       if (NILP (mask_file))
1683         mask_file = MAYBE_LISP_CONTYPE_METH
1684           (decode_console_type(console_type, ERROR_ME),
1685            locate_pixmap_file, (concat2 (file, build_string ("msk"))));
1686     }
1687
1688   if (!NILP (mask_file))
1689     {
1690       Lisp_Object mask_data =
1691         bitmap_to_lisp_data (mask_file, 0, 0, 0);
1692       alist = remassq_no_quit (Q_mask_file, alist);
1693       /* there can't be a :mask-data at this point. */
1694       alist = Fcons (Fcons (Q_mask_file, mask_file),
1695                      Fcons (Fcons (Q_mask_data, mask_data), alist));
1696     }
1697
1698   return alist;
1699 }
1700
1701 /* Normalize method for XBM's. */
1702
1703 static Lisp_Object
1704 xbm_normalize (Lisp_Object inst, Lisp_Object console_type)
1705 {
1706   Lisp_Object file = Qnil, mask_file = Qnil;
1707   struct gcpro gcpro1, gcpro2, gcpro3;
1708   Lisp_Object alist = Qnil;
1709
1710   GCPRO3 (file, mask_file, alist);
1711
1712   /* Now, convert any file data into inline data for both the regular
1713      data and the mask data.  At the end of this, `data' will contain
1714      the inline data (if any) or Qnil, and `file' will contain
1715      the name this data was derived from (if known) or Qnil.
1716      Likewise for `mask_file' and `mask_data'.
1717
1718      Note that if we cannot generate any regular inline data, we
1719      skip out. */
1720
1721   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data,
1722                                              console_type);
1723   mask_file = potential_pixmap_file_instantiator (inst, Q_mask_file,
1724                                                   Q_mask_data, console_type);
1725
1726   if (CONSP (file)) /* failure locating filename */
1727     signal_double_file_error ("Opening bitmap file",
1728                               "no such file or directory",
1729                               Fcar (file));
1730
1731   if (NILP (file) && NILP (mask_file)) /* no conversion necessary */
1732     RETURN_UNGCPRO (inst);
1733
1734   alist = tagged_vector_to_alist (inst);
1735
1736   if (!NILP (file))
1737     {
1738       int xhot, yhot;
1739       Lisp_Object data = bitmap_to_lisp_data (file, &xhot, &yhot, 0);
1740       alist = remassq_no_quit (Q_file, alist);
1741       /* there can't be a :data at this point. */
1742       alist = Fcons (Fcons (Q_file, file),
1743                      Fcons (Fcons (Q_data, data), alist));
1744
1745       if (xhot != -1 && NILP (assq_no_quit (Q_hotspot_x, alist)))
1746         alist = Fcons (Fcons (Q_hotspot_x, make_int (xhot)),
1747                        alist);
1748       if (yhot != -1 && NILP (assq_no_quit (Q_hotspot_y, alist)))
1749         alist = Fcons (Fcons (Q_hotspot_y, make_int (yhot)),
1750                        alist);
1751     }
1752
1753   alist = xbm_mask_file_munging (alist, file, mask_file, console_type);
1754
1755   {
1756     Lisp_Object result = alist_to_tagged_vector (Qxbm, alist);
1757     free_alist (alist);
1758     RETURN_UNGCPRO (result);
1759   }
1760 }
1761
1762 \f
1763 static int
1764 xbm_possible_dest_types (void)
1765 {
1766   return
1767     IMAGE_MONO_PIXMAP_MASK  |
1768     IMAGE_COLOR_PIXMAP_MASK |
1769     IMAGE_POINTER_MASK;
1770 }
1771
1772 static void
1773 xbm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1774                  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1775                  int dest_mask, Lisp_Object domain)
1776 {
1777   Lisp_Object device= IMAGE_INSTANCE_DEVICE (XIMAGE_INSTANCE (image_instance));
1778
1779   MAYBE_DEVMETH (XDEVICE (device),
1780                  xbm_instantiate,
1781                  (image_instance, instantiator, pointer_fg,
1782                   pointer_bg, dest_mask, domain));
1783 }
1784
1785 #endif
1786
1787 \f
1788 #ifdef HAVE_XPM
1789
1790 /**********************************************************************
1791  *                             XPM                                    *
1792  **********************************************************************/
1793
1794 Lisp_Object
1795 pixmap_to_lisp_data (Lisp_Object name, int ok_if_data_invalid)
1796 {
1797   char **data;
1798   int result;
1799
1800   result = XpmReadFileToData ((char *) XSTRING_DATA (name), &data);
1801
1802   if (result == XpmSuccess)
1803     {
1804       Lisp_Object retval = Qnil;
1805       struct buffer *old_buffer = current_buffer;
1806       Lisp_Object temp_buffer =
1807         Fget_buffer_create (build_string (" *pixmap conversion*"));
1808       int elt;
1809       int height, width, ncolors;
1810       struct gcpro gcpro1, gcpro2, gcpro3;
1811       int speccount = specpdl_depth ();
1812
1813       GCPRO3 (name, retval, temp_buffer);
1814
1815       specbind (Qinhibit_quit, Qt);
1816       set_buffer_internal (XBUFFER (temp_buffer));
1817       Ferase_buffer (Qnil);
1818
1819       buffer_insert_c_string (current_buffer, "/* XPM */\r");
1820       buffer_insert_c_string (current_buffer, "static char *pixmap[] = {\r");
1821
1822       sscanf (data[0], "%d %d %d", &height, &width, &ncolors);
1823       for (elt = 0; elt <= width + ncolors; elt++)
1824         {
1825           buffer_insert_c_string (current_buffer, "\"");
1826           buffer_insert_c_string (current_buffer, data[elt]);
1827
1828           if (elt < width + ncolors)
1829             buffer_insert_c_string (current_buffer, "\",\r");
1830           else
1831             buffer_insert_c_string (current_buffer, "\"};\r");
1832         }
1833
1834       retval = Fbuffer_substring (Qnil, Qnil, Qnil);
1835       XpmFree (data);
1836
1837       set_buffer_internal (old_buffer);
1838       unbind_to (speccount, Qnil);
1839
1840       RETURN_UNGCPRO (retval);
1841     }
1842
1843   switch (result)
1844     {
1845     case XpmFileInvalid:
1846       {
1847         if (ok_if_data_invalid)
1848           return Qt;
1849         signal_image_error ("invalid XPM data in file", name);
1850       }
1851     case XpmNoMemory:
1852       {
1853         signal_double_file_error ("Reading pixmap file",
1854                                   "out of memory", name);
1855       }
1856     case XpmOpenFailed:
1857       {
1858         /* should never happen? */
1859         signal_double_file_error ("Opening pixmap file",
1860                                   "no such file or directory", name);
1861       }
1862     default:
1863       {
1864         signal_double_file_error_2 ("Parsing pixmap file",
1865                                     "unknown error code",
1866                                     make_int (result), name);
1867         break;
1868       }
1869     }
1870
1871   return Qnil; /* not reached */
1872 }
1873
1874 static void
1875 check_valid_xpm_color_symbols (Lisp_Object data)
1876 {
1877   Lisp_Object rest;
1878
1879   for (rest = data; !NILP (rest); rest = XCDR (rest))
1880     {
1881       if (!CONSP (rest) ||
1882           !CONSP (XCAR (rest)) ||
1883           !STRINGP (XCAR (XCAR (rest))) ||
1884           (!STRINGP (XCDR (XCAR (rest))) &&
1885            !COLOR_SPECIFIERP (XCDR (XCAR (rest)))))
1886         signal_simple_error ("Invalid color symbol alist", data);
1887     }
1888 }
1889
1890 static void
1891 xpm_validate (Lisp_Object instantiator)
1892 {
1893   file_or_data_must_be_present (instantiator);
1894 }
1895
1896 Lisp_Object Vxpm_color_symbols;
1897
1898 Lisp_Object
1899 evaluate_xpm_color_symbols (void)
1900 {
1901   Lisp_Object rest, results = Qnil;
1902   struct gcpro gcpro1, gcpro2;
1903
1904   GCPRO2 (rest, results);
1905   for (rest = Vxpm_color_symbols; !NILP (rest); rest = XCDR (rest))
1906     {
1907       Lisp_Object name, value, cons;
1908
1909       CHECK_CONS (rest);
1910       cons = XCAR (rest);
1911       CHECK_CONS (cons);
1912       name = XCAR (cons);
1913       CHECK_STRING (name);
1914       value = XCDR (cons);
1915       CHECK_CONS (value);
1916       value = XCAR (value);
1917       value = Feval (value);
1918       if (NILP (value))
1919         continue;
1920       if (!STRINGP (value) && !COLOR_SPECIFIERP (value))
1921         signal_simple_error
1922           ("Result from xpm-color-symbols eval must be nil, string, or color",
1923            value);
1924       results = Fcons (Fcons (name, value), results);
1925     }
1926   UNGCPRO;                      /* no more evaluation */
1927   return results;
1928 }
1929
1930 static Lisp_Object
1931 xpm_normalize (Lisp_Object inst, Lisp_Object console_type)
1932 {
1933   Lisp_Object file = Qnil;
1934   Lisp_Object color_symbols;
1935   struct gcpro gcpro1, gcpro2;
1936   Lisp_Object alist = Qnil;
1937
1938   GCPRO2 (file, alist);
1939
1940   /* Now, convert any file data into inline data.  At the end of this,
1941      `data' will contain the inline data (if any) or Qnil, and
1942      `file' will contain the name this data was derived from (if
1943      known) or Qnil.
1944
1945      Note that if we cannot generate any regular inline data, we
1946      skip out. */
1947
1948   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data,
1949                                              console_type);
1950
1951   if (CONSP (file)) /* failure locating filename */
1952     signal_double_file_error ("Opening pixmap file",
1953                               "no such file or directory",
1954                               Fcar (file));
1955
1956   color_symbols = find_keyword_in_vector_or_given (inst, Q_color_symbols,
1957                                                    Qunbound);
1958
1959   if (NILP (file) && !UNBOUNDP (color_symbols))
1960     /* no conversion necessary */
1961     RETURN_UNGCPRO (inst);
1962
1963   alist = tagged_vector_to_alist (inst);
1964
1965   if (!NILP (file))
1966     {
1967       Lisp_Object data = pixmap_to_lisp_data (file, 0);
1968       alist = remassq_no_quit (Q_file, alist);
1969       /* there can't be a :data at this point. */
1970       alist = Fcons (Fcons (Q_file, file),
1971                      Fcons (Fcons (Q_data, data), alist));
1972     }
1973
1974   if (UNBOUNDP (color_symbols))
1975     {
1976       color_symbols = evaluate_xpm_color_symbols ();
1977       alist = Fcons (Fcons (Q_color_symbols, color_symbols),
1978                      alist);
1979     }
1980
1981   {
1982     Lisp_Object result = alist_to_tagged_vector (Qxpm, alist);
1983     free_alist (alist);
1984     RETURN_UNGCPRO (result);
1985   }
1986 }
1987
1988 static int
1989 xpm_possible_dest_types (void)
1990 {
1991   return
1992     IMAGE_MONO_PIXMAP_MASK  |
1993     IMAGE_COLOR_PIXMAP_MASK |
1994     IMAGE_POINTER_MASK;
1995 }
1996
1997 static void
1998 xpm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1999                  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2000                  int dest_mask, Lisp_Object domain)
2001 {
2002   Lisp_Object device= IMAGE_INSTANCE_DEVICE (XIMAGE_INSTANCE (image_instance));
2003
2004   MAYBE_DEVMETH (XDEVICE (device),
2005                  xpm_instantiate,
2006                  (image_instance, instantiator, pointer_fg,
2007                   pointer_bg, dest_mask, domain));
2008 }
2009
2010 #endif /* HAVE_XPM */
2011
2012 \f
2013 /****************************************************************************
2014  *                         Image Specifier Object                           *
2015  ****************************************************************************/
2016
2017 DEFINE_SPECIFIER_TYPE (image);
2018
2019 static void
2020 image_create (Lisp_Object obj)
2021 {
2022   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2023
2024   IMAGE_SPECIFIER_ALLOWED (image) = ~0; /* all are allowed */
2025   IMAGE_SPECIFIER_ATTACHEE (image) = Qnil;
2026   IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image) = Qnil;
2027 }
2028
2029 static void
2030 image_mark (Lisp_Object obj, void (*markobj) (Lisp_Object))
2031 {
2032   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2033
2034   markobj (IMAGE_SPECIFIER_ATTACHEE (image));
2035   markobj (IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image));
2036 }
2037
2038 static Lisp_Object
2039 image_instantiate_cache_result (Lisp_Object locative)
2040 {
2041   /* locative = (instance instantiator . subtable) */
2042   Fputhash (XCAR (XCDR (locative)), XCAR (locative), XCDR (XCDR (locative)));
2043   free_cons (XCONS (XCDR (locative)));
2044   free_cons (XCONS (locative));
2045   return Qnil;
2046 }
2047
2048 /* Given a specification for an image, return an instance of
2049    the image which matches the given instantiator and which can be
2050    displayed in the given domain. */
2051
2052 static Lisp_Object
2053 image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
2054                    Lisp_Object domain, Lisp_Object instantiator,
2055                    Lisp_Object depth)
2056 {
2057   Lisp_Object device = DFW_DEVICE (domain);
2058   struct device *d = XDEVICE (device);
2059   int dest_mask = XIMAGE_SPECIFIER_ALLOWED (specifier);
2060   int pointerp = dest_mask & image_instance_type_to_mask (IMAGE_POINTER);
2061
2062   if (IMAGE_INSTANCEP (instantiator))
2063     {
2064       /* make sure that the image instance's device and type are
2065          matching. */
2066
2067       if (EQ (device, XIMAGE_INSTANCE_DEVICE (instantiator)))
2068         {
2069           int mask =
2070             image_instance_type_to_mask (XIMAGE_INSTANCE_TYPE (instantiator));
2071           if (mask & dest_mask)
2072             return instantiator;
2073           else
2074             signal_simple_error ("Type of image instance not allowed here",
2075                                  instantiator);
2076         }
2077       else
2078         signal_simple_error_2 ("Wrong device for image instance",
2079                                instantiator, device);
2080     }
2081   else if (VECTORP (instantiator)
2082            && EQ (XVECTOR_DATA (instantiator)[0], Qinherit))
2083     {
2084       assert (XVECTOR_LENGTH (instantiator) == 3);
2085       return (FACE_PROPERTY_INSTANCE
2086               (Fget_face (XVECTOR_DATA (instantiator)[2]),
2087                Qbackground_pixmap, domain, 0, depth));
2088     }
2089   else
2090     {
2091       Lisp_Object instance;
2092       Lisp_Object subtable;
2093       Lisp_Object ls3 = Qnil;
2094       Lisp_Object pointer_fg = Qnil;
2095       Lisp_Object pointer_bg = Qnil;
2096
2097       if (pointerp)
2098         {
2099           pointer_fg = FACE_FOREGROUND (Vpointer_face, domain);
2100           pointer_bg = FACE_BACKGROUND (Vpointer_face, domain);
2101           ls3 = list3 (instantiator, pointer_fg, pointer_bg);
2102         }
2103
2104       /* First look in the hash table. */
2105       subtable = Fgethash (make_int (dest_mask), d->image_instance_cache,
2106                            Qunbound);
2107       if (UNBOUNDP (subtable))
2108         {
2109           /* For the image instance cache, we do comparisons with EQ rather
2110              than with EQUAL, as we do for color and font names.
2111              The reasons are:
2112
2113              1) pixmap data can be very long, and thus the hashing and
2114              comparing will take awhile.
2115              2) It's not so likely that we'll run into things that are EQUAL
2116              but not EQ (that can happen a lot with faces, because their
2117              specifiers are copied around); but pixmaps tend not to be
2118              in faces.
2119
2120              However, if the image-instance could be a pointer, we have to
2121              use EQUAL because we massaged the instantiator into a cons3
2122              also containing the foreground and background of the
2123              pointer face.
2124            */
2125
2126           subtable = make_lisp_hash_table (20,
2127                                            pointerp ? HASH_TABLE_KEY_CAR_WEAK
2128                                            : HASH_TABLE_KEY_WEAK,
2129                                            pointerp ? HASH_TABLE_EQUAL
2130                                            : HASH_TABLE_EQ);
2131           Fputhash (make_int (dest_mask), subtable,
2132                     d->image_instance_cache);
2133           instance = Qunbound;
2134         }
2135       else
2136         instance = Fgethash (pointerp ? ls3 : instantiator,
2137                              subtable, Qunbound);
2138
2139       if (UNBOUNDP (instance))
2140         {
2141           Lisp_Object locative =
2142             noseeum_cons (Qnil,
2143                           noseeum_cons (pointerp ? ls3 : instantiator,
2144                                         subtable));
2145           int speccount = specpdl_depth ();
2146
2147           /* make sure we cache the failures, too.
2148              Use an unwind-protect to catch such errors.
2149              If we fail, the unwind-protect records nil in
2150              the hash table.  If we succeed, we change the
2151              car of the locative to the resulting instance,
2152              which gets recorded instead. */
2153           record_unwind_protect (image_instantiate_cache_result,
2154                                  locative);
2155           instance = instantiate_image_instantiator (device,
2156                                                      domain,
2157                                                      instantiator,
2158                                                      pointer_fg, pointer_bg,
2159                                                      dest_mask);
2160           Fsetcar (locative, instance);
2161           unbind_to (speccount, Qnil);
2162         }
2163       else
2164         free_list (ls3);
2165
2166       if (NILP (instance))
2167         signal_simple_error ("Can't instantiate image (probably cached)",
2168                              instantiator);
2169       return instance;
2170     }
2171
2172   abort ();
2173   return Qnil; /* not reached */
2174 }
2175
2176 /* Validate an image instantiator. */
2177
2178 static void
2179 image_validate (Lisp_Object instantiator)
2180 {
2181   if (IMAGE_INSTANCEP (instantiator) || STRINGP (instantiator))
2182     return;
2183   else if (VECTORP (instantiator))
2184     {
2185       Lisp_Object *elt = XVECTOR_DATA (instantiator);
2186       int instantiator_len = XVECTOR_LENGTH (instantiator);
2187       struct image_instantiator_methods *meths;
2188       Lisp_Object already_seen = Qnil;
2189       struct gcpro gcpro1;
2190       int i;
2191
2192       if (instantiator_len < 1)
2193         signal_simple_error ("Vector length must be at least 1",
2194                              instantiator);
2195
2196       meths = decode_image_instantiator_format (elt[0], ERROR_ME);
2197       if (!(instantiator_len & 1))
2198         signal_simple_error
2199           ("Must have alternating keyword/value pairs", instantiator);
2200
2201       GCPRO1 (already_seen);
2202
2203       for (i = 1; i < instantiator_len; i += 2)
2204         {
2205           Lisp_Object keyword = elt[i];
2206           Lisp_Object value = elt[i+1];
2207           int j;
2208
2209           CHECK_SYMBOL (keyword);
2210           if (!SYMBOL_IS_KEYWORD (keyword))
2211             signal_simple_error ("Symbol must begin with a colon", keyword);
2212
2213           for (j = 0; j < Dynarr_length (meths->keywords); j++)
2214             if (EQ (keyword, Dynarr_at (meths->keywords, j).keyword))
2215               break;
2216
2217           if (j == Dynarr_length (meths->keywords))
2218             signal_simple_error ("Unrecognized keyword", keyword);
2219
2220           if (!Dynarr_at (meths->keywords, j).multiple_p)
2221             {
2222               if (!NILP (memq_no_quit (keyword, already_seen)))
2223                 signal_simple_error
2224                   ("Keyword may not appear more than once", keyword);
2225               already_seen = Fcons (keyword, already_seen);
2226             }
2227
2228           (Dynarr_at (meths->keywords, j).validate) (value);
2229         }
2230
2231       UNGCPRO;
2232
2233       MAYBE_IIFORMAT_METH (meths, validate, (instantiator));
2234     }
2235   else
2236     signal_simple_error ("Must be string or vector", instantiator);
2237 }
2238
2239 static void
2240 image_after_change (Lisp_Object specifier, Lisp_Object locale)
2241 {
2242   Lisp_Object attachee =
2243     IMAGE_SPECIFIER_ATTACHEE (XIMAGE_SPECIFIER (specifier));
2244   Lisp_Object property =
2245     IMAGE_SPECIFIER_ATTACHEE_PROPERTY (XIMAGE_SPECIFIER (specifier));
2246   if (FACEP (attachee))
2247     face_property_was_changed (attachee, property, locale);
2248   else if (GLYPHP (attachee))
2249     glyph_property_was_changed (attachee, property, locale);
2250 }
2251
2252 void
2253 set_image_attached_to (Lisp_Object obj, Lisp_Object face_or_glyph,
2254                        Lisp_Object property)
2255 {
2256   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2257
2258   IMAGE_SPECIFIER_ATTACHEE (image) = face_or_glyph;
2259   IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image) = property;
2260 }
2261
2262 static Lisp_Object
2263 image_going_to_add (Lisp_Object specifier, Lisp_Object locale,
2264                     Lisp_Object tag_set, Lisp_Object instantiator)
2265 {
2266   Lisp_Object possible_console_types = Qnil;
2267   Lisp_Object rest;
2268   Lisp_Object retlist = Qnil;
2269   struct gcpro gcpro1, gcpro2;
2270
2271   LIST_LOOP (rest, Vconsole_type_list)
2272     {
2273       Lisp_Object contype = XCAR (rest);
2274       if (!NILP (memq_no_quit (contype, tag_set)))
2275         possible_console_types = Fcons (contype, possible_console_types);
2276     }
2277
2278   if (XINT (Flength (possible_console_types)) > 1)
2279     /* two conflicting console types specified */
2280     return Qnil;
2281
2282   if (NILP (possible_console_types))
2283     possible_console_types = Vconsole_type_list;
2284
2285   GCPRO2 (retlist, possible_console_types);
2286
2287   LIST_LOOP (rest, possible_console_types)
2288     {
2289       Lisp_Object contype = XCAR (rest);
2290       Lisp_Object newinst = call_with_suspended_errors
2291         ((lisp_fn_t) normalize_image_instantiator,
2292          Qnil, Qimage, ERROR_ME_NOT, 3, instantiator, contype,
2293          make_int (XIMAGE_SPECIFIER_ALLOWED (specifier)));
2294
2295       if (!NILP (newinst))
2296         {
2297           Lisp_Object newtag;
2298           if (NILP (memq_no_quit (contype, tag_set)))
2299             newtag = Fcons (contype, tag_set);
2300           else
2301             newtag = tag_set;
2302           retlist = Fcons (Fcons (newtag, newinst), retlist);
2303         }
2304     }
2305
2306   UNGCPRO;
2307
2308   return retlist;
2309 }
2310
2311 DEFUN ("image-specifier-p", Fimage_specifier_p, 1, 1, 0, /*
2312 Return non-nil if OBJECT is an image specifier.
2313
2314 An image specifier is used for images (pixmaps and the like).  It is used
2315 to describe the actual image in a glyph.  It is instanced as an image-
2316 instance.
2317
2318 Image instantiators come in many formats: `xbm', `xpm', `gif', `jpeg',
2319 etc.  This describes the format of the data describing the image.  The
2320 resulting image instances also come in many types -- `mono-pixmap',
2321 `color-pixmap', `text', `pointer', etc.  This refers to the behavior of
2322 the image and the sorts of places it can appear. (For example, a
2323 color-pixmap image has fixed colors specified for it, while a
2324 mono-pixmap image comes in two unspecified shades "foreground" and
2325 "background" that are determined from the face of the glyph or
2326 surrounding text; a text image appears as a string of text and has an
2327 unspecified foreground, background, and font; a pointer image behaves
2328 like a mono-pixmap image but can only be used as a mouse pointer
2329 \[mono-pixmap images cannot be used as mouse pointers]; etc.) It is
2330 important to keep the distinction between image instantiator format and
2331 image instance type in mind.  Typically, a given image instantiator
2332 format can result in many different image instance types (for example,
2333 `xpm' can be instanced as `color-pixmap', `mono-pixmap', or `pointer';
2334 whereas `cursor-font' can be instanced only as `pointer'), and a
2335 particular image instance type can be generated by many different
2336 image instantiator formats (e.g.  `color-pixmap' can be generated by `xpm',
2337 `gif', `jpeg', etc.).
2338
2339 See `make-image-instance' for a more detailed discussion of image
2340 instance types.
2341
2342 An image instantiator should be a string or a vector of the form
2343
2344  [FORMAT :KEYWORD VALUE ...]
2345
2346 i.e. a format symbol followed by zero or more alternating keyword-value
2347 pairs.  FORMAT should be one of
2348
2349 'nothing
2350   (Don't display anything; no keywords are valid for this.
2351    Can only be instanced as `nothing'.)
2352 'string
2353   (Display this image as a text string.  Can only be instanced
2354    as `text', although support for instancing as `mono-pixmap'
2355    should be added.)
2356 'formatted-string
2357   (Display this image as a text string, with replaceable fields;
2358   not currently implemented.)
2359 'xbm
2360   (An X bitmap; only if X support was compiled into this XEmacs.
2361    Can be instanced as `mono-pixmap', `color-pixmap', or `pointer'.)
2362 'xpm
2363   (An XPM pixmap; only if XPM support was compiled into this XEmacs.
2364    Can be instanced as `color-pixmap', `mono-pixmap', or `pointer'.)
2365 'xface
2366   (An X-Face bitmap, used to encode people's faces in e-mail messages;
2367   only if X-Face support was compiled into this XEmacs.  Can be
2368   instanced as `mono-pixmap', `color-pixmap', or `pointer'.)
2369 'gif
2370   (A GIF87 or GIF89 image; only if GIF support was compiled into this
2371    XEmacs.  NOTE: only the first frame of animated gifs will be displayed.
2372    Can be instanced as `color-pixmap'.)
2373 'jpeg
2374   (A JPEG image; only if JPEG support was compiled into this XEmacs.
2375    Can be instanced as `color-pixmap'.)
2376 'png
2377   (A PNG image; only if PNG support was compiled into this XEmacs.
2378    Can be instanced as `color-pixmap'.)
2379 'tiff
2380   (A TIFF image; only if TIFF support was compiled into this XEmacs.
2381    Can be instanced as `color-pixmap'.)
2382 'cursor-font
2383   (One of the standard cursor-font names, such as "watch" or
2384    "right_ptr" under X.  Under X, this is, more specifically, any
2385    of the standard cursor names from appendix B of the Xlib manual
2386    [also known as the file <X11/cursorfont.h>] minus the XC_ prefix.
2387    On other window systems, the valid names will be specific to the
2388    type of window system.  Can only be instanced as `pointer'.)
2389 'font
2390   (A glyph from a font; i.e. the name of a font, and glyph index into it
2391    of the form "FONT fontname index [[mask-font] mask-index]".
2392    Currently can only be instanced as `pointer', although this should
2393    probably be fixed.)
2394 'subwindow
2395   (An embedded X window; not currently implemented.)
2396 'autodetect
2397   (XEmacs tries to guess what format the data is in.  If X support
2398   exists, the data string will be checked to see if it names a filename.
2399   If so, and this filename contains XBM or XPM data, the appropriate
2400   sort of pixmap or pointer will be created. [This includes picking up
2401   any specified hotspot or associated mask file.] Otherwise, if `pointer'
2402   is one of the allowable image-instance types and the string names a
2403   valid cursor-font name, the image will be created as a pointer.
2404   Otherwise, the image will be displayed as text.  If no X support
2405   exists, the image will always be displayed as text.)
2406 'inherit
2407   Inherit from the background-pixmap property of a face.
2408
2409 The valid keywords are:
2410
2411 :data
2412   (Inline data.  For most formats above, this should be a string.  For
2413   XBM images, this should be a list of three elements: width, height, and
2414   a string of bit data.  This keyword is not valid for instantiator
2415   formats `nothing' and `inherit'.)
2416 :file
2417   (Data is contained in a file.  The value is the name of this file.
2418   If both :data and :file are specified, the image is created from
2419   what is specified in :data and the string in :file becomes the
2420   value of the `image-instance-file-name' function when applied to
2421   the resulting image-instance.  This keyword is not valid for
2422   instantiator formats `nothing', `string', `formatted-string',
2423   `cursor-font', `font', `autodetect', and `inherit'.)
2424 :foreground
2425 :background
2426   (For `xbm', `xface', `cursor-font', and `font'.  These keywords
2427   allow you to explicitly specify foreground and background colors.
2428   The argument should be anything acceptable to `make-color-instance'.
2429   This will cause what would be a `mono-pixmap' to instead be colorized
2430   as a two-color color-pixmap, and specifies the foreground and/or
2431   background colors for a pointer instead of black and white.)
2432 :mask-data
2433   (For `xbm' and `xface'.  This specifies a mask to be used with the
2434   bitmap.  The format is a list of width, height, and bits, like for
2435   :data.)
2436 :mask-file
2437   (For `xbm' and `xface'.  This specifies a file containing the mask data.
2438   If neither a mask file nor inline mask data is given for an XBM image,
2439   and the XBM image comes from a file, XEmacs will look for a mask file
2440   with the same name as the image file but with "Mask" or "msk"
2441   appended.  For example, if you specify the XBM file "left_ptr"
2442   [usually located in "/usr/include/X11/bitmaps"], the associated
2443   mask file "left_ptrmsk" will automatically be picked up.)
2444 :hotspot-x
2445 :hotspot-y
2446   (For `xbm' and `xface'.  These keywords specify a hotspot if the image
2447   is instantiated as a `pointer'.  Note that if the XBM image file
2448   specifies a hotspot, it will automatically be picked up if no
2449   explicit hotspot is given.)
2450 :color-symbols
2451   (Only for `xpm'.  This specifies an alist that maps strings
2452   that specify symbolic color names to the actual color to be used
2453   for that symbolic color (in the form of a string or a color-specifier
2454   object).  If this is not specified, the contents of `xpm-color-symbols'
2455   are used to generate the alist.)
2456 :face
2457   (Only for `inherit'.  This specifies the face to inherit from.)
2458
2459 If instead of a vector, the instantiator is a string, it will be
2460 converted into a vector by looking it up according to the specs in the
2461 `console-type-image-conversion-list' (q.v.) for the console type of
2462 the domain (usually a window; sometimes a frame or device) over which
2463 the image is being instantiated.
2464
2465 If the instantiator specifies data from a file, the data will be read
2466 in at the time that the instantiator is added to the image (which may
2467 be well before when the image is actually displayed), and the
2468 instantiator will be converted into one of the inline-data forms, with
2469 the filename retained using a :file keyword.  This implies that the
2470 file must exist when the instantiator is added to the image, but does
2471 not need to exist at any other time (e.g. it may safely be a temporary
2472 file).
2473 */
2474        (object))
2475 {
2476   return IMAGE_SPECIFIERP (object) ? Qt : Qnil;
2477 }
2478
2479 \f
2480 /****************************************************************************
2481  *                             Glyph Object                                 *
2482  ****************************************************************************/
2483
2484 static Lisp_Object
2485 mark_glyph (Lisp_Object obj, void (*markobj) (Lisp_Object))
2486 {
2487   struct Lisp_Glyph *glyph = XGLYPH (obj);
2488
2489   markobj (glyph->image);
2490   markobj (glyph->contrib_p);
2491   markobj (glyph->baseline);
2492   markobj (glyph->face);
2493
2494   return glyph->plist;
2495 }
2496
2497 static void
2498 print_glyph (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
2499 {
2500   struct Lisp_Glyph *glyph = XGLYPH (obj);
2501   char buf[20];
2502
2503   if (print_readably)
2504     error ("printing unreadable object #<glyph 0x%x>", glyph->header.uid);
2505
2506   write_c_string ("#<glyph (", printcharfun);
2507   print_internal (Fglyph_type (obj), printcharfun, 0);
2508   write_c_string (") ", printcharfun);
2509   print_internal (glyph->image, printcharfun, 1);
2510   sprintf (buf, "0x%x>", glyph->header.uid);
2511   write_c_string (buf, printcharfun);
2512 }
2513
2514 /* Glyphs are equal if all of their display attributes are equal.  We
2515    don't compare names or doc-strings, because that would make equal
2516    be eq.
2517
2518    This isn't concerned with "unspecified" attributes, that's what
2519    #'glyph-differs-from-default-p is for. */
2520 static int
2521 glyph_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
2522 {
2523   struct Lisp_Glyph *g1 = XGLYPH (obj1);
2524   struct Lisp_Glyph *g2 = XGLYPH (obj2);
2525
2526   depth++;
2527
2528   return (internal_equal (g1->image,     g2->image,     depth) &&
2529           internal_equal (g1->contrib_p, g2->contrib_p, depth) &&
2530           internal_equal (g1->baseline,  g2->baseline,  depth) &&
2531           internal_equal (g1->face,      g2->face,      depth) &&
2532           !plists_differ (g1->plist,     g2->plist, 0, 0, depth + 1));
2533 }
2534
2535 static unsigned long
2536 glyph_hash (Lisp_Object obj, int depth)
2537 {
2538   depth++;
2539
2540   /* No need to hash all of the elements; that would take too long.
2541      Just hash the most common ones. */
2542   return HASH2 (internal_hash (XGLYPH (obj)->image, depth),
2543                 internal_hash (XGLYPH (obj)->face,  depth));
2544 }
2545
2546 static Lisp_Object
2547 glyph_getprop (Lisp_Object obj, Lisp_Object prop)
2548 {
2549   struct Lisp_Glyph *g = XGLYPH (obj);
2550
2551   if (EQ (prop, Qimage))     return g->image;
2552   if (EQ (prop, Qcontrib_p)) return g->contrib_p;
2553   if (EQ (prop, Qbaseline))  return g->baseline;
2554   if (EQ (prop, Qface))      return g->face;
2555
2556   return external_plist_get (&g->plist, prop, 0, ERROR_ME);
2557 }
2558
2559 static int
2560 glyph_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
2561 {
2562   if ((EQ (prop, Qimage))     ||
2563       (EQ (prop, Qcontrib_p)) ||
2564       (EQ (prop, Qbaseline)))
2565     return 0;
2566
2567   if (EQ (prop, Qface))
2568     {
2569       XGLYPH (obj)->face = Fget_face (value);
2570       return 1;
2571     }
2572
2573   external_plist_put (&XGLYPH (obj)->plist, prop, value, 0, ERROR_ME);
2574   return 1;
2575 }
2576
2577 static int
2578 glyph_remprop (Lisp_Object obj, Lisp_Object prop)
2579 {
2580   if ((EQ (prop, Qimage))     ||
2581       (EQ (prop, Qcontrib_p)) ||
2582       (EQ (prop, Qbaseline)))
2583     return -1;
2584
2585   if (EQ (prop, Qface))
2586     {
2587       XGLYPH (obj)->face = Qnil;
2588       return 1;
2589     }
2590
2591   return external_remprop (&XGLYPH (obj)->plist, prop, 0, ERROR_ME);
2592 }
2593
2594 static Lisp_Object
2595 glyph_plist (Lisp_Object obj)
2596 {
2597   struct Lisp_Glyph *glyph = XGLYPH (obj);
2598   Lisp_Object result = glyph->plist;
2599
2600   result = cons3 (Qface,      glyph->face,      result);
2601   result = cons3 (Qbaseline,  glyph->baseline,  result);
2602   result = cons3 (Qcontrib_p, glyph->contrib_p, result);
2603   result = cons3 (Qimage,     glyph->image,     result);
2604
2605   return result;
2606 }
2607
2608 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("glyph", glyph,
2609                                           mark_glyph, print_glyph, 0,
2610                                           glyph_equal, glyph_hash,
2611                                           glyph_getprop, glyph_putprop,
2612                                           glyph_remprop, glyph_plist,
2613                                           struct Lisp_Glyph);
2614 \f
2615 Lisp_Object
2616 allocate_glyph (enum glyph_type type,
2617                 void (*after_change) (Lisp_Object glyph, Lisp_Object property,
2618                                       Lisp_Object locale))
2619 {
2620   /* This function can GC */
2621   Lisp_Object obj = Qnil;
2622   struct Lisp_Glyph *g =
2623     alloc_lcrecord_type (struct Lisp_Glyph, lrecord_glyph);
2624
2625   g->type = type;
2626   g->image = Fmake_specifier (Qimage); /* This function can GC */
2627   switch (g->type)
2628     {
2629     case GLYPH_BUFFER:
2630       XIMAGE_SPECIFIER_ALLOWED (g->image) =
2631         IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK | IMAGE_MONO_PIXMAP_MASK |
2632           IMAGE_COLOR_PIXMAP_MASK | IMAGE_SUBWINDOW_MASK;
2633       break;
2634     case GLYPH_POINTER:
2635       XIMAGE_SPECIFIER_ALLOWED (g->image) =
2636         IMAGE_NOTHING_MASK | IMAGE_POINTER_MASK;
2637       break;
2638     case GLYPH_ICON:
2639       XIMAGE_SPECIFIER_ALLOWED (g->image) =
2640         IMAGE_NOTHING_MASK | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK;
2641       break;
2642     default:
2643       abort ();
2644     }
2645
2646   /* I think Fmake_specifier can GC.  I think set_specifier_fallback can GC. */
2647   /* We're getting enough reports of odd behavior in this area it seems */
2648   /* best to GCPRO everything. */
2649   {
2650     Lisp_Object tem1 = list1 (Fcons (Qnil, Vthe_nothing_vector));
2651     Lisp_Object tem2 = list1 (Fcons (Qnil, Qt));
2652     Lisp_Object tem3 = list1 (Fcons (Qnil, Qnil));
2653     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2654
2655     GCPRO4 (obj, tem1, tem2, tem3);
2656
2657     set_specifier_fallback (g->image, tem1);
2658     g->contrib_p = Fmake_specifier (Qboolean);
2659     set_specifier_fallback (g->contrib_p, tem2);
2660     /* #### should have a specifier for the following */
2661     g->baseline = Fmake_specifier (Qgeneric);
2662     set_specifier_fallback (g->baseline, tem3);
2663     g->face = Qnil;
2664     g->plist = Qnil;
2665     g->after_change = after_change;
2666     XSETGLYPH (obj, g);
2667
2668     set_image_attached_to (g->image, obj, Qimage);
2669     UNGCPRO;
2670   }
2671
2672   return obj;
2673 }
2674
2675 static enum glyph_type
2676 decode_glyph_type (Lisp_Object type, Error_behavior errb)
2677 {
2678   if (NILP (type))
2679     return GLYPH_BUFFER;
2680
2681   if (ERRB_EQ (errb, ERROR_ME))
2682     CHECK_SYMBOL (type);
2683
2684   if (EQ (type, Qbuffer))  return GLYPH_BUFFER;
2685   if (EQ (type, Qpointer)) return GLYPH_POINTER;
2686   if (EQ (type, Qicon))    return GLYPH_ICON;
2687
2688   maybe_signal_simple_error ("Invalid glyph type", type, Qimage, errb);
2689
2690   return GLYPH_UNKNOWN;
2691 }
2692
2693 static int
2694 valid_glyph_type_p (Lisp_Object type)
2695 {
2696   return !NILP (memq_no_quit (type, Vglyph_type_list));
2697 }
2698
2699 DEFUN ("valid-glyph-type-p", Fvalid_glyph_type_p, 1, 1, 0, /*
2700 Given a GLYPH-TYPE, return non-nil if it is valid.
2701 Valid types are `buffer', `pointer', and `icon'.
2702 */
2703        (glyph_type))
2704 {
2705   return valid_glyph_type_p (glyph_type) ? Qt : Qnil;
2706 }
2707
2708 DEFUN ("glyph-type-list", Fglyph_type_list, 0, 0, 0, /*
2709 Return a list of valid glyph types.
2710 */
2711        ())
2712 {
2713   return Fcopy_sequence (Vglyph_type_list);
2714 }
2715
2716 DEFUN ("make-glyph-internal", Fmake_glyph_internal, 0, 1, 0, /*
2717 Create and return a new uninitialized glyph or type TYPE.
2718
2719 TYPE specifies the type of the glyph; this should be one of `buffer',
2720 `pointer', or `icon', and defaults to `buffer'.  The type of the glyph
2721 specifies in which contexts the glyph can be used, and controls the
2722 allowable image types into which the glyph's image can be
2723 instantiated.
2724
2725 `buffer' glyphs can be used as the begin-glyph or end-glyph of an
2726 extent, in the modeline, and in the toolbar.  Their image can be
2727 instantiated as `nothing', `mono-pixmap', `color-pixmap', `text',
2728 and `subwindow'.
2729
2730 `pointer' glyphs can be used to specify the mouse pointer.  Their
2731 image can be instantiated as `pointer'.
2732
2733 `icon' glyphs can be used to specify the icon used when a frame is
2734 iconified.  Their image can be instantiated as `mono-pixmap' and
2735 `color-pixmap'.
2736 */
2737        (type))
2738 {
2739   enum glyph_type typeval = decode_glyph_type (type, ERROR_ME);
2740   return allocate_glyph (typeval, 0);
2741 }
2742
2743 DEFUN ("glyphp", Fglyphp, 1, 1, 0, /*
2744 Return non-nil if OBJECT is a glyph.
2745
2746 A glyph is an object used for pixmaps and the like.  It is used
2747 in begin-glyphs and end-glyphs attached to extents, in marginal and textual
2748 annotations, in overlay arrows (overlay-arrow-* variables), in toolbar
2749 buttons, and the like.  Its image is described using an image specifier --
2750 see `image-specifier-p'.
2751 */
2752        (object))
2753 {
2754   return GLYPHP (object) ? Qt : Qnil;
2755 }
2756
2757 DEFUN ("glyph-type", Fglyph_type, 1, 1, 0, /*
2758 Return the type of the given glyph.
2759 The return value will be one of 'buffer, 'pointer, or 'icon.
2760 */
2761        (glyph))
2762 {
2763   CHECK_GLYPH (glyph);
2764   switch (XGLYPH_TYPE (glyph))
2765     {
2766     default: abort ();
2767     case GLYPH_BUFFER:  return Qbuffer;
2768     case GLYPH_POINTER: return Qpointer;
2769     case GLYPH_ICON:    return Qicon;
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 }