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