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