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