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