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