XEmacs 21.2.20 "Yoko".
[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   new = allocate_image_instance (device);
1613   copy_lcrecord (XIMAGE_INSTANCE (new), XIMAGE_INSTANCE (image_instance));
1614   /* note that if this method returns non-zero, this method MUST
1615      copy any window-system resources, so that when one image instance is
1616      freed, the other one is not hosed. */
1617   if (!DEVMETH (XDEVICE (device), colorize_image_instance, (new, foreground,
1618                                                             background)))
1619     return image_instance;
1620   return new;
1621 }
1622
1623 \f
1624 /************************************************************************/
1625 /*                              error helpers                           */
1626 /************************************************************************/
1627 DOESNT_RETURN
1628 signal_image_error (CONST char *reason, Lisp_Object frob)
1629 {
1630   signal_error (Qimage_conversion_error,
1631                 list2 (build_translated_string (reason), frob));
1632 }
1633
1634 DOESNT_RETURN
1635 signal_image_error_2 (CONST char *reason, Lisp_Object frob0, Lisp_Object frob1)
1636 {
1637   signal_error (Qimage_conversion_error,
1638                 list3 (build_translated_string (reason), frob0, frob1));
1639 }
1640
1641 /****************************************************************************
1642  *                                  nothing                                 *
1643  ****************************************************************************/
1644
1645 static int
1646 nothing_possible_dest_types (void)
1647 {
1648   return IMAGE_NOTHING_MASK;
1649 }
1650
1651 static void
1652 nothing_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1653                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1654                      int dest_mask, Lisp_Object domain)
1655 {
1656   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1657
1658   if (dest_mask & IMAGE_NOTHING_MASK)
1659     IMAGE_INSTANCE_TYPE (ii) = IMAGE_NOTHING;
1660   else
1661     incompatible_image_types (instantiator, dest_mask, IMAGE_NOTHING_MASK);
1662 }
1663
1664 \f
1665 /****************************************************************************
1666  *                                  inherit                                 *
1667  ****************************************************************************/
1668
1669 static void
1670 inherit_validate (Lisp_Object instantiator)
1671 {
1672   face_must_be_present (instantiator);
1673 }
1674
1675 static Lisp_Object
1676 inherit_normalize (Lisp_Object inst, Lisp_Object console_type)
1677 {
1678   Lisp_Object face;
1679
1680   assert (XVECTOR_LENGTH (inst) == 3);
1681   face = XVECTOR_DATA (inst)[2];
1682   if (!FACEP (face))
1683     inst = vector3 (Qinherit, Q_face, Fget_face (face));
1684   return inst;
1685 }
1686
1687 static int
1688 inherit_possible_dest_types (void)
1689 {
1690   return IMAGE_MONO_PIXMAP_MASK;
1691 }
1692
1693 static void
1694 inherit_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1695                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1696                      int dest_mask, Lisp_Object domain)
1697 {
1698   /* handled specially in image_instantiate */
1699   abort ();
1700 }
1701
1702 \f
1703 /****************************************************************************
1704  *                                  string                                  *
1705  ****************************************************************************/
1706
1707 static void
1708 string_validate (Lisp_Object instantiator)
1709 {
1710   data_must_be_present (instantiator);
1711 }
1712
1713 static int
1714 string_possible_dest_types (void)
1715 {
1716   return IMAGE_TEXT_MASK;
1717 }
1718
1719 /* called from autodetect_instantiate() */
1720 void
1721 string_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1722                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1723                     int dest_mask, Lisp_Object domain)
1724 {
1725   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1726   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1727
1728   assert (!NILP (data));
1729   if (dest_mask & IMAGE_TEXT_MASK)
1730     {
1731       IMAGE_INSTANCE_TYPE (ii) = IMAGE_TEXT;
1732       IMAGE_INSTANCE_TEXT_STRING (ii) = data;
1733     }
1734   else
1735     incompatible_image_types (instantiator, dest_mask, IMAGE_TEXT_MASK);
1736 }
1737
1738 /* set the properties of a string */
1739 static Lisp_Object
1740 text_set_property (Lisp_Object image_instance, Lisp_Object prop,
1741                    Lisp_Object val)
1742 {
1743   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1744
1745   if (EQ (prop, Q_data))
1746     {
1747       CHECK_STRING (val);
1748       IMAGE_INSTANCE_TEXT_STRING (ii) = val;
1749
1750       return Qt;
1751     }
1752   return Qunbound;
1753 }
1754
1755 \f
1756 /****************************************************************************
1757  *                             formatted-string                             *
1758  ****************************************************************************/
1759
1760 static void
1761 formatted_string_validate (Lisp_Object instantiator)
1762 {
1763   data_must_be_present (instantiator);
1764 }
1765
1766 static int
1767 formatted_string_possible_dest_types (void)
1768 {
1769   return IMAGE_TEXT_MASK;
1770 }
1771
1772 static void
1773 formatted_string_instantiate (Lisp_Object image_instance,
1774                               Lisp_Object instantiator,
1775                               Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1776                               int dest_mask, Lisp_Object domain)
1777 {
1778   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1779   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1780
1781   assert (!NILP (data));
1782   /* #### implement this */
1783   warn_when_safe (Qunimplemented, Qnotice,
1784                   "`formatted-string' not yet implemented; assuming `string'");
1785   if (dest_mask & IMAGE_TEXT_MASK)
1786     {
1787       IMAGE_INSTANCE_TYPE (ii) = IMAGE_TEXT;
1788       IMAGE_INSTANCE_TEXT_STRING (ii) = data;
1789     }
1790   else
1791     incompatible_image_types (instantiator, dest_mask, IMAGE_TEXT_MASK);
1792 }
1793
1794 \f
1795 /************************************************************************/
1796 /*                        pixmap file functions                         */
1797 /************************************************************************/
1798
1799 /* If INSTANTIATOR refers to inline data, return Qnil.
1800    If INSTANTIATOR refers to data in a file, return the full filename
1801    if it exists; otherwise, return a cons of (filename).
1802
1803    FILE_KEYWORD and DATA_KEYWORD are symbols specifying the
1804    keywords used to look up the file and inline data,
1805    respectively, in the instantiator.  Normally these would
1806    be Q_file and Q_data, but might be different for mask data. */
1807
1808 Lisp_Object
1809 potential_pixmap_file_instantiator (Lisp_Object instantiator,
1810                                     Lisp_Object file_keyword,
1811                                     Lisp_Object data_keyword,
1812                                     Lisp_Object console_type)
1813 {
1814   Lisp_Object file;
1815   Lisp_Object data;
1816
1817   assert (VECTORP (instantiator));
1818
1819   data = find_keyword_in_vector (instantiator, data_keyword);
1820   file = find_keyword_in_vector (instantiator, file_keyword);
1821
1822   if (!NILP (file) && NILP (data))
1823     {
1824       Lisp_Object retval = MAYBE_LISP_CONTYPE_METH
1825         (decode_console_type(console_type, ERROR_ME),
1826          locate_pixmap_file, (file));
1827
1828       if (!NILP (retval))
1829         return retval;
1830       else
1831         return Fcons (file, Qnil); /* should have been file */
1832     }
1833
1834   return Qnil;
1835 }
1836
1837 Lisp_Object
1838 simple_image_type_normalize (Lisp_Object inst, Lisp_Object console_type,
1839                              Lisp_Object image_type_tag)
1840 {
1841   /* This function can call lisp */
1842   Lisp_Object file = Qnil;
1843   struct gcpro gcpro1, gcpro2;
1844   Lisp_Object alist = Qnil;
1845
1846   GCPRO2 (file, alist);
1847
1848   /* Now, convert any file data into inline data.  At the end of this,
1849      `data' will contain the inline data (if any) or Qnil, and `file'
1850      will contain the name this data was derived from (if known) or
1851      Qnil.
1852
1853      Note that if we cannot generate any regular inline data, we
1854      skip out. */
1855
1856   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data,
1857                                              console_type);
1858
1859   if (CONSP (file)) /* failure locating filename */
1860     signal_double_file_error ("Opening pixmap file",
1861                               "no such file or directory",
1862                               Fcar (file));
1863
1864   if (NILP (file)) /* no conversion necessary */
1865     RETURN_UNGCPRO (inst);
1866
1867   alist = tagged_vector_to_alist (inst);
1868
1869   {
1870     Lisp_Object data = make_string_from_file (file);
1871     alist = remassq_no_quit (Q_file, alist);
1872     /* there can't be a :data at this point. */
1873     alist = Fcons (Fcons (Q_file, file),
1874                    Fcons (Fcons (Q_data, data), alist));
1875   }
1876
1877   {
1878     Lisp_Object result = alist_to_tagged_vector (image_type_tag, alist);
1879     free_alist (alist);
1880     RETURN_UNGCPRO (result);
1881   }
1882 }
1883
1884 \f
1885 #ifdef HAVE_WINDOW_SYSTEM
1886 /**********************************************************************
1887  *                             XBM                                    *
1888  **********************************************************************/
1889
1890 /* Check if DATA represents a valid inline XBM spec (i.e. a list
1891    of (width height bits), with checking done on the dimensions).
1892    If not, signal an error. */
1893
1894 static void
1895 check_valid_xbm_inline (Lisp_Object data)
1896 {
1897   Lisp_Object width, height, bits;
1898
1899   if (!CONSP (data) ||
1900       !CONSP (XCDR (data)) ||
1901       !CONSP (XCDR (XCDR (data))) ||
1902       !NILP (XCDR (XCDR (XCDR (data)))))
1903     signal_simple_error ("Must be list of 3 elements", data);
1904
1905   width  = XCAR (data);
1906   height = XCAR (XCDR (data));
1907   bits   = XCAR (XCDR (XCDR (data)));
1908
1909   CHECK_STRING (bits);
1910
1911   if (!NATNUMP (width))
1912     signal_simple_error ("Width must be a natural number", width);
1913
1914   if (!NATNUMP (height))
1915     signal_simple_error ("Height must be a natural number", height);
1916
1917   if (((XINT (width) * XINT (height)) / 8) > XSTRING_CHAR_LENGTH (bits))
1918     signal_simple_error ("data is too short for width and height",
1919                          vector3 (width, height, bits));
1920 }
1921
1922 /* Validate method for XBM's. */
1923
1924 static void
1925 xbm_validate (Lisp_Object instantiator)
1926 {
1927   file_or_data_must_be_present (instantiator);
1928 }
1929
1930 /* Given a filename that is supposed to contain XBM data, return
1931    the inline representation of it as (width height bits).  Return
1932    the hotspot through XHOT and YHOT, if those pointers are not 0.
1933    If there is no hotspot, XHOT and YHOT will contain -1.
1934
1935    If the function fails:
1936
1937    -- if OK_IF_DATA_INVALID is set and the data was invalid,
1938       return Qt.
1939    -- maybe return an error, or return Qnil.
1940  */
1941
1942 #ifdef HAVE_X_WINDOWS
1943 #include <X11/Xlib.h>
1944 #else
1945 #define XFree(data) free(data)
1946 #endif
1947
1948 Lisp_Object
1949 bitmap_to_lisp_data (Lisp_Object name, int *xhot, int *yhot,
1950                      int ok_if_data_invalid)
1951 {
1952   unsigned int w, h;
1953   Extbyte *data;
1954   int result;
1955   CONST char *filename_ext;
1956
1957   GET_C_STRING_FILENAME_DATA_ALLOCA (name, filename_ext);
1958   result = read_bitmap_data_from_file (filename_ext, &w, &h,
1959                                        &data, xhot, yhot);
1960
1961   if (result == BitmapSuccess)
1962     {
1963       Lisp_Object retval;
1964       int len = (w + 7) / 8 * h;
1965
1966       retval = list3 (make_int (w), make_int (h),
1967                       make_ext_string (data, len, FORMAT_BINARY));
1968       XFree ((char *) data);
1969       return retval;
1970     }
1971
1972   switch (result)
1973     {
1974     case BitmapOpenFailed:
1975       {
1976         /* should never happen */
1977         signal_double_file_error ("Opening bitmap file",
1978                                   "no such file or directory",
1979                                   name);
1980       }
1981     case BitmapFileInvalid:
1982       {
1983         if (ok_if_data_invalid)
1984           return Qt;
1985         signal_double_file_error ("Reading bitmap file",
1986                                   "invalid data in file",
1987                                   name);
1988       }
1989     case BitmapNoMemory:
1990       {
1991         signal_double_file_error ("Reading bitmap file",
1992                                   "out of memory",
1993                                   name);
1994       }
1995     default:
1996       {
1997         signal_double_file_error_2 ("Reading bitmap file",
1998                                     "unknown error code",
1999                                     make_int (result), name);
2000       }
2001     }
2002
2003   return Qnil; /* not reached */
2004 }
2005
2006 Lisp_Object
2007 xbm_mask_file_munging (Lisp_Object alist, Lisp_Object file,
2008                        Lisp_Object mask_file, Lisp_Object console_type)
2009 {
2010   /* This is unclean but it's fairly standard -- a number of the
2011      bitmaps in /usr/include/X11/bitmaps use it -- so we support
2012      it. */
2013   if (NILP (mask_file)
2014       /* don't override explicitly specified mask data. */
2015       && NILP (assq_no_quit (Q_mask_data, alist))
2016       && !NILP (file))
2017     {
2018       mask_file = MAYBE_LISP_CONTYPE_METH
2019         (decode_console_type(console_type, ERROR_ME),
2020          locate_pixmap_file, (concat2 (file, build_string ("Mask"))));
2021       if (NILP (mask_file))
2022         mask_file = MAYBE_LISP_CONTYPE_METH
2023           (decode_console_type(console_type, ERROR_ME),
2024            locate_pixmap_file, (concat2 (file, build_string ("msk"))));
2025     }
2026
2027   if (!NILP (mask_file))
2028     {
2029       Lisp_Object mask_data =
2030         bitmap_to_lisp_data (mask_file, 0, 0, 0);
2031       alist = remassq_no_quit (Q_mask_file, alist);
2032       /* there can't be a :mask-data at this point. */
2033       alist = Fcons (Fcons (Q_mask_file, mask_file),
2034                      Fcons (Fcons (Q_mask_data, mask_data), alist));
2035     }
2036
2037   return alist;
2038 }
2039
2040 /* Normalize method for XBM's. */
2041
2042 static Lisp_Object
2043 xbm_normalize (Lisp_Object inst, Lisp_Object console_type)
2044 {
2045   Lisp_Object file = Qnil, mask_file = Qnil;
2046   struct gcpro gcpro1, gcpro2, gcpro3;
2047   Lisp_Object alist = Qnil;
2048
2049   GCPRO3 (file, mask_file, alist);
2050
2051   /* Now, convert any file data into inline data for both the regular
2052      data and the mask data.  At the end of this, `data' will contain
2053      the inline data (if any) or Qnil, and `file' will contain
2054      the name this data was derived from (if known) or Qnil.
2055      Likewise for `mask_file' and `mask_data'.
2056
2057      Note that if we cannot generate any regular inline data, we
2058      skip out. */
2059
2060   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data,
2061                                              console_type);
2062   mask_file = potential_pixmap_file_instantiator (inst, Q_mask_file,
2063                                                   Q_mask_data, console_type);
2064
2065   if (CONSP (file)) /* failure locating filename */
2066     signal_double_file_error ("Opening bitmap file",
2067                               "no such file or directory",
2068                               Fcar (file));
2069
2070   if (NILP (file) && NILP (mask_file)) /* no conversion necessary */
2071     RETURN_UNGCPRO (inst);
2072
2073   alist = tagged_vector_to_alist (inst);
2074
2075   if (!NILP (file))
2076     {
2077       int xhot, yhot;
2078       Lisp_Object data = bitmap_to_lisp_data (file, &xhot, &yhot, 0);
2079       alist = remassq_no_quit (Q_file, alist);
2080       /* there can't be a :data at this point. */
2081       alist = Fcons (Fcons (Q_file, file),
2082                      Fcons (Fcons (Q_data, data), alist));
2083
2084       if (xhot != -1 && NILP (assq_no_quit (Q_hotspot_x, alist)))
2085         alist = Fcons (Fcons (Q_hotspot_x, make_int (xhot)),
2086                        alist);
2087       if (yhot != -1 && NILP (assq_no_quit (Q_hotspot_y, alist)))
2088         alist = Fcons (Fcons (Q_hotspot_y, make_int (yhot)),
2089                        alist);
2090     }
2091
2092   alist = xbm_mask_file_munging (alist, file, mask_file, console_type);
2093
2094   {
2095     Lisp_Object result = alist_to_tagged_vector (Qxbm, alist);
2096     free_alist (alist);
2097     RETURN_UNGCPRO (result);
2098   }
2099 }
2100
2101 \f
2102 static int
2103 xbm_possible_dest_types (void)
2104 {
2105   return
2106     IMAGE_MONO_PIXMAP_MASK  |
2107     IMAGE_COLOR_PIXMAP_MASK |
2108     IMAGE_POINTER_MASK;
2109 }
2110
2111 #endif
2112
2113 \f
2114 #ifdef HAVE_XFACE
2115 /**********************************************************************
2116  *                             X-Face                                 *
2117  **********************************************************************/
2118
2119 static void
2120 xface_validate (Lisp_Object instantiator)
2121 {
2122   file_or_data_must_be_present (instantiator);
2123 }
2124
2125 static Lisp_Object
2126 xface_normalize (Lisp_Object inst, Lisp_Object console_type)
2127 {
2128   /* This function can call lisp */
2129   Lisp_Object file = Qnil, mask_file = Qnil;
2130   struct gcpro gcpro1, gcpro2, gcpro3;
2131   Lisp_Object alist = Qnil;
2132
2133   GCPRO3 (file, mask_file, alist);
2134
2135   /* Now, convert any file data into inline data for both the regular
2136      data and the mask data.  At the end of this, `data' will contain
2137      the inline data (if any) or Qnil, and `file' will contain
2138      the name this data was derived from (if known) or Qnil.
2139      Likewise for `mask_file' and `mask_data'.
2140
2141      Note that if we cannot generate any regular inline data, we
2142      skip out. */
2143
2144   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data,
2145                                              console_type);
2146   mask_file = potential_pixmap_file_instantiator (inst, Q_mask_file,
2147                                                   Q_mask_data, console_type);
2148
2149   if (CONSP (file)) /* failure locating filename */
2150     signal_double_file_error ("Opening bitmap file",
2151                               "no such file or directory",
2152                               Fcar (file));
2153
2154   if (NILP (file) && NILP (mask_file)) /* no conversion necessary */
2155     RETURN_UNGCPRO (inst);
2156
2157   alist = tagged_vector_to_alist (inst);
2158
2159   {
2160     Lisp_Object data = make_string_from_file (file);
2161     alist = remassq_no_quit (Q_file, alist);
2162     /* there can't be a :data at this point. */
2163     alist = Fcons (Fcons (Q_file, file),
2164                    Fcons (Fcons (Q_data, data), alist));
2165   }
2166
2167   alist = xbm_mask_file_munging (alist, file, mask_file, console_type);
2168
2169   {
2170     Lisp_Object result = alist_to_tagged_vector (Qxface, alist);
2171     free_alist (alist);
2172     RETURN_UNGCPRO (result);
2173   }
2174 }
2175
2176 static int
2177 xface_possible_dest_types (void)
2178 {
2179   return
2180     IMAGE_MONO_PIXMAP_MASK  |
2181     IMAGE_COLOR_PIXMAP_MASK |
2182     IMAGE_POINTER_MASK;
2183 }
2184
2185 #endif /* HAVE_XFACE */
2186
2187 \f
2188 #ifdef HAVE_XPM
2189
2190 /**********************************************************************
2191  *                             XPM                                    *
2192  **********************************************************************/
2193
2194 Lisp_Object
2195 pixmap_to_lisp_data (Lisp_Object name, int ok_if_data_invalid)
2196 {
2197   char **data;
2198   int result;
2199   char *fname = 0;
2200   
2201   GET_C_STRING_FILENAME_DATA_ALLOCA (name, fname);
2202   result = XpmReadFileToData (fname, &data);
2203
2204   if (result == XpmSuccess)
2205     {
2206       Lisp_Object retval = Qnil;
2207       struct buffer *old_buffer = current_buffer;
2208       Lisp_Object temp_buffer =
2209         Fget_buffer_create (build_string (" *pixmap conversion*"));
2210       int elt;
2211       int height, width, ncolors;
2212       struct gcpro gcpro1, gcpro2, gcpro3;
2213       int speccount = specpdl_depth ();
2214
2215       GCPRO3 (name, retval, temp_buffer);
2216
2217       specbind (Qinhibit_quit, Qt);
2218       set_buffer_internal (XBUFFER (temp_buffer));
2219       Ferase_buffer (Qnil);
2220
2221       buffer_insert_c_string (current_buffer, "/* XPM */\r");
2222       buffer_insert_c_string (current_buffer, "static char *pixmap[] = {\r");
2223
2224       sscanf (data[0], "%d %d %d", &height, &width, &ncolors);
2225       for (elt = 0; elt <= width + ncolors; elt++)
2226         {
2227           buffer_insert_c_string (current_buffer, "\"");
2228           buffer_insert_c_string (current_buffer, data[elt]);
2229
2230           if (elt < width + ncolors)
2231             buffer_insert_c_string (current_buffer, "\",\r");
2232           else
2233             buffer_insert_c_string (current_buffer, "\"};\r");
2234         }
2235
2236       retval = Fbuffer_substring (Qnil, Qnil, Qnil);
2237       XpmFree (data);
2238
2239       set_buffer_internal (old_buffer);
2240       unbind_to (speccount, Qnil);
2241
2242       RETURN_UNGCPRO (retval);
2243     }
2244
2245   switch (result)
2246     {
2247     case XpmFileInvalid:
2248       {
2249         if (ok_if_data_invalid)
2250           return Qt;
2251         signal_image_error ("invalid XPM data in file", name);
2252       }
2253     case XpmNoMemory:
2254       {
2255         signal_double_file_error ("Reading pixmap file",
2256                                   "out of memory", name);
2257       }
2258     case XpmOpenFailed:
2259       {
2260         /* should never happen? */
2261         signal_double_file_error ("Opening pixmap file",
2262                                   "no such file or directory", name);
2263       }
2264     default:
2265       {
2266         signal_double_file_error_2 ("Parsing pixmap file",
2267                                     "unknown error code",
2268                                     make_int (result), name);
2269         break;
2270       }
2271     }
2272
2273   return Qnil; /* not reached */
2274 }
2275
2276 static void
2277 check_valid_xpm_color_symbols (Lisp_Object data)
2278 {
2279   Lisp_Object rest;
2280
2281   for (rest = data; !NILP (rest); rest = XCDR (rest))
2282     {
2283       if (!CONSP (rest) ||
2284           !CONSP (XCAR (rest)) ||
2285           !STRINGP (XCAR (XCAR (rest))) ||
2286           (!STRINGP (XCDR (XCAR (rest))) &&
2287            !COLOR_SPECIFIERP (XCDR (XCAR (rest)))))
2288         signal_simple_error ("Invalid color symbol alist", data);
2289     }
2290 }
2291
2292 static void
2293 xpm_validate (Lisp_Object instantiator)
2294 {
2295   file_or_data_must_be_present (instantiator);
2296 }
2297
2298 Lisp_Object Vxpm_color_symbols;
2299
2300 Lisp_Object
2301 evaluate_xpm_color_symbols (void)
2302 {
2303   Lisp_Object rest, results = Qnil;
2304   struct gcpro gcpro1, gcpro2;
2305
2306   GCPRO2 (rest, results);
2307   for (rest = Vxpm_color_symbols; !NILP (rest); rest = XCDR (rest))
2308     {
2309       Lisp_Object name, value, cons;
2310
2311       CHECK_CONS (rest);
2312       cons = XCAR (rest);
2313       CHECK_CONS (cons);
2314       name = XCAR (cons);
2315       CHECK_STRING (name);
2316       value = XCDR (cons);
2317       CHECK_CONS (value);
2318       value = XCAR (value);
2319       value = Feval (value);
2320       if (NILP (value))
2321         continue;
2322       if (!STRINGP (value) && !COLOR_SPECIFIERP (value))
2323         signal_simple_error
2324           ("Result from xpm-color-symbols eval must be nil, string, or color",
2325            value);
2326       results = Fcons (Fcons (name, value), results);
2327     }
2328   UNGCPRO;                      /* no more evaluation */
2329   return results;
2330 }
2331
2332 static Lisp_Object
2333 xpm_normalize (Lisp_Object inst, Lisp_Object console_type)
2334 {
2335   Lisp_Object file = Qnil;
2336   Lisp_Object color_symbols;
2337   struct gcpro gcpro1, gcpro2;
2338   Lisp_Object alist = Qnil;
2339
2340   GCPRO2 (file, alist);
2341
2342   /* Now, convert any file data into inline data.  At the end of this,
2343      `data' will contain the inline data (if any) or Qnil, and
2344      `file' will contain the name this data was derived from (if
2345      known) or Qnil.
2346
2347      Note that if we cannot generate any regular inline data, we
2348      skip out. */
2349
2350   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data,
2351                                              console_type);
2352
2353   if (CONSP (file)) /* failure locating filename */
2354     signal_double_file_error ("Opening pixmap file",
2355                               "no such file or directory",
2356                               Fcar (file));
2357
2358   color_symbols = find_keyword_in_vector_or_given (inst, Q_color_symbols,
2359                                                    Qunbound);
2360
2361   if (NILP (file) && !UNBOUNDP (color_symbols))
2362     /* no conversion necessary */
2363     RETURN_UNGCPRO (inst);
2364
2365   alist = tagged_vector_to_alist (inst);
2366
2367   if (!NILP (file))
2368     {
2369       Lisp_Object data = pixmap_to_lisp_data (file, 0);
2370       alist = remassq_no_quit (Q_file, alist);
2371       /* there can't be a :data at this point. */
2372       alist = Fcons (Fcons (Q_file, file),
2373                      Fcons (Fcons (Q_data, data), alist));
2374     }
2375
2376   if (UNBOUNDP (color_symbols))
2377     {
2378       color_symbols = evaluate_xpm_color_symbols ();
2379       alist = Fcons (Fcons (Q_color_symbols, color_symbols),
2380                      alist);
2381     }
2382
2383   {
2384     Lisp_Object result = alist_to_tagged_vector (Qxpm, alist);
2385     free_alist (alist);
2386     RETURN_UNGCPRO (result);
2387   }
2388 }
2389
2390 static int
2391 xpm_possible_dest_types (void)
2392 {
2393   return
2394     IMAGE_MONO_PIXMAP_MASK  |
2395     IMAGE_COLOR_PIXMAP_MASK |
2396     IMAGE_POINTER_MASK;
2397 }
2398
2399 #endif /* HAVE_XPM */
2400
2401 \f
2402 /****************************************************************************
2403  *                         Image Specifier Object                           *
2404  ****************************************************************************/
2405
2406 DEFINE_SPECIFIER_TYPE (image);
2407
2408 static void
2409 image_create (Lisp_Object obj)
2410 {
2411   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2412
2413   IMAGE_SPECIFIER_ALLOWED (image) = ~0; /* all are allowed */
2414   IMAGE_SPECIFIER_ATTACHEE (image) = Qnil;
2415   IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image) = Qnil;
2416 }
2417
2418 static void
2419 image_mark (Lisp_Object obj)
2420 {
2421   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2422
2423   mark_object (IMAGE_SPECIFIER_ATTACHEE (image));
2424   mark_object (IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image));
2425 }
2426
2427 static Lisp_Object
2428 image_instantiate_cache_result (Lisp_Object locative)
2429 {
2430   /* locative = (instance instantiator . subtable) */
2431   Fputhash (XCAR (XCDR (locative)), XCAR (locative), XCDR (XCDR (locative)));
2432   free_cons (XCONS (XCDR (locative)));
2433   free_cons (XCONS (locative));
2434   return Qnil;
2435 }
2436
2437 /* Given a specification for an image, return an instance of
2438    the image which matches the given instantiator and which can be
2439    displayed in the given domain. */
2440
2441 static Lisp_Object
2442 image_instantiate (Lisp_Object specifier, Lisp_Object matchspec,
2443                    Lisp_Object domain, Lisp_Object instantiator,
2444                    Lisp_Object depth)
2445 {
2446   Lisp_Object device = DFW_DEVICE (domain);
2447   struct device *d = XDEVICE (device);
2448   int dest_mask = XIMAGE_SPECIFIER_ALLOWED (specifier);
2449   int pointerp = dest_mask & image_instance_type_to_mask (IMAGE_POINTER);
2450
2451   if (IMAGE_INSTANCEP (instantiator))
2452     {
2453       /* make sure that the image instance's device and type are
2454          matching. */
2455
2456       if (EQ (device, XIMAGE_INSTANCE_DEVICE (instantiator)))
2457         {
2458           int mask =
2459             image_instance_type_to_mask (XIMAGE_INSTANCE_TYPE (instantiator));
2460           if (mask & dest_mask)
2461             return instantiator;
2462           else
2463             signal_simple_error ("Type of image instance not allowed here",
2464                                  instantiator);
2465         }
2466       else
2467         signal_simple_error_2 ("Wrong device for image instance",
2468                                instantiator, device);
2469     }
2470   else if (VECTORP (instantiator)
2471            && EQ (XVECTOR_DATA (instantiator)[0], Qinherit))
2472     {
2473       assert (XVECTOR_LENGTH (instantiator) == 3);
2474       return (FACE_PROPERTY_INSTANCE
2475               (Fget_face (XVECTOR_DATA (instantiator)[2]),
2476                Qbackground_pixmap, domain, 0, depth));
2477     }
2478   else
2479     {
2480       Lisp_Object instance;
2481       Lisp_Object subtable;
2482       Lisp_Object ls3 = Qnil;
2483       Lisp_Object pointer_fg = Qnil;
2484       Lisp_Object pointer_bg = Qnil;
2485
2486       if (pointerp)
2487         {
2488           pointer_fg = FACE_FOREGROUND (Vpointer_face, domain);
2489           pointer_bg = FACE_BACKGROUND (Vpointer_face, domain);
2490           ls3 = list3 (instantiator, pointer_fg, pointer_bg);
2491         }
2492
2493       /* First look in the hash table. */
2494       subtable = Fgethash (make_int (dest_mask), d->image_instance_cache,
2495                            Qunbound);
2496       if (UNBOUNDP (subtable))
2497         {
2498           /* For the image instance cache, we do comparisons with EQ rather
2499              than with EQUAL, as we do for color and font names.
2500              The reasons are:
2501              
2502              1) pixmap data can be very long, and thus the hashing and
2503              comparing will take awhile.
2504              2) It's not so likely that we'll run into things that are EQUAL
2505              but not EQ (that can happen a lot with faces, because their
2506              specifiers are copied around); but pixmaps tend not to be
2507              in faces.
2508
2509              However, if the image-instance could be a pointer, we have to
2510              use EQUAL because we massaged the instantiator into a cons3
2511              also containing the foreground and background of the
2512              pointer face.
2513            */
2514
2515           subtable = make_lisp_hash_table (20,
2516                                            pointerp ? HASH_TABLE_KEY_CAR_WEAK
2517                                            : HASH_TABLE_KEY_WEAK,
2518                                            pointerp ? HASH_TABLE_EQUAL
2519                                            : HASH_TABLE_EQ);
2520           Fputhash (make_int (dest_mask), subtable,
2521                     d->image_instance_cache);
2522           instance = Qunbound;
2523         }
2524       else
2525         {
2526           instance = Fgethash (pointerp ? ls3 : instantiator,
2527                                subtable, Qunbound);
2528           /* subwindows have a per-window cache and have to be treated
2529              differently.  dest_mask can be a bitwise OR of all image
2530              types so we will only catch someone possibly trying to
2531              instantiate a subwindow type thing. Unfortunately, this
2532              will occur most of the time so this probably slows things
2533              down. But with the current design I don't see anyway
2534              round it. */
2535           if (UNBOUNDP (instance)
2536               &&
2537               dest_mask & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
2538             {
2539               if (!WINDOWP (domain))
2540                 signal_simple_error ("Can't instantiate subwindow outside a window",
2541                                      instantiator);
2542               instance = Fgethash (instantiator, 
2543                                    XWINDOW (domain)->subwindow_instance_cache, 
2544                                    Qunbound);
2545             }
2546         }
2547
2548       if (UNBOUNDP (instance))
2549         {
2550           Lisp_Object locative =
2551             noseeum_cons (Qnil,
2552                           noseeum_cons (pointerp ? ls3 : instantiator,
2553                                         subtable));
2554           int speccount = specpdl_depth ();
2555           
2556           /* make sure we cache the failures, too.
2557              Use an unwind-protect to catch such errors.
2558              If we fail, the unwind-protect records nil in
2559              the hash table.  If we succeed, we change the
2560              car of the locative to the resulting instance,
2561              which gets recorded instead. */
2562           record_unwind_protect (image_instantiate_cache_result,
2563                                  locative);
2564           instance = instantiate_image_instantiator (device,
2565                                                      domain,
2566                                                      instantiator,
2567                                                      pointer_fg, pointer_bg,
2568                                                      dest_mask);
2569           
2570           Fsetcar (locative, instance);
2571           /* only after the image has been instantiated do we know
2572              whether we need to put it in the per-window image instance
2573              cache. */
2574           if (image_instance_type_to_mask (XIMAGE_INSTANCE_TYPE (instance))
2575               &
2576               (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
2577             {
2578               if (!WINDOWP (domain))
2579                 signal_simple_error ("Can't instantiate subwindow outside a window",
2580                                      instantiator);
2581               
2582               Fsetcdr (XCDR (locative), XWINDOW (domain)->subwindow_instance_cache );
2583             }
2584           unbind_to (speccount, Qnil);
2585         }
2586       else
2587         free_list (ls3);
2588
2589       if (NILP (instance))
2590         signal_simple_error ("Can't instantiate image (probably cached)",
2591                              instantiator);
2592       return instance;
2593     }
2594
2595   abort ();
2596   return Qnil; /* not reached */
2597 }
2598
2599 /* Validate an image instantiator. */
2600
2601 static void
2602 image_validate (Lisp_Object instantiator)
2603 {
2604   if (IMAGE_INSTANCEP (instantiator) || STRINGP (instantiator))
2605     return;
2606   else if (VECTORP (instantiator))
2607     {
2608       Lisp_Object *elt = XVECTOR_DATA (instantiator);
2609       int instantiator_len = XVECTOR_LENGTH (instantiator);
2610       struct image_instantiator_methods *meths;
2611       Lisp_Object already_seen = Qnil;
2612       struct gcpro gcpro1;
2613       int i;
2614
2615       if (instantiator_len < 1)
2616         signal_simple_error ("Vector length must be at least 1",
2617                              instantiator);
2618
2619       meths = decode_image_instantiator_format (elt[0], ERROR_ME);
2620       if (!(instantiator_len & 1))
2621         signal_simple_error
2622           ("Must have alternating keyword/value pairs", instantiator);
2623
2624       GCPRO1 (already_seen);
2625
2626       for (i = 1; i < instantiator_len; i += 2)
2627         {
2628           Lisp_Object keyword = elt[i];
2629           Lisp_Object value = elt[i+1];
2630           int j;
2631
2632           CHECK_SYMBOL (keyword);
2633           if (!SYMBOL_IS_KEYWORD (keyword))
2634             signal_simple_error ("Symbol must begin with a colon", keyword);
2635
2636           for (j = 0; j < Dynarr_length (meths->keywords); j++)
2637             if (EQ (keyword, Dynarr_at (meths->keywords, j).keyword))
2638               break;
2639
2640           if (j == Dynarr_length (meths->keywords))
2641             signal_simple_error ("Unrecognized keyword", keyword);
2642
2643           if (!Dynarr_at (meths->keywords, j).multiple_p)
2644             {
2645               if (!NILP (memq_no_quit (keyword, already_seen)))
2646                 signal_simple_error
2647                   ("Keyword may not appear more than once", keyword);
2648               already_seen = Fcons (keyword, already_seen);
2649             }
2650
2651           (Dynarr_at (meths->keywords, j).validate) (value);
2652         }
2653
2654       UNGCPRO;
2655
2656       MAYBE_IIFORMAT_METH (meths, validate, (instantiator));
2657     }
2658   else
2659     signal_simple_error ("Must be string or vector", instantiator);
2660 }
2661
2662 static void
2663 image_after_change (Lisp_Object specifier, Lisp_Object locale)
2664 {
2665   Lisp_Object attachee =
2666     IMAGE_SPECIFIER_ATTACHEE (XIMAGE_SPECIFIER (specifier));
2667   Lisp_Object property =
2668     IMAGE_SPECIFIER_ATTACHEE_PROPERTY (XIMAGE_SPECIFIER (specifier));
2669   if (FACEP (attachee))
2670     face_property_was_changed (attachee, property, locale);
2671   else if (GLYPHP (attachee))
2672     glyph_property_was_changed (attachee, property, locale);
2673 }
2674
2675 void
2676 set_image_attached_to (Lisp_Object obj, Lisp_Object face_or_glyph,
2677                        Lisp_Object property)
2678 {
2679   struct Lisp_Specifier *image = XIMAGE_SPECIFIER (obj);
2680
2681   IMAGE_SPECIFIER_ATTACHEE (image) = face_or_glyph;
2682   IMAGE_SPECIFIER_ATTACHEE_PROPERTY (image) = property;
2683 }
2684
2685 static Lisp_Object
2686 image_going_to_add (Lisp_Object specifier, Lisp_Object locale,
2687                     Lisp_Object tag_set, Lisp_Object instantiator)
2688 {
2689   Lisp_Object possible_console_types = Qnil;
2690   Lisp_Object rest;
2691   Lisp_Object retlist = Qnil;
2692   struct gcpro gcpro1, gcpro2;
2693
2694   LIST_LOOP (rest, Vconsole_type_list)
2695     {
2696       Lisp_Object contype = XCAR (rest);
2697       if (!NILP (memq_no_quit (contype, tag_set)))
2698         possible_console_types = Fcons (contype, possible_console_types);
2699     }
2700
2701   if (XINT (Flength (possible_console_types)) > 1)
2702     /* two conflicting console types specified */
2703     return Qnil;
2704
2705   if (NILP (possible_console_types))
2706     possible_console_types = Vconsole_type_list;
2707
2708   GCPRO2 (retlist, possible_console_types);
2709
2710   LIST_LOOP (rest, possible_console_types)
2711     {
2712       Lisp_Object contype = XCAR (rest);
2713       Lisp_Object newinst = call_with_suspended_errors
2714         ((lisp_fn_t) normalize_image_instantiator,
2715          Qnil, Qimage, ERROR_ME_NOT, 3, instantiator, contype,
2716          make_int (XIMAGE_SPECIFIER_ALLOWED (specifier)));
2717
2718       if (!NILP (newinst))
2719         {
2720           Lisp_Object newtag;
2721           if (NILP (memq_no_quit (contype, tag_set)))
2722             newtag = Fcons (contype, tag_set);
2723           else
2724             newtag = tag_set;
2725           retlist = Fcons (Fcons (newtag, newinst), retlist);
2726         }
2727     }
2728
2729   UNGCPRO;
2730
2731   return retlist;
2732 }
2733
2734 DEFUN ("image-specifier-p", Fimage_specifier_p, 1, 1, 0, /*
2735 Return non-nil if OBJECT is an image specifier.
2736
2737 An image specifier is used for images (pixmaps and the like).  It is used
2738 to describe the actual image in a glyph.  It is instanced as an image-
2739 instance.
2740
2741 Image instantiators come in many formats: `xbm', `xpm', `gif', `jpeg',
2742 etc.  This describes the format of the data describing the image.  The
2743 resulting image instances also come in many types -- `mono-pixmap',
2744 `color-pixmap', `text', `pointer', etc.  This refers to the behavior of
2745 the image and the sorts of places it can appear. (For example, a
2746 color-pixmap image has fixed colors specified for it, while a
2747 mono-pixmap image comes in two unspecified shades "foreground" and
2748 "background" that are determined from the face of the glyph or
2749 surrounding text; a text image appears as a string of text and has an
2750 unspecified foreground, background, and font; a pointer image behaves
2751 like a mono-pixmap image but can only be used as a mouse pointer
2752 \[mono-pixmap images cannot be used as mouse pointers]; etc.) It is
2753 important to keep the distinction between image instantiator format and
2754 image instance type in mind.  Typically, a given image instantiator
2755 format can result in many different image instance types (for example,
2756 `xpm' can be instanced as `color-pixmap', `mono-pixmap', or `pointer';
2757 whereas `cursor-font' can be instanced only as `pointer'), and a
2758 particular image instance type can be generated by many different
2759 image instantiator formats (e.g.  `color-pixmap' can be generated by `xpm',
2760 `gif', `jpeg', etc.).
2761
2762 See `make-image-instance' for a more detailed discussion of image
2763 instance types.
2764
2765 An image instantiator should be a string or a vector of the form
2766
2767  [FORMAT :KEYWORD VALUE ...]
2768
2769 i.e. a format symbol followed by zero or more alternating keyword-value
2770 pairs.  FORMAT should be one of
2771
2772 'nothing
2773   (Don't display anything; no keywords are valid for this.
2774    Can only be instanced as `nothing'.)
2775 'string
2776   (Display this image as a text string.  Can only be instanced
2777    as `text', although support for instancing as `mono-pixmap'
2778    should be added.)
2779 'formatted-string
2780   (Display this image as a text string, with replaceable fields;
2781   not currently implemented.)
2782 'xbm
2783   (An X bitmap; only if X or Windows support was compiled into this XEmacs.
2784    Can be instanced as `mono-pixmap', `color-pixmap', or `pointer'.)
2785 'xpm
2786   (An XPM pixmap; only if XPM support was compiled into this XEmacs.
2787    Can be instanced as `color-pixmap', `mono-pixmap', or `pointer'.)
2788 'xface
2789   (An X-Face bitmap, used to encode people's faces in e-mail messages;
2790   only if X-Face support was compiled into this XEmacs.  Can be
2791   instanced as `mono-pixmap', `color-pixmap', or `pointer'.)
2792 'gif
2793   (A GIF87 or GIF89 image; only if GIF support was compiled into this
2794    XEmacs.  NOTE: only the first frame of animated gifs will be displayed.
2795    Can be instanced as `color-pixmap'.)
2796 'jpeg
2797   (A JPEG image; only if JPEG support was compiled into this XEmacs.
2798    Can be instanced as `color-pixmap'.)
2799 'png
2800   (A PNG image; only if PNG support was compiled into this XEmacs.
2801    Can be instanced as `color-pixmap'.)
2802 'tiff
2803   (A TIFF image; only if TIFF support was compiled into this XEmacs.
2804    Can be instanced as `color-pixmap'.)
2805 'cursor-font
2806   (One of the standard cursor-font names, such as "watch" or
2807    "right_ptr" under X.  Under X, this is, more specifically, any
2808    of the standard cursor names from appendix B of the Xlib manual
2809    [also known as the file <X11/cursorfont.h>] minus the XC_ prefix.
2810    On other window systems, the valid names will be specific to the
2811    type of window system.  Can only be instanced as `pointer'.)
2812 'font
2813   (A glyph from a font; i.e. the name of a font, and glyph index into it
2814    of the form "FONT fontname index [[mask-font] mask-index]".
2815    Currently can only be instanced as `pointer', although this should
2816    probably be fixed.)
2817 'subwindow
2818   (An embedded windowing system window.)
2819 'edit-field
2820   (A text editing widget glyph.)
2821 'button
2822   (A button widget glyph; either a push button, radio button or toggle button.)
2823 'tab-control
2824   (A tab widget glyph; a series of user selectable tabs.)
2825 'progress-gauge
2826   (A sliding widget glyph, for showing progress.)
2827 'combo-box
2828   (A drop list of selectable items in a widget glyph, for editing text.)
2829 'label
2830   (A static, text-only, widget glyph; for displaying text.)
2831 'tree-view
2832   (A folding widget glyph.)
2833 'autodetect
2834   (XEmacs tries to guess what format the data is in.  If X support
2835   exists, the data string will be checked to see if it names a filename.
2836   If so, and this filename contains XBM or XPM data, the appropriate
2837   sort of pixmap or pointer will be created. [This includes picking up
2838   any specified hotspot or associated mask file.] Otherwise, if `pointer'
2839   is one of the allowable image-instance types and the string names a
2840   valid cursor-font name, the image will be created as a pointer.
2841   Otherwise, the image will be displayed as text.  If no X support
2842   exists, the image will always be displayed as text.)
2843 'inherit
2844   Inherit from the background-pixmap property of a face.
2845
2846 The valid keywords are:
2847
2848 :data
2849   (Inline data.  For most formats above, this should be a string.  For
2850   XBM images, this should be a list of three elements: width, height, and
2851   a string of bit data.  This keyword is not valid for instantiator
2852   formats `nothing' and `inherit'.)
2853 :file
2854   (Data is contained in a file.  The value is the name of this file.
2855   If both :data and :file are specified, the image is created from
2856   what is specified in :data and the string in :file becomes the
2857   value of the `image-instance-file-name' function when applied to
2858   the resulting image-instance.  This keyword is not valid for
2859   instantiator formats `nothing', `string', `formatted-string',
2860   `cursor-font', `font', `autodetect', and `inherit'.)
2861 :foreground
2862 :background
2863   (For `xbm', `xface', `cursor-font', `widget' and `font'.  These keywords
2864   allow you to explicitly specify foreground and background colors.
2865   The argument should be anything acceptable to `make-color-instance'.
2866   This will cause what would be a `mono-pixmap' to instead be colorized
2867   as a two-color color-pixmap, and specifies the foreground and/or
2868   background colors for a pointer instead of black and white.)
2869 :mask-data
2870   (For `xbm' and `xface'.  This specifies a mask to be used with the
2871   bitmap.  The format is a list of width, height, and bits, like for
2872   :data.)
2873 :mask-file
2874   (For `xbm' and `xface'.  This specifies a file containing the mask data.
2875   If neither a mask file nor inline mask data is given for an XBM image,
2876   and the XBM image comes from a file, XEmacs will look for a mask file
2877   with the same name as the image file but with "Mask" or "msk"
2878   appended.  For example, if you specify the XBM file "left_ptr"
2879   [usually located in "/usr/include/X11/bitmaps"], the associated
2880   mask file "left_ptrmsk" will automatically be picked up.)
2881 :hotspot-x
2882 :hotspot-y
2883   (For `xbm' and `xface'.  These keywords specify a hotspot if the image
2884   is instantiated as a `pointer'.  Note that if the XBM image file
2885   specifies a hotspot, it will automatically be picked up if no
2886   explicit hotspot is given.)
2887 :color-symbols
2888   (Only for `xpm'.  This specifies an alist that maps strings
2889   that specify symbolic color names to the actual color to be used
2890   for that symbolic color (in the form of a string or a color-specifier
2891   object).  If this is not specified, the contents of `xpm-color-symbols'
2892   are used to generate the alist.)
2893 :face
2894   (Only for `inherit'.  This specifies the face to inherit from.
2895   For widget glyphs this also specifies the face to use for
2896   display. It defaults to gui-element-face.)
2897
2898 Keywords accepted as menu item specs are also accepted by widget
2899 glyphs. These are `:selected', `:active', `:suffix', `:keys',
2900 `:style', `:filter', `:config', `:included', `:key-sequence',
2901 `:accelerator', `:label' and `:callback'.
2902
2903 If instead of a vector, the instantiator is a string, it will be
2904 converted into a vector by looking it up according to the specs in the
2905 `console-type-image-conversion-list' (q.v.) for the console type of
2906 the domain (usually a window; sometimes a frame or device) over which
2907 the image is being instantiated.
2908
2909 If the instantiator specifies data from a file, the data will be read
2910 in at the time that the instantiator is added to the image (which may
2911 be well before when the image is actually displayed), and the
2912 instantiator will be converted into one of the inline-data forms, with
2913 the filename retained using a :file keyword.  This implies that the
2914 file must exist when the instantiator is added to the image, but does
2915 not need to exist at any other time (e.g. it may safely be a temporary
2916 file).
2917 */
2918        (object))
2919 {
2920   return IMAGE_SPECIFIERP (object) ? Qt : Qnil;
2921 }
2922
2923 \f
2924 /****************************************************************************
2925  *                             Glyph Object                                 *
2926  ****************************************************************************/
2927
2928 static Lisp_Object
2929 mark_glyph (Lisp_Object obj)
2930 {
2931   struct Lisp_Glyph *glyph = XGLYPH (obj);
2932
2933   mark_object (glyph->image);
2934   mark_object (glyph->contrib_p);
2935   mark_object (glyph->baseline);
2936   mark_object (glyph->face);
2937
2938   return glyph->plist;
2939 }
2940
2941 static void
2942 print_glyph (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
2943 {
2944   struct Lisp_Glyph *glyph = XGLYPH (obj);
2945   char buf[20];
2946
2947   if (print_readably)
2948     error ("printing unreadable object #<glyph 0x%x>", glyph->header.uid);
2949
2950   write_c_string ("#<glyph (", printcharfun);
2951   print_internal (Fglyph_type (obj), printcharfun, 0);
2952   write_c_string (") ", printcharfun);
2953   print_internal (glyph->image, printcharfun, 1);
2954   sprintf (buf, "0x%x>", glyph->header.uid);
2955   write_c_string (buf, printcharfun);
2956 }
2957
2958 /* Glyphs are equal if all of their display attributes are equal.  We
2959    don't compare names or doc-strings, because that would make equal
2960    be eq.
2961
2962    This isn't concerned with "unspecified" attributes, that's what
2963    #'glyph-differs-from-default-p is for. */
2964 static int
2965 glyph_equal (Lisp_Object obj1, Lisp_Object obj2, int depth)
2966 {
2967   struct Lisp_Glyph *g1 = XGLYPH (obj1);
2968   struct Lisp_Glyph *g2 = XGLYPH (obj2);
2969
2970   depth++;
2971
2972   return (internal_equal (g1->image,     g2->image,     depth) &&
2973           internal_equal (g1->contrib_p, g2->contrib_p, depth) &&
2974           internal_equal (g1->baseline,  g2->baseline,  depth) &&
2975           internal_equal (g1->face,      g2->face,      depth) &&
2976           !plists_differ (g1->plist,     g2->plist, 0, 0, depth + 1));
2977 }
2978
2979 static unsigned long
2980 glyph_hash (Lisp_Object obj, int depth)
2981 {
2982   depth++;
2983
2984   /* No need to hash all of the elements; that would take too long.
2985      Just hash the most common ones. */
2986   return HASH2 (internal_hash (XGLYPH (obj)->image, depth),
2987                 internal_hash (XGLYPH (obj)->face,  depth));
2988 }
2989
2990 static Lisp_Object
2991 glyph_getprop (Lisp_Object obj, Lisp_Object prop)
2992 {
2993   struct Lisp_Glyph *g = XGLYPH (obj);
2994
2995   if (EQ (prop, Qimage))     return g->image;
2996   if (EQ (prop, Qcontrib_p)) return g->contrib_p;
2997   if (EQ (prop, Qbaseline))  return g->baseline;
2998   if (EQ (prop, Qface))      return g->face;
2999
3000   return external_plist_get (&g->plist, prop, 0, ERROR_ME);
3001 }
3002
3003 static int
3004 glyph_putprop (Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
3005 {
3006   if (EQ (prop, Qimage)     ||
3007       EQ (prop, Qcontrib_p) ||
3008       EQ (prop, Qbaseline))
3009     return 0;
3010
3011   if (EQ (prop, Qface))
3012     {
3013       XGLYPH (obj)->face = Fget_face (value);
3014       return 1;
3015     }
3016
3017   external_plist_put (&XGLYPH (obj)->plist, prop, value, 0, ERROR_ME);
3018   return 1;
3019 }
3020
3021 static int
3022 glyph_remprop (Lisp_Object obj, Lisp_Object prop)
3023 {
3024   if (EQ (prop, Qimage)     ||
3025       EQ (prop, Qcontrib_p) ||
3026       EQ (prop, Qbaseline))
3027     return -1;
3028
3029   if (EQ (prop, Qface))
3030     {
3031       XGLYPH (obj)->face = Qnil;
3032       return 1;
3033     }
3034
3035   return external_remprop (&XGLYPH (obj)->plist, prop, 0, ERROR_ME);
3036 }
3037
3038 static Lisp_Object
3039 glyph_plist (Lisp_Object obj)
3040 {
3041   struct Lisp_Glyph *glyph = XGLYPH (obj);
3042   Lisp_Object result = glyph->plist;
3043
3044   result = cons3 (Qface,      glyph->face,      result);
3045   result = cons3 (Qbaseline,  glyph->baseline,  result);
3046   result = cons3 (Qcontrib_p, glyph->contrib_p, result);
3047   result = cons3 (Qimage,     glyph->image,     result);
3048
3049   return result;
3050 }
3051
3052 static const struct lrecord_description glyph_description[] = {
3053   { XD_LISP_OBJECT, offsetof(struct Lisp_Glyph, image), 5 },
3054   { XD_END }
3055 };
3056
3057 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS ("glyph", glyph,
3058                                           mark_glyph, print_glyph, 0,
3059                                           glyph_equal, glyph_hash, glyph_description,
3060                                           glyph_getprop, glyph_putprop,
3061                                           glyph_remprop, glyph_plist,
3062                                           struct Lisp_Glyph);
3063 \f
3064 Lisp_Object
3065 allocate_glyph (enum glyph_type type,
3066                 void (*after_change) (Lisp_Object glyph, Lisp_Object property,
3067                                       Lisp_Object locale))
3068 {
3069   /* This function can GC */
3070   Lisp_Object obj = Qnil;
3071   struct Lisp_Glyph *g =
3072     alloc_lcrecord_type (struct Lisp_Glyph, &lrecord_glyph);
3073
3074   g->type = type;
3075   g->image = Fmake_specifier (Qimage); /* This function can GC */
3076   g->dirty = 0;
3077   switch (g->type)
3078     {
3079     case GLYPH_BUFFER:
3080       XIMAGE_SPECIFIER_ALLOWED (g->image) =
3081         IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK 
3082         | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK 
3083         | IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK
3084         | IMAGE_LAYOUT_MASK;
3085       break;
3086     case GLYPH_POINTER:
3087       XIMAGE_SPECIFIER_ALLOWED (g->image) =
3088         IMAGE_NOTHING_MASK | IMAGE_POINTER_MASK;
3089       break;
3090     case GLYPH_ICON:
3091       XIMAGE_SPECIFIER_ALLOWED (g->image) =
3092         IMAGE_NOTHING_MASK | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK;
3093       break;
3094     default:
3095       abort ();
3096     }
3097
3098   /* I think Fmake_specifier can GC.  I think set_specifier_fallback can GC. */
3099   /* We're getting enough reports of odd behavior in this area it seems */
3100   /* best to GCPRO everything. */
3101   {
3102     Lisp_Object tem1 = list1 (Fcons (Qnil, Vthe_nothing_vector));
3103     Lisp_Object tem2 = list1 (Fcons (Qnil, Qt));
3104     Lisp_Object tem3 = list1 (Fcons (Qnil, Qnil));
3105     struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3106
3107     GCPRO4 (obj, tem1, tem2, tem3);
3108
3109     set_specifier_fallback (g->image, tem1);
3110     g->contrib_p = Fmake_specifier (Qboolean);
3111     set_specifier_fallback (g->contrib_p, tem2);
3112     /* #### should have a specifier for the following */
3113     g->baseline = Fmake_specifier (Qgeneric);
3114     set_specifier_fallback (g->baseline, tem3);
3115     g->face = Qnil;
3116     g->plist = Qnil;
3117     g->after_change = after_change;
3118     XSETGLYPH (obj, g);
3119
3120     set_image_attached_to (g->image, obj, Qimage);
3121     UNGCPRO;
3122   }
3123
3124   return obj;
3125 }
3126
3127 static enum glyph_type
3128 decode_glyph_type (Lisp_Object type, Error_behavior errb)
3129 {
3130   if (NILP (type))
3131     return GLYPH_BUFFER;
3132
3133   if (ERRB_EQ (errb, ERROR_ME))
3134     CHECK_SYMBOL (type);
3135
3136   if (EQ (type, Qbuffer))  return GLYPH_BUFFER;
3137   if (EQ (type, Qpointer)) return GLYPH_POINTER;
3138   if (EQ (type, Qicon))    return GLYPH_ICON;
3139
3140   maybe_signal_simple_error ("Invalid glyph type", type, Qimage, errb);
3141
3142   return GLYPH_UNKNOWN;
3143 }
3144
3145 static int
3146 valid_glyph_type_p (Lisp_Object type)
3147 {
3148   return !NILP (memq_no_quit (type, Vglyph_type_list));
3149 }
3150
3151 DEFUN ("valid-glyph-type-p", Fvalid_glyph_type_p, 1, 1, 0, /*
3152 Given a GLYPH-TYPE, return non-nil if it is valid.
3153 Valid types are `buffer', `pointer', and `icon'.
3154 */
3155        (glyph_type))
3156 {
3157   return valid_glyph_type_p (glyph_type) ? Qt : Qnil;
3158 }
3159
3160 DEFUN ("glyph-type-list", Fglyph_type_list, 0, 0, 0, /*
3161 Return a list of valid glyph types.
3162 */
3163        ())
3164 {
3165   return Fcopy_sequence (Vglyph_type_list);
3166 }
3167
3168 DEFUN ("make-glyph-internal", Fmake_glyph_internal, 0, 1, 0, /*
3169 Create and return a new uninitialized glyph or type TYPE.
3170
3171 TYPE specifies the type of the glyph; this should be one of `buffer',
3172 `pointer', or `icon', and defaults to `buffer'.  The type of the glyph
3173 specifies in which contexts the glyph can be used, and controls the
3174 allowable image types into which the glyph's image can be
3175 instantiated.
3176
3177 `buffer' glyphs can be used as the begin-glyph or end-glyph of an
3178 extent, in the modeline, and in the toolbar.  Their image can be
3179 instantiated as `nothing', `mono-pixmap', `color-pixmap', `text',
3180 and `subwindow'.
3181
3182 `pointer' glyphs can be used to specify the mouse pointer.  Their
3183 image can be instantiated as `pointer'.
3184
3185 `icon' glyphs can be used to specify the icon used when a frame is
3186 iconified.  Their image can be instantiated as `mono-pixmap' and
3187 `color-pixmap'.
3188 */
3189        (type))
3190 {
3191   enum glyph_type typeval = decode_glyph_type (type, ERROR_ME);
3192   return allocate_glyph (typeval, 0);
3193 }
3194
3195 DEFUN ("glyphp", Fglyphp, 1, 1, 0, /*
3196 Return non-nil if OBJECT is a glyph.
3197
3198 A glyph is an object used for pixmaps and the like.  It is used
3199 in begin-glyphs and end-glyphs attached to extents, in marginal and textual
3200 annotations, in overlay arrows (overlay-arrow-* variables), in toolbar
3201 buttons, and the like.  Its image is described using an image specifier --
3202 see `image-specifier-p'.
3203 */
3204        (object))
3205 {
3206   return GLYPHP (object) ? Qt : Qnil;
3207 }
3208
3209 DEFUN ("glyph-type", Fglyph_type, 1, 1, 0, /*
3210 Return the type of the given glyph.
3211 The return value will be one of 'buffer, 'pointer, or 'icon.
3212 */
3213        (glyph))
3214 {
3215   CHECK_GLYPH (glyph);
3216   switch (XGLYPH_TYPE (glyph))
3217     {
3218     default: abort ();
3219     case GLYPH_BUFFER:  return Qbuffer;
3220     case GLYPH_POINTER: return Qpointer;
3221     case GLYPH_ICON:    return Qicon;
3222     }
3223 }
3224
3225 /*****************************************************************************
3226  glyph_width
3227
3228  Return the width of the given GLYPH on the given WINDOW.  If the
3229  instance is a string then the width is calculated using the font of
3230  the given FACE, unless a face is defined by the glyph itself.
3231  ****************************************************************************/
3232 unsigned short
3233 glyph_width (Lisp_Object glyph_or_image, Lisp_Object frame_face,
3234              face_index window_findex, Lisp_Object window)
3235 {
3236   Lisp_Object instance = glyph_or_image;
3237   Lisp_Object frame = XWINDOW (window)->frame;
3238
3239   /* #### We somehow need to distinguish between the user causing this
3240      error condition and a bug causing it. */
3241   if (GLYPHP (glyph_or_image))
3242     instance = glyph_image_instance (glyph_or_image, window, ERROR_ME_NOT, 1);
3243
3244   if (!IMAGE_INSTANCEP (instance))
3245     return 0;
3246
3247   switch (XIMAGE_INSTANCE_TYPE (instance))
3248     {
3249     case IMAGE_TEXT:
3250       {
3251         Lisp_Object str = XIMAGE_INSTANCE_TEXT_STRING (instance);
3252         Lisp_Object private_face = Qnil;
3253
3254         if (GLYPHP (glyph_or_image))
3255           private_face = XGLYPH_FACE(glyph_or_image);
3256
3257         if (!NILP (private_face))
3258           return redisplay_frame_text_width_string (XFRAME (frame),
3259                                                     private_face,
3260                                                     0, str, 0, -1);
3261         else
3262         if (!NILP (frame_face))
3263           return redisplay_frame_text_width_string (XFRAME (frame),
3264                                                     frame_face,
3265                                                     0, str, 0, -1);
3266         else
3267           return redisplay_text_width_string (XWINDOW (window),
3268                                               window_findex,
3269                                               0, str, 0, -1);
3270       }
3271
3272     case IMAGE_MONO_PIXMAP:
3273     case IMAGE_COLOR_PIXMAP:
3274     case IMAGE_POINTER:
3275       return XIMAGE_INSTANCE_PIXMAP_WIDTH (instance);
3276
3277     case IMAGE_NOTHING:
3278       return 0;
3279
3280     case IMAGE_SUBWINDOW:
3281     case IMAGE_WIDGET:
3282     case IMAGE_LAYOUT:
3283       return XIMAGE_INSTANCE_SUBWINDOW_WIDTH (instance);
3284
3285     default:
3286       abort ();
3287       return 0;
3288     }
3289 }
3290
3291 DEFUN ("glyph-width", Fglyph_width, 1, 2, 0, /*
3292 Return the width of GLYPH on WINDOW.
3293 This may not be exact as it does not take into account all of the context
3294 that redisplay will.
3295 */
3296        (glyph, window))
3297 {
3298   XSETWINDOW (window, decode_window (window));
3299   CHECK_GLYPH (glyph);
3300
3301   return make_int (glyph_width (glyph, Qnil, DEFAULT_INDEX, window));
3302 }
3303
3304 #define RETURN_ASCENT   0
3305 #define RETURN_DESCENT  1
3306 #define RETURN_HEIGHT   2
3307
3308 Lisp_Object
3309 glyph_image_instance (Lisp_Object glyph, Lisp_Object domain,
3310                       Error_behavior errb, int no_quit)
3311 {
3312   Lisp_Object specifier = GLYPH_IMAGE (XGLYPH (glyph));
3313
3314   /* This can never return Qunbound.  All glyphs have 'nothing as
3315      a fallback. */
3316   return specifier_instance (specifier, Qunbound, domain, errb, no_quit, 0,
3317                              Qzero);
3318 }
3319
3320 static unsigned short
3321 glyph_height_internal (Lisp_Object glyph_or_image, Lisp_Object frame_face,
3322                        face_index window_findex, Lisp_Object window,
3323                        int function)
3324 {
3325   Lisp_Object instance = glyph_or_image;
3326   Lisp_Object frame = XWINDOW (window)->frame;
3327
3328   if (GLYPHP (glyph_or_image))
3329     instance = glyph_image_instance (glyph_or_image, window, ERROR_ME_NOT, 1);
3330
3331   if (!IMAGE_INSTANCEP (instance))
3332     return 0;
3333
3334   switch (XIMAGE_INSTANCE_TYPE (instance))
3335     {
3336     case IMAGE_TEXT:
3337       {
3338         struct font_metric_info fm;
3339         Lisp_Object string = XIMAGE_INSTANCE_TEXT_STRING (instance);
3340         unsigned char charsets[NUM_LEADING_BYTES];
3341         struct face_cachel frame_cachel;
3342         struct face_cachel *cachel;
3343
3344         find_charsets_in_bufbyte_string (charsets,
3345                                          XSTRING_DATA   (string),
3346                                          XSTRING_LENGTH (string));
3347
3348         if (!NILP (frame_face))
3349           {
3350             reset_face_cachel (&frame_cachel);
3351             update_face_cachel_data (&frame_cachel, frame, frame_face);
3352             cachel = &frame_cachel;
3353           }
3354         else
3355           cachel = WINDOW_FACE_CACHEL (XWINDOW (window), window_findex);
3356         ensure_face_cachel_complete (cachel, window, charsets);
3357
3358         face_cachel_charset_font_metric_info (cachel, charsets, &fm);
3359
3360         switch (function)
3361           {
3362           case RETURN_ASCENT:  return fm.ascent;
3363           case RETURN_DESCENT: return fm.descent;
3364           case RETURN_HEIGHT:  return fm.ascent + fm.descent;
3365           default:
3366             abort ();
3367             return 0; /* not reached */
3368           }
3369       }
3370
3371     case IMAGE_MONO_PIXMAP:
3372     case IMAGE_COLOR_PIXMAP:
3373     case IMAGE_POINTER:
3374       /* #### Ugh ugh ugh -- temporary crap */
3375       if (function == RETURN_ASCENT || function == RETURN_HEIGHT)
3376         return XIMAGE_INSTANCE_PIXMAP_HEIGHT (instance);
3377       else
3378         return 0;
3379
3380     case IMAGE_NOTHING:
3381       return 0;
3382
3383     case IMAGE_SUBWINDOW:
3384     case IMAGE_WIDGET:
3385     case IMAGE_LAYOUT:
3386       /* #### Ugh ugh ugh -- temporary crap */
3387       if (function == RETURN_ASCENT || function == RETURN_HEIGHT)
3388         return XIMAGE_INSTANCE_SUBWINDOW_HEIGHT (instance);
3389       else
3390         return 0;
3391
3392     default:
3393       abort ();
3394       return 0;
3395     }
3396 }
3397
3398 unsigned short
3399 glyph_ascent (Lisp_Object glyph, Lisp_Object frame_face,
3400               face_index window_findex, Lisp_Object window)
3401 {
3402   return glyph_height_internal (glyph, frame_face, window_findex, window,
3403                                 RETURN_ASCENT);
3404 }
3405
3406 unsigned short
3407 glyph_descent (Lisp_Object glyph, Lisp_Object frame_face,
3408                face_index window_findex, Lisp_Object window)
3409 {
3410   return glyph_height_internal (glyph, frame_face, window_findex, window,
3411                                 RETURN_DESCENT);
3412 }
3413
3414 /* strictly a convenience function. */
3415 unsigned short
3416 glyph_height (Lisp_Object glyph, Lisp_Object frame_face,
3417               face_index window_findex, Lisp_Object window)
3418 {
3419   return glyph_height_internal (glyph, frame_face, window_findex, window,
3420                                 RETURN_HEIGHT);
3421 }
3422
3423 DEFUN ("glyph-ascent", Fglyph_ascent, 1, 2, 0, /*
3424 Return the ascent value of GLYPH on WINDOW.
3425 This may not be exact as it does not take into account all of the context
3426 that redisplay will.
3427 */
3428        (glyph, window))
3429 {
3430   XSETWINDOW (window, decode_window (window));
3431   CHECK_GLYPH (glyph);
3432
3433   return make_int (glyph_ascent (glyph, Qnil, DEFAULT_INDEX, window));
3434 }
3435
3436 DEFUN ("glyph-descent", Fglyph_descent, 1, 2, 0, /*
3437 Return the descent value of GLYPH on WINDOW.
3438 This may not be exact as it does not take into account all of the context
3439 that redisplay will.
3440 */
3441        (glyph, window))
3442 {
3443   XSETWINDOW (window, decode_window (window));
3444   CHECK_GLYPH (glyph);
3445
3446   return make_int (glyph_descent (glyph, Qnil, DEFAULT_INDEX, window));
3447 }
3448
3449 /* This is redundant but I bet a lot of people expect it to exist. */
3450 DEFUN ("glyph-height", Fglyph_height, 1, 2, 0, /*
3451 Return the height of GLYPH on WINDOW.
3452 This may not be exact as it does not take into account all of the context
3453 that redisplay will.
3454 */
3455        (glyph, window))
3456 {
3457   XSETWINDOW (window, decode_window (window));
3458   CHECK_GLYPH (glyph);
3459
3460   return make_int (glyph_height (glyph, Qnil, DEFAULT_INDEX, window));
3461 }
3462
3463 #undef RETURN_ASCENT
3464 #undef RETURN_DESCENT
3465 #undef RETURN_HEIGHT
3466
3467 static unsigned int
3468 glyph_dirty_p (Lisp_Object glyph_or_image, Lisp_Object window)
3469 {
3470   Lisp_Object instance = glyph_or_image;
3471
3472   if (GLYPHP (glyph_or_image))
3473     instance = glyph_image_instance (glyph_or_image, window, ERROR_ME_NOT, 1);
3474
3475   return XIMAGE_INSTANCE_DIRTYP (instance);
3476 }
3477
3478 static void
3479 set_glyph_dirty_p (Lisp_Object glyph_or_image, Lisp_Object window, int dirty)
3480 {
3481   Lisp_Object instance = glyph_or_image;
3482
3483   if (!NILP (glyph_or_image))
3484     {
3485       if (GLYPHP (glyph_or_image))
3486         {
3487           instance = glyph_image_instance (glyph_or_image, window,
3488                                            ERROR_ME_NOT, 1);
3489           XGLYPH_DIRTYP (glyph_or_image) = dirty;
3490         }
3491
3492       XIMAGE_INSTANCE_DIRTYP (instance) = dirty;
3493     }
3494 }
3495
3496 /* #### do we need to cache this info to speed things up? */
3497
3498 Lisp_Object
3499 glyph_baseline (Lisp_Object glyph, Lisp_Object domain)
3500 {
3501   if (!GLYPHP (glyph))
3502     return Qnil;
3503   else
3504     {
3505       Lisp_Object retval =
3506         specifier_instance_no_quit (GLYPH_BASELINE (XGLYPH (glyph)),
3507                                     /* #### look into ERROR_ME_NOT */
3508                                     Qunbound, domain, ERROR_ME_NOT,
3509                                     0, Qzero);
3510       if (!NILP (retval) && !INTP (retval))
3511         retval = Qnil;
3512       else if (INTP (retval))
3513         {
3514           if (XINT (retval) < 0)
3515             retval = Qzero;
3516           if (XINT (retval) > 100)
3517             retval = make_int (100);
3518         }
3519       return retval;
3520     }
3521 }
3522
3523 Lisp_Object
3524 glyph_face (Lisp_Object glyph, Lisp_Object domain)
3525 {
3526   /* #### Domain parameter not currently used but it will be */
3527   return GLYPHP (glyph) ? GLYPH_FACE (XGLYPH (glyph)) : Qnil;
3528 }
3529
3530 int
3531 glyph_contrib_p (Lisp_Object glyph, Lisp_Object domain)
3532 {
3533   if (!GLYPHP (glyph))
3534     return 0;
3535   else
3536     return !NILP (specifier_instance_no_quit
3537                   (GLYPH_CONTRIB_P (XGLYPH (glyph)), Qunbound, domain,
3538                    /* #### look into ERROR_ME_NOT */
3539                    ERROR_ME_NOT, 0, Qzero));
3540 }
3541
3542 static void
3543 glyph_property_was_changed (Lisp_Object glyph, Lisp_Object property,
3544                             Lisp_Object locale)
3545 {
3546   if (XGLYPH (glyph)->after_change)
3547     (XGLYPH (glyph)->after_change) (glyph, property, locale);
3548 }
3549
3550 \f
3551 /*****************************************************************************
3552  *                     glyph cachel functions                                *
3553  *****************************************************************************/
3554
3555 /*
3556  #### All of this is 95% copied from face cachels.
3557       Consider consolidating.
3558  */
3559
3560 void
3561 mark_glyph_cachels (glyph_cachel_dynarr *elements)
3562 {
3563   int elt;
3564
3565   if (!elements)
3566     return;
3567
3568   for (elt = 0; elt < Dynarr_length (elements); elt++)
3569     {
3570       struct glyph_cachel *cachel = Dynarr_atp (elements, elt);
3571       mark_object (cachel->glyph);
3572     }
3573 }
3574
3575 static void
3576 update_glyph_cachel_data (struct window *w, Lisp_Object glyph,
3577                           struct glyph_cachel *cachel)
3578 {
3579   if (!cachel->updated || NILP (cachel->glyph) || !EQ (cachel->glyph, glyph)
3580       || XGLYPH_DIRTYP (cachel->glyph))
3581     {
3582       Lisp_Object window, instance;
3583
3584       XSETWINDOW (window, w);
3585
3586       cachel->glyph   = glyph;
3587     /* Speed things up slightly by grabbing the glyph instantiation
3588        and passing it to the size functions. */
3589       instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
3590       cachel->dirty = XGLYPH_DIRTYP (glyph) = glyph_dirty_p (glyph, window);
3591       cachel->width   = glyph_width   (instance, Qnil, DEFAULT_INDEX, window);
3592       cachel->ascent  = glyph_ascent  (instance, Qnil, DEFAULT_INDEX, window);
3593       cachel->descent = glyph_descent (instance, Qnil, DEFAULT_INDEX, window);
3594     }
3595
3596   cachel->updated = 1;
3597 }
3598
3599 static void
3600 add_glyph_cachel (struct window *w, Lisp_Object glyph)
3601 {
3602   struct glyph_cachel new_cachel;
3603
3604   xzero (new_cachel);
3605   new_cachel.glyph = Qnil;
3606
3607   update_glyph_cachel_data (w, glyph, &new_cachel);
3608   Dynarr_add (w->glyph_cachels, new_cachel);
3609 }
3610
3611 glyph_index
3612 get_glyph_cachel_index (struct window *w, Lisp_Object glyph)
3613 {
3614   int elt;
3615
3616   if (noninteractive)
3617     return 0;
3618
3619   for (elt = 0; elt < Dynarr_length (w->glyph_cachels); elt++)
3620     {
3621       struct glyph_cachel *cachel =
3622         Dynarr_atp (w->glyph_cachels, elt);
3623
3624       if (EQ (cachel->glyph, glyph) && !NILP (glyph))
3625         {
3626           update_glyph_cachel_data (w, glyph, cachel);
3627           return elt;
3628         }
3629     }
3630
3631   /* If we didn't find the glyph, add it and then return its index. */
3632   add_glyph_cachel (w, glyph);
3633   return elt;
3634 }
3635
3636 void
3637 reset_glyph_cachels (struct window *w)
3638 {
3639   Dynarr_reset (w->glyph_cachels);
3640   get_glyph_cachel_index (w, Vcontinuation_glyph);
3641   get_glyph_cachel_index (w, Vtruncation_glyph);
3642   get_glyph_cachel_index (w, Vhscroll_glyph);
3643   get_glyph_cachel_index (w, Vcontrol_arrow_glyph);
3644   get_glyph_cachel_index (w, Voctal_escape_glyph);
3645   get_glyph_cachel_index (w, Vinvisible_text_glyph);
3646 }
3647
3648 void
3649 mark_glyph_cachels_as_not_updated (struct window *w)
3650 {
3651   int elt;
3652
3653   /* We need to have a dirty flag to tell if the glyph has changed.
3654      We can check to see if each glyph variable is actually a
3655      completely different glyph, though. */
3656 #define FROB(glyph_obj, gindex)                                         \
3657   update_glyph_cachel_data (w, glyph_obj,                               \
3658                               Dynarr_atp (w->glyph_cachels, gindex))
3659
3660   FROB (Vcontinuation_glyph, CONT_GLYPH_INDEX);
3661   FROB (Vtruncation_glyph, TRUN_GLYPH_INDEX);
3662   FROB (Vhscroll_glyph, HSCROLL_GLYPH_INDEX);
3663   FROB (Vcontrol_arrow_glyph, CONTROL_GLYPH_INDEX);
3664   FROB (Voctal_escape_glyph, OCT_ESC_GLYPH_INDEX);
3665   FROB (Vinvisible_text_glyph, INVIS_GLYPH_INDEX);
3666 #undef FROB
3667
3668   for (elt = 0; elt < Dynarr_length (w->glyph_cachels); elt++)
3669     {
3670       Dynarr_atp (w->glyph_cachels, elt)->updated = 0;
3671     }
3672 }
3673
3674 /* Unset the dirty bit on all the glyph cachels that have it. */
3675 void 
3676 mark_glyph_cachels_as_clean (struct window* w)
3677 {
3678   int elt;
3679   Lisp_Object window;
3680   XSETWINDOW (window, w);
3681   for (elt = 0; elt < Dynarr_length (w->glyph_cachels); elt++)
3682     {
3683       struct glyph_cachel *cachel = Dynarr_atp (w->glyph_cachels, elt);
3684       cachel->dirty = 0;
3685       set_glyph_dirty_p (cachel->glyph, window, 0);
3686     }
3687 }
3688
3689 #ifdef MEMORY_USAGE_STATS
3690
3691 int
3692 compute_glyph_cachel_usage (glyph_cachel_dynarr *glyph_cachels,
3693                             struct overhead_stats *ovstats)
3694 {
3695   int total = 0;
3696
3697   if (glyph_cachels)
3698     total += Dynarr_memory_usage (glyph_cachels, ovstats);
3699
3700   return total;
3701 }
3702
3703 #endif /* MEMORY_USAGE_STATS */
3704
3705
3706 \f
3707 /*****************************************************************************
3708  *                     subwindow cachel functions                                    *
3709  *****************************************************************************/
3710 /* subwindows are curious in that you have to physically unmap them to
3711    not display them. It is problematic deciding what to do in
3712    redisplay. We have two caches - a per-window instance cache that
3713    keeps track of subwindows on a window, these are linked to their
3714    instantiator in the hashtable and when the instantiator goes away
3715    we want the instance to go away also. However we also have a
3716    per-frame instance cache that we use to determine if a subwindow is
3717    obscuring an area that we want to clear. We need to be able to flip
3718    through this quickly so a hashtable is not suitable hence the
3719    subwindow_cachels. The question is should we just not mark
3720    instances in the subwindow_cachels or should we try and invalidate
3721    the cache at suitable points in redisplay? If we don't invalidate
3722    the cache it will fill up with crud that will only get removed when
3723    the frame is deleted. So invalidation is good, the question is when
3724    and whether we mark as well. Go for the simple option - don't mark,
3725    MARK_SUBWINDOWS_CHANGED when a subwindow gets deleted. */
3726
3727 void
3728 mark_subwindow_cachels (subwindow_cachel_dynarr *elements)
3729 {
3730   int elt;
3731
3732   if (!elements)
3733     return;
3734
3735   for (elt = 0; elt < Dynarr_length (elements); elt++)
3736     {
3737       struct subwindow_cachel *cachel = Dynarr_atp (elements, elt);
3738       mark_object (cachel->subwindow);
3739     }
3740 }
3741
3742 static void
3743 update_subwindow_cachel_data (struct frame *f, Lisp_Object subwindow,
3744                           struct subwindow_cachel *cachel)
3745 {
3746   cachel->subwindow   = subwindow;
3747   cachel->width   = XIMAGE_INSTANCE_SUBWINDOW_WIDTH (subwindow);
3748   cachel->height   = XIMAGE_INSTANCE_SUBWINDOW_HEIGHT (subwindow);
3749   cachel->updated = 1;
3750 }
3751
3752 static void
3753 add_subwindow_cachel (struct frame *f, Lisp_Object subwindow)
3754 {
3755   struct subwindow_cachel new_cachel;
3756
3757   xzero (new_cachel);
3758   new_cachel.subwindow = Qnil;
3759   new_cachel.x=0;
3760   new_cachel.y=0;
3761   new_cachel.being_displayed=0;
3762
3763   update_subwindow_cachel_data (f, subwindow, &new_cachel);
3764   Dynarr_add (f->subwindow_cachels, new_cachel);
3765 }
3766
3767 static int
3768 get_subwindow_cachel_index (struct frame *f, Lisp_Object subwindow)
3769 {
3770   int elt;
3771
3772   if (noninteractive)
3773     return 0;
3774
3775   for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
3776     {
3777       struct subwindow_cachel *cachel =
3778         Dynarr_atp (f->subwindow_cachels, elt);
3779
3780       if (EQ (cachel->subwindow, subwindow) && !NILP (subwindow))
3781         {
3782           if (!cachel->updated)
3783             update_subwindow_cachel_data (f, subwindow, cachel);
3784           return elt;
3785         }
3786     }
3787
3788   /* If we didn't find the glyph, add it and then return its index. */
3789   add_subwindow_cachel (f, subwindow);
3790   return elt;
3791 }
3792
3793 static void
3794 update_subwindow_cachel (Lisp_Object subwindow)
3795 {
3796   struct frame* f;
3797   int elt;
3798
3799   if (NILP (subwindow))
3800     return;
3801
3802   f = XFRAME ( XIMAGE_INSTANCE_SUBWINDOW_FRAME (subwindow));
3803
3804   for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
3805     {
3806       struct subwindow_cachel *cachel =
3807         Dynarr_atp (f->subwindow_cachels, elt);
3808       
3809       if (EQ (cachel->subwindow, subwindow) && !NILP (subwindow))
3810         {
3811           update_subwindow_cachel_data (f, subwindow, cachel);
3812         }
3813     }
3814 }
3815
3816 /* redisplay in general assumes that drawing something will erase
3817    what was there before. unfortunately this does not apply to
3818    subwindows that need to be specifically unmapped in order to
3819    disappear. we take a brute force approach - on the basis that its
3820    cheap - and unmap all subwindows in a display line */
3821 void
3822 reset_subwindow_cachels (struct frame *f)
3823 {
3824   int elt;
3825   for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
3826     {
3827       struct subwindow_cachel *cachel =
3828         Dynarr_atp (f->subwindow_cachels, elt);
3829
3830       if (!NILP (cachel->subwindow) && cachel->being_displayed)
3831         {
3832           cachel->updated = 1;
3833           /* #### This is not optimal as update_subwindow will search
3834              the cachels for ourselves as well. We could easily optimize. */
3835           unmap_subwindow (cachel->subwindow);
3836         }
3837     }
3838   Dynarr_reset (f->subwindow_cachels);
3839 }
3840
3841 void
3842 mark_subwindow_cachels_as_not_updated (struct frame *f)
3843 {
3844   int elt;
3845
3846   for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
3847     Dynarr_atp (f->subwindow_cachels, elt)->updated = 0;
3848 }
3849
3850
3851
3852 /*****************************************************************************
3853  *                              subwindow exposure ignorance                    *
3854  *****************************************************************************/
3855 /* when we unmap subwindows the associated window system will generate
3856    expose events. This we do not want as redisplay already copes with
3857    the repainting necessary. Worse, we can get in an endless cycle of
3858    redisplay if we are not careful. Thus we keep a per-frame list of
3859    expose events that are going to come and ignore them as
3860    required. */
3861
3862 struct expose_ignore_blocktype
3863 {
3864   Blocktype_declare (struct expose_ignore);
3865 } *the_expose_ignore_blocktype;
3866
3867 int
3868 check_for_ignored_expose (struct frame* f, int x, int y, int width, int height)
3869 {
3870   struct expose_ignore *ei, *prev;
3871   /* the ignore list is FIFO so we should generally get a match with
3872      the first element in the list */
3873   for (ei = f->subwindow_exposures, prev = 0; ei; ei = ei->next)
3874     {
3875       /* Checking for exact matches just isn't good enough as we
3876          mighte get exposures for partially obscure subwindows, thus
3877          we have to check for overlaps. Being conservative we will
3878          check for exposures wholly contained by the subwindow, this
3879          might give us what we want.*/
3880       if (ei->x <= x && ei->y <= y 
3881           && ei->x + ei->width >= x + width
3882           && ei->y + ei->height >= y + height)
3883         {
3884 #ifdef DEBUG_WIDGETS
3885           stderr_out ("ignored %d+%d, %dx%d for exposure %d+%d, %dx%d\n",
3886                       x, y, width, height, ei->x, ei->y, ei->width, ei->height);
3887 #endif
3888           if (!prev)
3889             f->subwindow_exposures = ei->next;
3890           else
3891             prev->next = ei->next;
3892           
3893           if (ei == f->subwindow_exposures_tail)
3894             f->subwindow_exposures_tail = prev;
3895
3896           Blocktype_free (the_expose_ignore_blocktype, ei);
3897           return 1;
3898         }
3899       prev = ei;
3900     }
3901   return 0;
3902 }
3903
3904 static void
3905 register_ignored_expose (struct frame* f, int x, int y, int width, int height)
3906 {
3907   if (!hold_ignored_expose_registration)
3908     {
3909       struct expose_ignore *ei;
3910       
3911       ei = Blocktype_alloc (the_expose_ignore_blocktype);
3912       
3913       ei->next = NULL;
3914       ei->x = x;
3915       ei->y = y;
3916       ei->width = width;
3917       ei->height = height;
3918       
3919       /* we have to add the exposure to the end of the list, since we
3920          want to check the oldest events first. for speed we keep a record
3921          of the end so that we can add right to it. */
3922       if (f->subwindow_exposures_tail)
3923         {
3924           f->subwindow_exposures_tail->next = ei;
3925         }
3926       if (!f->subwindow_exposures)
3927         {
3928           f->subwindow_exposures = ei;
3929         }
3930       f->subwindow_exposures_tail = ei;
3931     }
3932 }
3933
3934 /****************************************************************************
3935  find_matching_subwindow
3936
3937  See if there is a subwindow that completely encloses the requested
3938  area.
3939  ****************************************************************************/
3940 int find_matching_subwindow (struct frame* f, int x, int y, int width, int height)
3941 {
3942   int elt;
3943
3944   for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
3945     {
3946       struct subwindow_cachel *cachel =
3947         Dynarr_atp (f->subwindow_cachels, elt);
3948
3949       if (cachel->being_displayed
3950           &&
3951           cachel->x <= x && cachel->y <= y
3952           && 
3953           cachel->x + cachel->width >= x + width
3954           &&
3955           cachel->y + cachel->height >= y + height)
3956         {
3957           return 1;
3958         }
3959     }
3960   return 0;
3961 }
3962
3963 \f
3964 /*****************************************************************************
3965  *                              subwindow functions                          *
3966  *****************************************************************************/
3967
3968 /* update the displayed characteristics of a subwindow */
3969 static void
3970 update_subwindow (Lisp_Object subwindow)
3971 {
3972   struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
3973
3974   if (!IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET
3975       ||
3976       NILP (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii)))
3977     return;
3978
3979   MAYBE_DEVMETH (XDEVICE (ii->device), update_subwindow, (ii));
3980 }
3981
3982 void
3983 update_frame_subwindows (struct frame *f)
3984 {
3985   int elt;
3986
3987   if (f->subwindows_changed || f->subwindows_state_changed || f->faces_changed)
3988     for (elt = 0; elt < Dynarr_length (f->subwindow_cachels); elt++)
3989       {
3990         struct subwindow_cachel *cachel =
3991           Dynarr_atp (f->subwindow_cachels, elt);
3992         
3993         if (cachel->being_displayed)
3994           {
3995             update_subwindow (cachel->subwindow);
3996           }
3997       }
3998 }
3999
4000 /* remove a subwindow from its frame */
4001 void unmap_subwindow (Lisp_Object subwindow)
4002 {
4003   struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
4004   int elt;
4005   struct subwindow_cachel* cachel;
4006   struct frame* f;
4007
4008   if (!(IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET
4009         ||
4010         IMAGE_INSTANCE_TYPE (ii) == IMAGE_SUBWINDOW)
4011       ||
4012       NILP (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii)))
4013     return;
4014 #ifdef DEBUG_WIDGETS
4015   stderr_out ("unmapping subwindow %d\n", IMAGE_INSTANCE_SUBWINDOW_ID (ii));
4016 #endif
4017   f = XFRAME (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii));
4018   elt = get_subwindow_cachel_index (f, subwindow);
4019   cachel = Dynarr_atp (f->subwindow_cachels, elt);
4020
4021   /* make sure we don't get expose events */
4022   register_ignored_expose (f, cachel->x, cachel->y, cachel->width, cachel->height);
4023   cachel->x = -1;
4024   cachel->y = -1;
4025   cachel->being_displayed = 0;
4026   IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 0;
4027
4028   MAYBE_DEVMETH (XDEVICE (ii->device), unmap_subwindow, (ii));
4029 }
4030
4031 /* show a subwindow in its frame */
4032 void map_subwindow (Lisp_Object subwindow, int x, int y,
4033                     struct display_glyph_area *dga)
4034 {
4035   struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (subwindow);
4036   int elt; 
4037   struct subwindow_cachel* cachel;
4038   struct frame* f;
4039
4040   if (!(IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET
4041         ||
4042         IMAGE_INSTANCE_TYPE (ii) == IMAGE_SUBWINDOW)
4043       ||
4044       NILP (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii)))
4045     return;
4046
4047 #ifdef DEBUG_WIDGETS
4048   stderr_out ("mapping subwindow %d, %dx%d@%d+%d\n",
4049               IMAGE_INSTANCE_SUBWINDOW_ID (ii),
4050               dga->width, dga->height, x, y);
4051 #endif
4052   f = XFRAME (IMAGE_INSTANCE_SUBWINDOW_FRAME (ii));
4053   IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 1;
4054   elt = get_subwindow_cachel_index (f, subwindow);
4055   cachel = Dynarr_atp (f->subwindow_cachels, elt);
4056   cachel->x = x;
4057   cachel->y = y;
4058   cachel->width = dga->width;
4059   cachel->height = dga->height;
4060   cachel->being_displayed = 1;
4061
4062   MAYBE_DEVMETH (XDEVICE (ii->device), map_subwindow, (ii, x, y, dga));
4063 }
4064
4065 static int
4066 subwindow_possible_dest_types (void)
4067 {
4068   return IMAGE_SUBWINDOW_MASK;
4069 }
4070
4071 /* Partially instantiate a subwindow. */
4072 void
4073 subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
4074                        Lisp_Object pointer_fg, Lisp_Object pointer_bg,
4075                        int dest_mask, Lisp_Object domain)
4076 {
4077   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
4078   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
4079   Lisp_Object frame = FW_FRAME (domain);
4080   Lisp_Object width = find_keyword_in_vector (instantiator, Q_pixel_width);
4081   Lisp_Object height = find_keyword_in_vector (instantiator, Q_pixel_height);
4082
4083   if (NILP (frame))
4084     signal_simple_error ("No selected frame", device);
4085   
4086   if (!(dest_mask & IMAGE_SUBWINDOW_MASK))
4087     incompatible_image_types (instantiator, dest_mask, IMAGE_SUBWINDOW_MASK);
4088
4089   ii->data = 0;
4090   IMAGE_INSTANCE_SUBWINDOW_ID (ii) = 0;
4091   IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 0;
4092   IMAGE_INSTANCE_SUBWINDOW_FRAME (ii) = frame;
4093
4094   /* this stuff may get overidden by the widget code */
4095   if (NILP (width))
4096     IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = 20;
4097   else
4098     {
4099       int w = 1;
4100       CHECK_INT (width);
4101       if (XINT (width) > 1)
4102         w = XINT (width);
4103       IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = w;
4104     }
4105   if (NILP (height))
4106     IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = 20;
4107   else
4108     {
4109       int h = 1;
4110       CHECK_INT (height);
4111       if (XINT (height) > 1)
4112         h = XINT (height);
4113       IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = h;
4114     }
4115 }
4116
4117 DEFUN ("subwindowp", Fsubwindowp, 1, 1, 0, /*
4118 Return non-nil if OBJECT is a subwindow.
4119 */
4120        (object))
4121 {
4122   CHECK_IMAGE_INSTANCE (object);
4123   return (XIMAGE_INSTANCE_TYPE (object) == IMAGE_SUBWINDOW) ? Qt : Qnil;
4124 }
4125
4126 DEFUN ("image-instance-subwindow-id", Fimage_instance_subwindow_id, 1, 1, 0, /*
4127 Return the window id of SUBWINDOW as a number.
4128 */
4129        (subwindow))
4130 {
4131   CHECK_SUBWINDOW_IMAGE_INSTANCE (subwindow);
4132   return make_int ((int) XIMAGE_INSTANCE_SUBWINDOW_ID (subwindow));
4133 }
4134
4135 DEFUN ("resize-subwindow", Fresize_subwindow, 1, 3, 0, /*
4136 Resize SUBWINDOW to WIDTH x HEIGHT.
4137 If a value is nil that parameter is not changed.
4138 */
4139        (subwindow, width, height))
4140 {
4141   int neww, newh;
4142
4143   CHECK_SUBWINDOW_IMAGE_INSTANCE (subwindow);
4144
4145   if (NILP (width))
4146     neww = XIMAGE_INSTANCE_SUBWINDOW_WIDTH (subwindow);
4147   else
4148     neww = XINT (width);
4149
4150   if (NILP (height))
4151     newh = XIMAGE_INSTANCE_SUBWINDOW_HEIGHT (subwindow);
4152   else
4153     newh = XINT (height);
4154
4155   
4156   MAYBE_DEVMETH (XDEVICE (XIMAGE_INSTANCE_DEVICE (subwindow)), 
4157                  resize_subwindow, (XIMAGE_INSTANCE (subwindow), neww, newh));
4158
4159   XIMAGE_INSTANCE_SUBWINDOW_HEIGHT (subwindow) = newh;
4160   XIMAGE_INSTANCE_SUBWINDOW_WIDTH (subwindow) = neww;
4161
4162   /* need to update the cachels as redisplay will not do this */
4163   update_subwindow_cachel (subwindow);
4164
4165   return subwindow;
4166 }
4167
4168 DEFUN ("force-subwindow-map", Fforce_subwindow_map, 1, 1, 0, /*
4169 Generate a Map event for SUBWINDOW.
4170 */
4171        (subwindow))
4172 {
4173   CHECK_SUBWINDOW_IMAGE_INSTANCE (subwindow);
4174 #if 0
4175   map_subwindow (subwindow, 0, 0);
4176 #endif
4177   return subwindow;
4178 }
4179
4180 \f
4181 /*****************************************************************************
4182  *                              display tables                               *
4183  *****************************************************************************/
4184
4185 /* Get the display tables for use currently on window W with face
4186    FACE.  #### This will have to be redone.  */
4187
4188 void
4189 get_display_tables (struct window *w, face_index findex,
4190                     Lisp_Object *face_table, Lisp_Object *window_table)
4191 {
4192   Lisp_Object tem;
4193   tem = WINDOW_FACE_CACHEL_DISPLAY_TABLE (w, findex);
4194   if (UNBOUNDP (tem))
4195     tem = Qnil;
4196   if (!LISTP (tem))
4197     tem = noseeum_cons (tem, Qnil);
4198   *face_table = tem;
4199   tem = w->display_table;
4200   if (UNBOUNDP (tem))
4201     tem = Qnil;
4202   if (!LISTP (tem))
4203     tem = noseeum_cons (tem, Qnil);
4204   *window_table = tem;
4205 }
4206
4207 Lisp_Object
4208 display_table_entry (Emchar ch, Lisp_Object face_table,
4209                      Lisp_Object window_table)
4210 {
4211   Lisp_Object tail;
4212
4213   /* Loop over FACE_TABLE, and then over WINDOW_TABLE. */
4214   for (tail = face_table; 1; tail = XCDR (tail))
4215     {
4216       Lisp_Object table;
4217       if (NILP (tail))
4218         {
4219           if (!NILP (window_table))
4220             {
4221               tail = window_table;
4222               window_table = Qnil;
4223             }
4224           else
4225             return Qnil;
4226         }
4227       table = XCAR (tail);
4228
4229       if (VECTORP (table))
4230         {
4231           if (ch < XVECTOR_LENGTH (table) && !NILP (XVECTOR_DATA (table)[ch]))
4232             return XVECTOR_DATA (table)[ch];
4233           else
4234             continue;
4235         }
4236       else if (CHAR_TABLEP (table)
4237                && XCHAR_TABLE_TYPE (table) == CHAR_TABLE_TYPE_CHAR)
4238         {
4239           return get_char_table (ch, XCHAR_TABLE (table));
4240         }
4241       else if (CHAR_TABLEP (table)
4242                && XCHAR_TABLE_TYPE (table) == CHAR_TABLE_TYPE_GENERIC)
4243         {
4244           Lisp_Object gotit = get_char_table (ch, XCHAR_TABLE (table));
4245           if (!NILP (gotit))
4246             return gotit;
4247           else
4248             continue;
4249         }
4250       else if (RANGE_TABLEP (table))
4251         {
4252           Lisp_Object gotit = Fget_range_table (make_char (ch), table, Qnil);
4253           if (!NILP (gotit))
4254             return gotit;
4255           else
4256             continue;
4257         }
4258       else
4259         abort ();
4260     }
4261 }
4262
4263 /*****************************************************************************
4264  *                              timeouts for animated glyphs                      *
4265  *****************************************************************************/
4266 static Lisp_Object Qglyph_animated_timeout_handler;
4267
4268 DEFUN ("glyph-animated-timeout-handler", Fglyph_animated_timeout_handler, 1, 1, 0, /*
4269 Callback function for updating animated images.
4270 Don't use this.
4271 */
4272        (arg))
4273 {
4274   CHECK_WEAK_LIST (arg);
4275
4276   if (!NILP (XWEAK_LIST_LIST (arg)) && !NILP (XCAR (XWEAK_LIST_LIST (arg))))
4277     {
4278       Lisp_Object value = XCAR (XWEAK_LIST_LIST (arg));
4279       
4280       if (IMAGE_INSTANCEP (value))
4281         {
4282           struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (value);
4283
4284           if (COLOR_PIXMAP_IMAGE_INSTANCEP (value)
4285               &&
4286               IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii) > 1
4287               &&
4288               !disable_animated_pixmaps)
4289             {
4290               /* Increment the index of the image slice we are currently
4291                  viewing. */
4292               IMAGE_INSTANCE_PIXMAP_SLICE (ii) =
4293                 (IMAGE_INSTANCE_PIXMAP_SLICE (ii) + 1)
4294                 % IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii);
4295               /* We might need to kick redisplay at this point - but we
4296                  also might not. */
4297               MARK_DEVICE_FRAMES_GLYPHS_CHANGED 
4298                 (XDEVICE (IMAGE_INSTANCE_DEVICE (ii)));
4299               IMAGE_INSTANCE_DIRTYP (ii) = 1;
4300             }
4301         }
4302     }
4303   return Qnil;
4304 }
4305
4306 Lisp_Object add_glyph_animated_timeout (EMACS_INT tickms, Lisp_Object image)
4307 {
4308   Lisp_Object ret = Qnil;
4309
4310   if (tickms > 0 && IMAGE_INSTANCEP (image))
4311     {
4312       double ms = ((double)tickms) / 1000.0;
4313       struct gcpro gcpro1;
4314       Lisp_Object holder = make_weak_list (WEAK_LIST_SIMPLE);
4315
4316       GCPRO1 (holder);
4317       XWEAK_LIST_LIST (holder) = Fcons (image, Qnil);
4318
4319       ret = Fadd_timeout (make_float (ms),
4320                           Qglyph_animated_timeout_handler,
4321                           holder, make_float (ms));
4322
4323       UNGCPRO;
4324     }
4325   return ret;
4326 }
4327
4328 void disable_glyph_animated_timeout (int i)
4329 {
4330   Lisp_Object id;
4331   XSETINT (id, i);
4332
4333   Fdisable_timeout (id);
4334 }
4335
4336 \f
4337 /*****************************************************************************
4338  *                              initialization                               *
4339  *****************************************************************************/
4340
4341 void
4342 syms_of_glyphs (void)
4343 {
4344   /* image instantiators */
4345
4346   DEFSUBR (Fimage_instantiator_format_list);
4347   DEFSUBR (Fvalid_image_instantiator_format_p);
4348   DEFSUBR (Fset_console_type_image_conversion_list);
4349   DEFSUBR (Fconsole_type_image_conversion_list);
4350
4351   defkeyword (&Q_file, ":file");
4352   defkeyword (&Q_data, ":data");
4353   defkeyword (&Q_face, ":face");
4354   defkeyword (&Q_pixel_height, ":pixel-height");
4355   defkeyword (&Q_pixel_width, ":pixel-width");
4356
4357 #ifdef HAVE_XPM
4358   defkeyword (&Q_color_symbols, ":color-symbols");
4359 #endif
4360 #ifdef HAVE_WINDOW_SYSTEM
4361   defkeyword (&Q_mask_file, ":mask-file");
4362   defkeyword (&Q_mask_data, ":mask-data");
4363   defkeyword (&Q_hotspot_x, ":hotspot-x");
4364   defkeyword (&Q_hotspot_y, ":hotspot-y");
4365   defkeyword (&Q_foreground, ":foreground");
4366   defkeyword (&Q_background, ":background");
4367 #endif
4368   /* image specifiers */
4369
4370   DEFSUBR (Fimage_specifier_p);
4371   /* Qimage in general.c */
4372
4373   /* image instances */
4374
4375   defsymbol (&Qimage_instancep, "image-instance-p");
4376
4377   defsymbol (&Qnothing_image_instance_p, "nothing-image-instance-p");
4378   defsymbol (&Qtext_image_instance_p, "text-image-instance-p");
4379   defsymbol (&Qmono_pixmap_image_instance_p, "mono-pixmap-image-instance-p");
4380   defsymbol (&Qcolor_pixmap_image_instance_p, "color-pixmap-image-instance-p");
4381   defsymbol (&Qpointer_image_instance_p, "pointer-image-instance-p");
4382   defsymbol (&Qwidget_image_instance_p, "widget-image-instance-p");
4383   defsymbol (&Qsubwindow_image_instance_p, "subwindow-image-instance-p");
4384   defsymbol (&Qlayout_image_instance_p, "layout-image-instance-p");
4385
4386   DEFSUBR (Fmake_image_instance);
4387   DEFSUBR (Fimage_instance_p);
4388   DEFSUBR (Fimage_instance_type);
4389   DEFSUBR (Fvalid_image_instance_type_p);
4390   DEFSUBR (Fimage_instance_type_list);
4391   DEFSUBR (Fimage_instance_name);
4392   DEFSUBR (Fimage_instance_string);
4393   DEFSUBR (Fimage_instance_file_name);
4394   DEFSUBR (Fimage_instance_mask_file_name);
4395   DEFSUBR (Fimage_instance_depth);
4396   DEFSUBR (Fimage_instance_height);
4397   DEFSUBR (Fimage_instance_width);
4398   DEFSUBR (Fimage_instance_hotspot_x);
4399   DEFSUBR (Fimage_instance_hotspot_y);
4400   DEFSUBR (Fimage_instance_foreground);
4401   DEFSUBR (Fimage_instance_background);
4402   DEFSUBR (Fimage_instance_property);
4403   DEFSUBR (Fset_image_instance_property);
4404   DEFSUBR (Fcolorize_image_instance);
4405   /* subwindows */
4406   DEFSUBR (Fsubwindowp);
4407   DEFSUBR (Fimage_instance_subwindow_id);
4408   DEFSUBR (Fresize_subwindow);
4409   DEFSUBR (Fforce_subwindow_map);
4410
4411   /* Qnothing defined as part of the "nothing" image-instantiator
4412      type. */
4413   /* Qtext defined in general.c */
4414   defsymbol (&Qmono_pixmap, "mono-pixmap");
4415   defsymbol (&Qcolor_pixmap, "color-pixmap");
4416   /* Qpointer defined in general.c */
4417
4418   /* glyphs */
4419
4420   defsymbol (&Qglyphp, "glyphp");
4421   defsymbol (&Qcontrib_p, "contrib-p");
4422   defsymbol (&Qbaseline, "baseline");
4423
4424   defsymbol (&Qbuffer_glyph_p, "buffer-glyph-p");
4425   defsymbol (&Qpointer_glyph_p, "pointer-glyph-p");
4426   defsymbol (&Qicon_glyph_p, "icon-glyph-p");
4427
4428   defsymbol (&Qconst_glyph_variable, "const-glyph-variable");
4429
4430   DEFSUBR (Fglyph_type);
4431   DEFSUBR (Fvalid_glyph_type_p);
4432   DEFSUBR (Fglyph_type_list);
4433   DEFSUBR (Fglyphp);
4434   DEFSUBR (Fmake_glyph_internal);
4435   DEFSUBR (Fglyph_width);
4436   DEFSUBR (Fglyph_ascent);
4437   DEFSUBR (Fglyph_descent);
4438   DEFSUBR (Fglyph_height);
4439
4440   /* Qbuffer defined in general.c. */
4441   /* Qpointer defined above */
4442
4443   /* Unfortunately, timeout handlers must be lisp functions. This is
4444      for animated glyphs. */
4445   defsymbol (&Qglyph_animated_timeout_handler,
4446              "glyph-animated-timeout-handler");
4447   DEFSUBR (Fglyph_animated_timeout_handler);
4448
4449   /* Errors */
4450   deferror (&Qimage_conversion_error,
4451             "image-conversion-error",
4452             "image-conversion error", Qio_error);
4453
4454 }
4455
4456 static const struct lrecord_description image_specifier_description[] = {
4457   { XD_LISP_OBJECT, specifier_data_offset + offsetof(struct image_specifier, attachee), 2 },
4458   { XD_END }
4459 };
4460
4461 void
4462 specifier_type_create_image (void)
4463 {
4464   /* image specifiers */
4465
4466   INITIALIZE_SPECIFIER_TYPE_WITH_DATA (image, "image", "imagep");
4467
4468   SPECIFIER_HAS_METHOD (image, create);
4469   SPECIFIER_HAS_METHOD (image, mark);
4470   SPECIFIER_HAS_METHOD (image, instantiate);
4471   SPECIFIER_HAS_METHOD (image, validate);
4472   SPECIFIER_HAS_METHOD (image, after_change);
4473   SPECIFIER_HAS_METHOD (image, going_to_add);
4474 }
4475
4476 void
4477 reinit_specifier_type_create_image (void)
4478 {
4479   REINITIALIZE_SPECIFIER_TYPE (image);
4480 }
4481
4482
4483 static const struct lrecord_description iike_description_1[] = {
4484   { XD_LISP_OBJECT, offsetof(ii_keyword_entry, keyword), 1 },
4485   { XD_END }
4486 };
4487
4488 static const struct struct_description iike_description = {
4489   sizeof(ii_keyword_entry),
4490   iike_description_1
4491 };
4492
4493 static const struct lrecord_description iiked_description_1[] = {
4494   XD_DYNARR_DESC(ii_keyword_entry_dynarr, &iike_description),
4495   { XD_END }
4496 };
4497
4498 static const struct struct_description iiked_description = {
4499   sizeof(ii_keyword_entry_dynarr),
4500   iiked_description_1
4501 };
4502
4503 static const struct lrecord_description iife_description_1[] = {
4504   { XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, symbol), 2 },
4505   { XD_STRUCT_PTR,  offsetof(image_instantiator_format_entry, meths),  1, &iim_description },
4506   { XD_END }
4507 };
4508
4509 static const struct struct_description iife_description = {
4510   sizeof(image_instantiator_format_entry),
4511   iife_description_1
4512 };
4513
4514 static const struct lrecord_description iifed_description_1[] = {
4515   XD_DYNARR_DESC(image_instantiator_format_entry_dynarr, &iife_description),
4516   { XD_END }
4517 };
4518
4519 static const struct struct_description iifed_description = {
4520   sizeof(image_instantiator_format_entry_dynarr),
4521   iifed_description_1
4522 };
4523
4524 static const struct lrecord_description iim_description_1[] = {
4525   { XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, symbol), 2 },
4526   { XD_STRUCT_PTR,  offsetof(struct image_instantiator_methods, keywords), 1, &iiked_description },
4527   { XD_STRUCT_PTR,  offsetof(struct image_instantiator_methods, consoles), 1, &cted_description },
4528   { XD_END }
4529 };
4530
4531 const struct struct_description iim_description = {
4532   sizeof(struct image_instantiator_methods),
4533   iim_description_1
4534 };
4535
4536 void
4537 image_instantiator_format_create (void)
4538 {
4539   /* image instantiators */
4540
4541   the_image_instantiator_format_entry_dynarr =
4542     Dynarr_new (image_instantiator_format_entry);
4543
4544   Vimage_instantiator_format_list = Qnil;
4545   staticpro (&Vimage_instantiator_format_list);
4546
4547   dumpstruct (&the_image_instantiator_format_entry_dynarr, &iifed_description);
4548
4549   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (nothing, "nothing");
4550
4551   IIFORMAT_HAS_METHOD (nothing, possible_dest_types);
4552   IIFORMAT_HAS_METHOD (nothing, instantiate);
4553
4554   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (inherit, "inherit");
4555
4556   IIFORMAT_HAS_METHOD (inherit, validate);
4557   IIFORMAT_HAS_METHOD (inherit, normalize);
4558   IIFORMAT_HAS_METHOD (inherit, possible_dest_types);
4559   IIFORMAT_HAS_METHOD (inherit, instantiate);
4560
4561   IIFORMAT_VALID_KEYWORD (inherit, Q_face, check_valid_face);
4562
4563   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (string, "string");
4564
4565   IIFORMAT_HAS_METHOD (string, validate);
4566   IIFORMAT_HAS_METHOD (string, possible_dest_types);
4567   IIFORMAT_HAS_METHOD (string, instantiate);
4568
4569   IIFORMAT_VALID_KEYWORD (string, Q_data, check_valid_string);
4570   /* Do this so we can set strings. */
4571   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (text, "text");
4572   IIFORMAT_HAS_METHOD (text, set_property);
4573
4574   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (formatted_string, "formatted-string");
4575
4576   IIFORMAT_HAS_METHOD (formatted_string, validate);
4577   IIFORMAT_HAS_METHOD (formatted_string, possible_dest_types);
4578   IIFORMAT_HAS_METHOD (formatted_string, instantiate);
4579   IIFORMAT_VALID_KEYWORD (formatted_string, Q_data, check_valid_string);
4580
4581   /* subwindows */
4582   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (subwindow, "subwindow");
4583   IIFORMAT_HAS_METHOD (subwindow, possible_dest_types);
4584   IIFORMAT_HAS_METHOD (subwindow, instantiate);
4585   IIFORMAT_VALID_KEYWORD (subwindow, Q_pixel_width, check_valid_int);
4586   IIFORMAT_VALID_KEYWORD (subwindow, Q_pixel_height, check_valid_int);
4587
4588 #ifdef HAVE_WINDOW_SYSTEM
4589   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (xbm, "xbm");
4590
4591   IIFORMAT_HAS_METHOD (xbm, validate);
4592   IIFORMAT_HAS_METHOD (xbm, normalize);
4593   IIFORMAT_HAS_METHOD (xbm, possible_dest_types);
4594
4595   IIFORMAT_VALID_KEYWORD (xbm, Q_data, check_valid_xbm_inline);
4596   IIFORMAT_VALID_KEYWORD (xbm, Q_file, check_valid_string);
4597   IIFORMAT_VALID_KEYWORD (xbm, Q_mask_data, check_valid_xbm_inline);
4598   IIFORMAT_VALID_KEYWORD (xbm, Q_mask_file, check_valid_string);
4599   IIFORMAT_VALID_KEYWORD (xbm, Q_hotspot_x, check_valid_int);
4600   IIFORMAT_VALID_KEYWORD (xbm, Q_hotspot_y, check_valid_int);
4601   IIFORMAT_VALID_KEYWORD (xbm, Q_foreground, check_valid_string);
4602   IIFORMAT_VALID_KEYWORD (xbm, Q_background, check_valid_string);
4603 #endif /* HAVE_WINDOW_SYSTEM */
4604
4605 #ifdef HAVE_XFACE
4606   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (xface, "xface");
4607
4608   IIFORMAT_HAS_METHOD (xface, validate);
4609   IIFORMAT_HAS_METHOD (xface, normalize);
4610   IIFORMAT_HAS_METHOD (xface, possible_dest_types);
4611
4612   IIFORMAT_VALID_KEYWORD (xface, Q_data, check_valid_string);
4613   IIFORMAT_VALID_KEYWORD (xface, Q_file, check_valid_string);
4614   IIFORMAT_VALID_KEYWORD (xface, Q_hotspot_x, check_valid_int);
4615   IIFORMAT_VALID_KEYWORD (xface, Q_hotspot_y, check_valid_int);
4616   IIFORMAT_VALID_KEYWORD (xface, Q_foreground, check_valid_string);
4617   IIFORMAT_VALID_KEYWORD (xface, Q_background, check_valid_string);
4618 #endif
4619
4620 #ifdef HAVE_XPM
4621   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (xpm, "xpm");
4622
4623   IIFORMAT_HAS_METHOD (xpm, validate);
4624   IIFORMAT_HAS_METHOD (xpm, normalize);
4625   IIFORMAT_HAS_METHOD (xpm, possible_dest_types);
4626
4627   IIFORMAT_VALID_KEYWORD (xpm, Q_data, check_valid_string);
4628   IIFORMAT_VALID_KEYWORD (xpm, Q_file, check_valid_string);
4629   IIFORMAT_VALID_KEYWORD (xpm, Q_color_symbols, check_valid_xpm_color_symbols);
4630 #endif /* HAVE_XPM */
4631 }
4632
4633 void
4634 reinit_vars_of_glyphs (void)
4635 {
4636   the_expose_ignore_blocktype =
4637     Blocktype_new (struct expose_ignore_blocktype);
4638
4639   hold_ignored_expose_registration = 0;
4640 }
4641
4642
4643 void
4644 vars_of_glyphs (void)
4645 {
4646   reinit_vars_of_glyphs ();
4647
4648   Vthe_nothing_vector = vector1 (Qnothing);
4649   staticpro (&Vthe_nothing_vector);
4650
4651   /* image instances */
4652
4653   Vimage_instance_type_list = Fcons (Qnothing, 
4654                                      list6 (Qtext, Qmono_pixmap, Qcolor_pixmap, 
4655                                             Qpointer, Qsubwindow, Qwidget));
4656   staticpro (&Vimage_instance_type_list);
4657
4658   /* glyphs */
4659
4660   Vglyph_type_list = list3 (Qbuffer, Qpointer, Qicon);
4661   staticpro (&Vglyph_type_list);
4662
4663   /* The octal-escape glyph, control-arrow-glyph and
4664      invisible-text-glyph are completely initialized in glyphs.el */
4665
4666   DEFVAR_LISP ("octal-escape-glyph", &Voctal_escape_glyph /*
4667 What to prefix character codes displayed in octal with.
4668 */);
4669   Voctal_escape_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
4670
4671   DEFVAR_LISP ("control-arrow-glyph", &Vcontrol_arrow_glyph /*
4672 What to use as an arrow for control characters.
4673 */);
4674   Vcontrol_arrow_glyph = allocate_glyph (GLYPH_BUFFER,
4675                                          redisplay_glyph_changed);
4676
4677   DEFVAR_LISP ("invisible-text-glyph", &Vinvisible_text_glyph /*
4678 What to use to indicate the presence of invisible text.
4679 This is the glyph that is displayed when an ellipsis is called for
4680 \(see `selective-display-ellipses' and `buffer-invisibility-spec').
4681 Normally this is three dots ("...").
4682 */);
4683   Vinvisible_text_glyph = allocate_glyph (GLYPH_BUFFER,
4684                                           redisplay_glyph_changed);
4685
4686   /* Partially initialized in glyphs.el */
4687   DEFVAR_LISP ("hscroll-glyph", &Vhscroll_glyph /*
4688 What to display at the beginning of horizontally scrolled lines.
4689 */);
4690   Vhscroll_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
4691 #ifdef HAVE_WINDOW_SYSTEM
4692   Fprovide (Qxbm);
4693 #endif
4694 #ifdef HAVE_XPM
4695   Fprovide (Qxpm);
4696
4697   DEFVAR_LISP ("xpm-color-symbols", &Vxpm_color_symbols /*
4698 Definitions of logical color-names used when reading XPM files.
4699 Elements of this list should be of the form (COLOR-NAME FORM-TO-EVALUATE).
4700 The COLOR-NAME should be a string, which is the name of the color to define;
4701 the FORM should evaluate to a `color' specifier object, or a string to be
4702 passed to `make-color-instance'.  If a loaded XPM file references a symbolic
4703 color called COLOR-NAME, it will display as the computed color instead.
4704
4705 The default value of this variable defines the logical color names
4706 \"foreground\" and \"background\" to be the colors of the `default' face.
4707 */ );
4708   Vxpm_color_symbols = Qnil; /* initialized in x-faces.el */
4709 #endif /* HAVE_XPM */
4710 #ifdef HAVE_XFACE
4711   Fprovide (Qxface);
4712 #endif
4713
4714   DEFVAR_BOOL ("disable-animated-pixmaps", &disable_animated_pixmaps /*
4715 Whether animated pixmaps should be animated.
4716 Default is t.
4717 */);
4718   disable_animated_pixmaps = 0;
4719 }
4720
4721 void
4722 specifier_vars_of_glyphs (void)
4723 {
4724   /* #### Can we GC here? The set_specifier_* calls definitely need */
4725   /* protection. */
4726   /* display tables */
4727
4728   DEFVAR_SPECIFIER ("current-display-table", &Vcurrent_display_table /*
4729 *The display table currently in use.
4730 This is a specifier; use `set-specifier' to change it.
4731 The display table is a vector created with `make-display-table'.
4732 The 256 elements control how to display each possible text character.
4733 Each value should be a string, a glyph, a vector or nil.
4734 If a value is a vector it must be composed only of strings and glyphs.
4735 nil means display the character in the default fashion.
4736 Faces can have their own, overriding display table.
4737 */ );
4738   Vcurrent_display_table = Fmake_specifier (Qdisplay_table);
4739   set_specifier_fallback (Vcurrent_display_table,
4740                           list1 (Fcons (Qnil, Qnil)));
4741   set_specifier_caching (Vcurrent_display_table,
4742                          slot_offset (struct window,
4743                                       display_table),
4744                          some_window_value_changed,
4745                          0, 0);
4746 }
4747
4748 void
4749 complex_vars_of_glyphs (void)
4750 {
4751   /* Partially initialized in glyphs-x.c, glyphs.el */
4752   DEFVAR_LISP ("truncation-glyph", &Vtruncation_glyph /*
4753 What to display at the end of truncated lines.
4754 */ );
4755   Vtruncation_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
4756
4757   /* Partially initialized in glyphs-x.c, glyphs.el */
4758   DEFVAR_LISP ("continuation-glyph", &Vcontinuation_glyph /*
4759 What to display at the end of wrapped lines.
4760 */ );
4761   Vcontinuation_glyph = allocate_glyph (GLYPH_BUFFER, redisplay_glyph_changed);
4762
4763   /* Partially initialized in glyphs-x.c, glyphs.el */
4764   DEFVAR_LISP ("xemacs-logo", &Vxemacs_logo /*
4765 The glyph used to display the XEmacs logo at startup.
4766 */ );
4767   Vxemacs_logo = allocate_glyph (GLYPH_BUFFER, 0);
4768 }