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