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