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