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