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
8 This file is part of SXEmacs
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.
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.
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/>. */
24 /* Synched up with: Not in FSF. */
26 /* Written by Ben Wing and Chuck Thompson. Heavily modified /
27 rewritten by Andy Piper. */
32 #include <mem/blocktype.h>
44 #include "redisplay.h"
45 #include "specifier.h"
47 #include <ent/ent-float.h>
53 Lisp_Object Qimage_conversion_error;
55 Lisp_Object Qglyphp, Qcontrib_p, Qbaseline;
56 Lisp_Object Qbuffer_glyph_p, Qpointer_glyph_p, Qicon_glyph_p;
57 Lisp_Object Qnothing_image_instance_p, Qtext_image_instance_p;
58 Lisp_Object Qmono_pixmap_image_instance_p;
59 Lisp_Object Qcolor_pixmap_image_instance_p;
60 Lisp_Object Qpointer_image_instance_p;
61 Lisp_Object Qsubwindow_image_instance_p;
62 Lisp_Object Qwidget_image_instance_p;
63 Lisp_Object Qconst_glyph_variable;
64 Lisp_Object Qmono_pixmap, Qcolor_pixmap, Qsubwindow;
65 Lisp_Object Q_face, Q_pixel_width, Q_pixel_height;
66 Lisp_Object Qformatted_string;
67 Lisp_Object Vcurrent_display_table;
68 Lisp_Object Vtruncation_glyph, Vcontinuation_glyph, Voctal_escape_glyph;
69 Lisp_Object Vcontrol_arrow_glyph, Vinvisible_text_glyph, Vhscroll_glyph;
70 Lisp_Object Vsxemacs_logo;
71 Lisp_Object Vthe_nothing_vector;
72 Lisp_Object Vimage_instantiator_format_list;
73 Lisp_Object Vimage_instance_type_list;
74 Lisp_Object Vglyph_type_list;
76 int disable_animated_pixmaps;
78 DEFINE_IMAGE_INSTANTIATOR_FORMAT(nothing);
79 DEFINE_IMAGE_INSTANTIATOR_FORMAT(inherit);
80 DEFINE_IMAGE_INSTANTIATOR_FORMAT(string);
81 DEFINE_IMAGE_INSTANTIATOR_FORMAT(formatted_string);
82 DEFINE_IMAGE_INSTANTIATOR_FORMAT(subwindow);
83 DEFINE_IMAGE_INSTANTIATOR_FORMAT(text);
84 DEFINE_IMAGE_INSTANTIATOR_FORMAT(pointer);
86 Lisp_Object Q_mask_file, Q_mask_data, Q_hotspot_x, Q_hotspot_y;
87 Lisp_Object Q_foreground, Q_background;
89 #ifdef HAVE_WINDOW_SYSTEM
90 DEFINE_IMAGE_INSTANTIATOR_FORMAT(xbm);
94 #define BitmapSuccess 0
95 #define BitmapOpenFailed 1
96 #define BitmapFileInvalid 2
97 #define BitmapNoMemory 3
102 DEFINE_IMAGE_INSTANTIATOR_FORMAT(xface);
107 DEFINE_IMAGE_INSTANTIATOR_FORMAT(xpm);
109 Lisp_Object Q_color_symbols;
112 typedef struct image_instantiator_format_entry image_instantiator_format_entry;
113 struct image_instantiator_format_entry {
116 struct image_instantiator_methods *meths;
120 Dynarr_declare(struct image_instantiator_format_entry);
121 } image_instantiator_format_entry_dynarr;
123 /* This contains one entry per format, per device it's defined on. */
124 image_instantiator_format_entry_dynarr
125 *the_image_instantiator_format_entry_dynarr;
127 static Lisp_Object allocate_image_instance(Lisp_Object governing_domain,
129 Lisp_Object instantiator);
130 static void image_validate(Lisp_Object instantiator);
131 static void glyph_property_was_changed(Lisp_Object glyph,
132 Lisp_Object property,
134 static void set_image_instance_dirty_p(Lisp_Object instance, int dirty);
135 static void register_ignored_expose(struct frame *f, int x, int y, int width,
137 static void cache_subwindow_instance_in_frame_maybe(Lisp_Object instance);
138 static void update_image_instance(Lisp_Object image_instance,
139 Lisp_Object instantiator);
140 /* Unfortunately windows and X are different. In windows BeginPaint()
141 will prevent WM_PAINT messages being generated so it is unnecessary
142 to register exposures as they will not occur. Under X they will
144 int hold_ignored_expose_registration;
146 EXFUN(Fimage_instance_type, 1);
147 EXFUN(Fglyph_type, 1);
148 EXFUN(Fnext_window, 4);
150 /****************************************************************************
151 * Image Instantiators *
152 ****************************************************************************/
154 struct image_instantiator_methods *decode_device_ii_format(Lisp_Object device,
160 if (!SYMBOLP(format)) {
161 if (ERRB_EQ(errb, ERROR_ME))
162 CHECK_SYMBOL(format);
167 i < Dynarr_length(the_image_instantiator_format_entry_dynarr);
171 Dynarr_at(the_image_instantiator_format_entry_dynarr,
175 (the_image_instantiator_format_entry_dynarr,
177 if ((NILP(d) && NILP(device))
180 EQ(CONSOLE_TYPE(XCONSOLE
181 (DEVICE_CONSOLE(XDEVICE(device)))),
185 (the_image_instantiator_format_entry_dynarr,
190 maybe_signal_simple_error("Invalid image-instantiator format", format,
196 struct image_instantiator_methods *decode_image_instantiator_format(Lisp_Object
201 return decode_device_ii_format(Qnil, format, errb);
205 valid_image_instantiator_format_p(Lisp_Object format, Lisp_Object locale)
208 struct image_instantiator_methods *meths =
209 decode_image_instantiator_format(format, ERROR_ME_NOT);
210 Lisp_Object contype = Qnil;
211 /* mess with the locale */
212 if (!NILP(locale) && SYMBOLP(locale))
215 struct console *console = decode_console(locale);
216 contype = console ? CONSOLE_TYPE(console) : locale;
218 /* nothing is valid in all locales */
219 if (EQ(format, Qnothing))
221 /* reject unknown formats */
222 else if (NILP(contype) || !meths)
225 for (i = 0; i < Dynarr_length(meths->consoles); i++)
226 if (EQ(contype, Dynarr_at(meths->consoles, i).symbol))
231 DEFUN("valid-image-instantiator-format-p", Fvalid_image_instantiator_format_p, 1, 2, 0, /*
232 Given an IMAGE-INSTANTIATOR-FORMAT, return non-nil if it is valid.
233 If LOCALE is non-nil then the format is checked in that locale.
234 If LOCALE is nil the current console is used.
236 Valid formats are some subset of 'nothing, 'string, 'formatted-string,
237 'xpm, 'xbm, 'xface, 'gif, 'jpeg, 'png, 'tiff, 'cursor-font, 'font,
238 'autodetect, 'subwindow, 'inherit, 'mswindows-resource, 'bmp,
239 'native-layout, 'layout, 'label, 'tab-control, 'tree-view,
240 'progress-gauge, 'scrollbar, 'combo-box, 'edit-field, 'button,
241 'widget, 'pointer, and 'text, depending on how SXEmacs was compiled.
243 (image_instantiator_format, locale))
245 return valid_image_instantiator_format_p(image_instantiator_format,
249 DEFUN("image-instantiator-format-list", Fimage_instantiator_format_list, 0, 0, 0, /*
250 Return a list of valid image-instantiator formats.
254 return Fcopy_sequence(Vimage_instantiator_format_list);
258 add_entry_to_device_ii_format_list(Lisp_Object device, Lisp_Object symbol,
259 struct image_instantiator_methods *meths)
261 struct image_instantiator_format_entry entry;
263 entry.symbol = symbol;
264 entry.device = device;
266 Dynarr_add(the_image_instantiator_format_entry_dynarr, entry);
267 if (NILP(memq_no_quit(symbol, Vimage_instantiator_format_list)))
268 Vimage_instantiator_format_list =
269 Fcons(symbol, Vimage_instantiator_format_list);
272 void add_entry_to_image_instantiator_format_list(Lisp_Object symbol, struct
273 image_instantiator_methods
276 add_entry_to_device_ii_format_list(Qnil, symbol, meths);
279 static Lisp_Object *get_image_conversion_list(Lisp_Object console_type)
281 return &decode_console_type(console_type,
282 ERROR_ME)->image_conversion_list;
285 DEFUN("set-console-type-image-conversion-list", Fset_console_type_image_conversion_list, 2, 2, 0, /*
286 Set the image-conversion-list for consoles of the given CONSOLE-TYPE.
287 The image-conversion-list specifies how image instantiators that
288 are strings should be interpreted. Each element of the list should be
289 a list of two elements (a regular expression string and a vector) or
290 a list of three elements (the preceding two plus an integer index into
291 the vector). The string is converted to the vector associated with the
292 first matching regular expression. If a vector index is specified, the
293 string itself is substituted into that position in the vector.
295 Note: The conversion above is applied when the image instantiator is
296 added to an image specifier, not when the specifier is actually
297 instantiated. Therefore, changing the image-conversion-list only affects
298 newly-added instantiators. Existing instantiators in glyphs and image
299 specifiers will not be affected.
301 (console_type, list))
304 Lisp_Object *imlist = get_image_conversion_list(console_type);
306 /* Check the list to make sure that it only has valid entries. */
308 EXTERNAL_LIST_LOOP(tail, list) {
309 Lisp_Object mapping = XCAR(tail);
311 /* Mapping form should be (STRING VECTOR) or (STRING VECTOR INTEGER) */
312 if (!CONSP(mapping) ||
313 !CONSP(XCDR(mapping)) ||
314 (!NILP(XCDR(XCDR(mapping))) &&
315 (!CONSP(XCDR(XCDR(mapping))) ||
316 !NILP(XCDR(XCDR(XCDR(mapping)))))))
317 signal_simple_error("Invalid mapping form", mapping);
319 Lisp_Object mapexp = XCAR(mapping);
320 Lisp_Object typevec = XCAR(XCDR(mapping));
321 Lisp_Object pos = Qnil;
325 CHECK_STRING(mapexp);
326 CHECK_VECTOR(typevec);
327 if (!NILP(XCDR(XCDR(mapping)))) {
328 pos = XCAR(XCDR(XCDR(mapping)));
331 XINT(pos) >= XVECTOR_LENGTH(typevec))
334 make_int(XVECTOR_LENGTH(typevec) -
338 newvec = Fcopy_sequence(typevec);
340 XVECTOR_DATA(newvec)[XINT(pos)] = mapexp;
342 image_validate(newvec);
347 *imlist = Fcopy_tree(list, Qt);
351 DEFUN("console-type-image-conversion-list", Fconsole_type_image_conversion_list, 1, 1, 0, /*
352 Return the image-conversion-list for devices of the given CONSOLE-TYPE.
353 The image-conversion-list specifies how to interpret image string
354 instantiators for the specified console type. See
355 `set-console-type-image-conversion-list' for a description of its syntax.
359 return Fcopy_tree(*get_image_conversion_list(console_type), Qt);
362 /* Process a string instantiator according to the image-conversion-list for
363 CONSOLE_TYPE. Returns a vector. */
366 process_image_string_instantiator(Lisp_Object data,
367 Lisp_Object console_type, int dest_mask)
371 LIST_LOOP(tail, *get_image_conversion_list(console_type)) {
372 Lisp_Object mapping = XCAR(tail);
373 Lisp_Object mapexp = XCAR(mapping);
374 Lisp_Object typevec = XCAR(XCDR(mapping));
376 /* if the result is of a type that can't be instantiated
377 (e.g. a string when we're dealing with a pointer glyph),
380 IIFORMAT_METH(decode_image_instantiator_format
381 (INSTANTIATOR_TYPE(typevec), ERROR_ME),
382 possible_dest_types, ())))
384 if (fast_string_match(mapexp, 0, data, 0, -1, 0, ERROR_ME, 0) >=
386 if (!NILP(XCDR(XCDR(mapping)))) {
387 int pos = XINT(XCAR(XCDR(XCDR(mapping))));
388 Lisp_Object newvec = Fcopy_sequence(typevec);
389 XVECTOR_DATA(newvec)[pos] = data;
397 signal_simple_error("Unable to interpret glyph instantiator", data);
403 find_keyword_in_vector_or_given(Lisp_Object vector, Lisp_Object keyword,
404 Lisp_Object default_)
407 int instantiator_len;
409 elt = XVECTOR_DATA(vector);
410 instantiator_len = XVECTOR_LENGTH(vector);
415 while (instantiator_len > 0) {
416 if (EQ(elt[0], keyword))
419 instantiator_len -= 2;
425 Lisp_Object find_keyword_in_vector(Lisp_Object vector, Lisp_Object keyword)
427 return find_keyword_in_vector_or_given(vector, keyword, Qnil);
431 find_instantiator_differences(Lisp_Object new, Lisp_Object old)
433 Lisp_Object alist = Qnil;
434 Lisp_Object *elt = XVECTOR_DATA(new);
435 Lisp_Object *old_elt = XVECTOR_DATA(old);
436 int len = XVECTOR_LENGTH(new);
439 /* If the vector length has changed then consider everything
440 changed. We could try and figure out what properties have
441 disappeared or been added, but this code is only used as an
442 optimization anyway so lets not bother. */
443 if (len != XVECTOR_LENGTH(old))
448 for (len -= 2; len >= 1; len -= 2) {
449 /* Keyword comparisons can be done with eq, the value must be
451 #### Note that this does not optimize re-ordering. */
452 if (!EQ(elt[len], old_elt[len])
453 || !internal_equal(elt[len + 1], old_elt[len + 1], 0))
454 alist = Fcons(Fcons(elt[len], elt[len + 1]), alist);
458 Lisp_Object result = alist_to_tagged_vector(elt[0], alist);
460 RETURN_UNGCPRO(result);
464 DEFUN("set-instantiator-property", Fset_instantiator_property, 3, 3, 0, /*
465 Destructively set the property KEYWORD of INSTANTIATOR to VALUE.
466 If the property is not set then it is added to a copy of the
467 instantiator and the new instantiator returned.
468 Use `set-glyph-image' on glyphs to register instantiator changes.
470 (instantiator, keyword, value))
475 CHECK_VECTOR(instantiator);
476 if (!KEYWORDP(keyword))
477 signal_simple_error("instantiator property must be a keyword",
480 elt = XVECTOR_DATA(instantiator);
481 len = XVECTOR_LENGTH(instantiator);
483 for (len -= 2; len >= 1; len -= 2) {
484 if (EQ(elt[len], keyword)) {
485 elt[len + 1] = value;
490 /* Didn't find it so add it. */
492 Lisp_Object alist = Qnil, result;
496 alist = tagged_vector_to_alist(instantiator);
497 alist = Fcons(Fcons(keyword, value), alist);
498 result = alist_to_tagged_vector(elt[0], alist);
500 RETURN_UNGCPRO(result);
506 void check_valid_string(Lisp_Object data)
511 void check_valid_vector(Lisp_Object data)
516 void check_valid_face(Lisp_Object data)
521 void check_valid_int(Lisp_Object data)
526 void file_or_data_must_be_present(Lisp_Object instantiator)
528 if (NILP(find_keyword_in_vector(instantiator, Q_file)) &&
529 NILP(find_keyword_in_vector(instantiator, Q_data)))
530 signal_simple_error("Must supply either :file or :data",
534 void data_must_be_present(Lisp_Object instantiator)
536 if (NILP(find_keyword_in_vector(instantiator, Q_data)))
537 signal_simple_error("Must supply :data", instantiator);
540 static void face_must_be_present(Lisp_Object instantiator)
542 if (NILP(find_keyword_in_vector(instantiator, Q_face)))
543 signal_simple_error("Must supply :face", instantiator);
546 /* utility function useful in retrieving data from a file. */
548 Lisp_Object make_string_from_file(Lisp_Object file)
550 /* This function can call lisp */
551 int count = specpdl_depth();
552 Lisp_Object temp_buffer;
556 specbind(Qinhibit_quit, Qt);
557 record_unwind_protect(Fset_buffer, Fcurrent_buffer());
558 temp_buffer = Fget_buffer_create(build_string(" *pixmap conversion*"));
560 set_buffer_internal(XBUFFER(temp_buffer));
562 specbind(intern("format-alist"), Qnil);
563 Finsert_file_contents_internal(file, Qnil, Qnil, Qnil, Qnil, Qnil,
565 data = Fbuffer_substring(Qnil, Qnil, Qnil);
566 unbind_to(count, Qnil);
571 /* The following two functions are provided to make it easier for
572 the normalize methods to work with keyword-value vectors.
573 Hash tables are kind of heavyweight for this purpose.
574 (If vectors were resizable, we could avoid this problem;
575 but they're not.) An alternative approach that might be
576 more efficient but require more work is to use a type of
577 assoc-Dynarr and provide primitives for deleting elements out
578 of it. (However, you'd also have to add an unwind-protect
579 to make sure the Dynarr got freed in case of an error in
580 the normalization process.) */
582 Lisp_Object tagged_vector_to_alist(Lisp_Object vector)
584 Lisp_Object *elt = XVECTOR_DATA(vector);
585 int len = XVECTOR_LENGTH(vector);
586 Lisp_Object result = Qnil;
589 for (len -= 2; len >= 1; len -= 2)
590 result = Fcons(Fcons(elt[len], elt[len + 1]), result);
595 Lisp_Object alist_to_tagged_vector(Lisp_Object tag, Lisp_Object alist)
597 int len = 1 + 2 * XINT(Flength(alist));
598 Lisp_Object *elt = alloca_array(Lisp_Object, len);
604 LIST_LOOP(rest, alist) {
605 Lisp_Object pair = XCAR(rest);
607 elt[i + 1] = XCDR(pair);
611 return Fvector(len, elt);
614 #ifdef ERROR_CHECK_GLYPHS
616 check_instance_cache_mapper(Lisp_Object key, Lisp_Object value,
619 /* This function can GC */
620 /* value can be nil; we cache failures as well as successes */
623 VOID_TO_LISP(window, flag_closure);
624 assert(EQ(XIMAGE_INSTANCE_DOMAIN(value), window));
630 void check_window_subwindow_cache(struct window *w)
634 XSETWINDOW(window, w);
636 assert(!NILP(w->subwindow_instance_cache));
637 elisp_maphash(check_instance_cache_mapper,
638 w->subwindow_instance_cache, LISP_TO_VOID(window));
641 void check_image_instance_structure(Lisp_Object instance)
643 /* Weird nothing images exist at startup when the console is
645 if (!NOTHING_IMAGE_INSTANCEP(instance)) {
646 assert(DOMAIN_LIVE_P(instance));
647 assert(VECTORP(XIMAGE_INSTANCE_INSTANTIATOR(instance)));
649 if (WINDOWP(XIMAGE_INSTANCE_DOMAIN(instance)))
650 check_window_subwindow_cache
651 (XWINDOW(XIMAGE_INSTANCE_DOMAIN(instance)));
655 /* Determine what kind of domain governs the image instance.
656 Verify that the given domain is at least as specific, and extract
657 the governing domain from it. */
659 get_image_instantiator_governing_domain(Lisp_Object instantiator,
662 int governing_domain;
664 struct image_instantiator_methods *meths =
665 decode_image_instantiator_format(INSTANTIATOR_TYPE(instantiator),
667 governing_domain = IIFORMAT_METH_OR_GIVEN(meths, governing_domain, (),
668 GOVERNING_DOMAIN_DEVICE);
670 if (governing_domain == GOVERNING_DOMAIN_WINDOW
671 && NILP(DOMAIN_WINDOW(domain)))
672 signal_simple_error_2
673 ("Domain for this instantiator must be resolvable to a window",
674 instantiator, domain);
675 else if (governing_domain == GOVERNING_DOMAIN_FRAME
676 && NILP(DOMAIN_FRAME(domain)))
677 signal_simple_error_2
678 ("Domain for this instantiator must be resolvable to a frame",
679 instantiator, domain);
681 if (governing_domain == GOVERNING_DOMAIN_WINDOW)
682 domain = DOMAIN_WINDOW(domain);
683 else if (governing_domain == GOVERNING_DOMAIN_FRAME)
684 domain = DOMAIN_FRAME(domain);
685 else if (governing_domain == GOVERNING_DOMAIN_DEVICE)
686 domain = DOMAIN_DEVICE(domain);
694 normalize_image_instantiator(Lisp_Object instantiator,
695 Lisp_Object contype, Lisp_Object dest_mask)
697 if (IMAGE_INSTANCEP(instantiator))
700 if (STRINGP(instantiator))
702 process_image_string_instantiator(instantiator, contype,
704 /* Subsequent validation will pick this up. */
705 if (!VECTORP(instantiator))
707 /* We have to always store the actual pixmap data and not the
708 filename even though this is a potential memory pig. We have to
709 do this because it is quite possible that we will need to
710 instantiate a new instance of the pixmap and the file will no
711 longer exist (e.g. w3 pixmaps are almost always from temporary
715 struct image_instantiator_methods *meths;
717 GCPRO1(instantiator);
720 decode_image_instantiator_format(INSTANTIATOR_TYPE
721 (instantiator), ERROR_ME);
722 RETURN_UNGCPRO(IIFORMAT_METH_OR_GIVEN
724 (instantiator, contype, dest_mask),
730 instantiate_image_instantiator(Lisp_Object governing_domain,
732 Lisp_Object instantiator,
733 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
734 int dest_mask, Lisp_Object glyph)
736 Lisp_Object ii = allocate_image_instance(governing_domain,
737 IMAGE_INSTANCEP(domain) ?
738 domain : glyph, instantiator);
739 Lisp_Image_Instance *p = XIMAGE_INSTANCE(ii);
740 struct image_instantiator_methods *meths, *device_meths;
744 if (!valid_image_instantiator_format_p(INSTANTIATOR_TYPE(instantiator),
745 DOMAIN_DEVICE(governing_domain)))
747 ("Image instantiator format is invalid in this locale.",
751 decode_image_instantiator_format(INSTANTIATOR_TYPE(instantiator),
753 MAYBE_IIFORMAT_METH(meths, instantiate,
754 (ii, instantiator, pointer_fg, pointer_bg,
757 /* Now do device specific instantiation. */
758 device_meths = decode_device_ii_format(DOMAIN_DEVICE(governing_domain),
759 INSTANTIATOR_TYPE(instantiator),
762 if (!HAS_IIFORMAT_METH_P(meths, instantiate)
764 || !HAS_IIFORMAT_METH_P(device_meths, instantiate)))
766 ("Don't know how to instantiate this image instantiator?",
769 /* In general native window system methods will require sane
770 geometry values, thus the instance needs to have been laid-out
771 before they get called. */
772 image_instance_layout(ii, XIMAGE_INSTANCE_WIDTH(ii),
773 XIMAGE_INSTANCE_HEIGHT(ii),
774 IMAGE_UNCHANGED_GEOMETRY,
775 IMAGE_UNCHANGED_GEOMETRY, domain);
777 MAYBE_IIFORMAT_METH(device_meths, instantiate,
778 (ii, instantiator, pointer_fg, pointer_bg,
780 /* Do post instantiation. */
781 MAYBE_IIFORMAT_METH(meths, post_instantiate,
782 (ii, instantiator, domain));
783 MAYBE_IIFORMAT_METH(device_meths, post_instantiate,
784 (ii, instantiator, domain));
787 IMAGE_INSTANCE_INITIALIZED(p) = 1;
788 /* Now that we're done verify that we really are laid out. */
789 if (IMAGE_INSTANCE_LAYOUT_CHANGED(p))
790 image_instance_layout(ii, XIMAGE_INSTANCE_WIDTH(ii),
791 XIMAGE_INSTANCE_HEIGHT(ii),
792 IMAGE_UNCHANGED_GEOMETRY,
793 IMAGE_UNCHANGED_GEOMETRY, domain);
795 /* We *must* have a clean image at this point. */
796 IMAGE_INSTANCE_TEXT_CHANGED(p) = 0;
797 IMAGE_INSTANCE_SIZE_CHANGED(p) = 0;
798 IMAGE_INSTANCE_LAYOUT_CHANGED(p) = 0;
799 IMAGE_INSTANCE_DIRTYP(p) = 0;
801 assert(XIMAGE_INSTANCE_HEIGHT(ii) >= 0
802 && XIMAGE_INSTANCE_WIDTH(ii) >= 0);
804 ERROR_CHECK_IMAGE_INSTANCE(ii);
809 /****************************************************************************
810 * Image-Instance Object *
811 ****************************************************************************/
813 Lisp_Object Qimage_instancep;
815 static Lisp_Object mark_image_instance(Lisp_Object obj)
817 Lisp_Image_Instance *i = XIMAGE_INSTANCE(obj);
819 /* #### I want to check the instance here, but there are way too
820 many instances of the instance being marked while the domain is
821 dead. For instance you can get marked through an event when using
824 ERROR_CHECK_IMAGE_INSTANCE(obj);
827 mark_object(i->name);
828 mark_object(i->instantiator);
829 /* Is this legal in marking? We may get in the situation where the
830 domain has been deleted - making the instance unusable. It seems
831 better to remove the domain so that it can be finalized. */
832 if (!DOMAIN_LIVE_P(i->domain))
835 mark_object(i->domain);
837 /* We don't mark the glyph reference since that would create a
838 circularity preventing GC. Ditto the instantiator. */
839 switch (IMAGE_INSTANCE_TYPE(i)) {
841 mark_object(IMAGE_INSTANCE_TEXT_STRING(i));
843 case IMAGE_MONO_PIXMAP:
844 case IMAGE_COLOR_PIXMAP:
845 mark_object(IMAGE_INSTANCE_PIXMAP_FILENAME(i));
846 mark_object(IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i));
847 mark_object(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i));
848 mark_object(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i));
849 mark_object(IMAGE_INSTANCE_PIXMAP_FG(i));
850 mark_object(IMAGE_INSTANCE_PIXMAP_BG(i));
854 mark_object(IMAGE_INSTANCE_WIDGET_TYPE(i));
855 mark_object(IMAGE_INSTANCE_WIDGET_PROPS(i));
856 mark_object(IMAGE_INSTANCE_SUBWINDOW_FACE(i));
857 mark_object(IMAGE_INSTANCE_WIDGET_ITEMS(i));
858 mark_object(IMAGE_INSTANCE_LAYOUT_CHILDREN(i));
859 mark_object(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(i));
860 mark_object(IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i));
861 mark_object(IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i));
862 case IMAGE_SUBWINDOW:
872 /* The image may have been previously finalized (yes that's weird,
873 see Fdelete_frame() and mark_window_as_deleted()), in which case
874 the domain will be nil, so cope with this. */
875 if (!NILP(IMAGE_INSTANCE_DEVICE(i)))
876 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(i)),
877 mark_image_instance, (i));
883 print_image_instance(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
885 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(obj);
888 error("printing unreadable object #<image-instance 0x%x>",
890 write_c_string("#<image-instance (", printcharfun);
891 print_internal(Fimage_instance_type(obj), printcharfun, 0);
892 write_c_string(") ", printcharfun);
893 if (!NILP(ii->name)) {
894 print_internal(ii->name, printcharfun, 1);
895 write_c_string(" ", printcharfun);
897 write_c_string("on ", printcharfun);
898 print_internal(ii->domain, printcharfun, 0);
899 write_c_string(" ", printcharfun);
900 switch (IMAGE_INSTANCE_TYPE(ii)) {
905 print_internal(IMAGE_INSTANCE_TEXT_STRING(ii), printcharfun, 1);
908 case IMAGE_MONO_PIXMAP:
909 case IMAGE_COLOR_PIXMAP:
911 if (STRINGP(IMAGE_INSTANCE_PIXMAP_FILENAME(ii))) {
913 Lisp_Object filename =
914 IMAGE_INSTANCE_PIXMAP_FILENAME(ii);
915 s = strrchr((char *)XSTRING_DATA(filename), '/');
917 print_internal(build_string(s + 1),
920 print_internal(filename, printcharfun, 1);
922 if (IMAGE_INSTANCE_PIXMAP_DEPTH(ii) > 1)
923 write_fmt_str(printcharfun, " %dx%dx%d",
924 IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
925 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii),
926 IMAGE_INSTANCE_PIXMAP_DEPTH(ii));
928 write_fmt_str(printcharfun, " %dx%d", IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
929 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii));
930 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) ||
931 !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
932 write_c_string(" @", printcharfun);
933 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii))) {
934 write_fmt_str(printcharfun,"%ld",
935 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)));
937 write_c_string("??", printcharfun);
938 write_c_string(",", printcharfun);
939 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
940 write_fmt_str(printcharfun,"%ld",
941 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii)));
943 write_c_string("??", printcharfun);
945 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii)) ||
946 !NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
947 write_c_string(" (", printcharfun);
948 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii))) {
951 (IMAGE_INSTANCE_PIXMAP_FG(ii))->name,
954 write_c_string("/", printcharfun);
955 if (!NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
958 (IMAGE_INSTANCE_PIXMAP_BG(ii))->name,
961 write_c_string(")", printcharfun);
966 print_internal(IMAGE_INSTANCE_WIDGET_TYPE(ii), printcharfun, 0);
968 if (GUI_ITEMP(IMAGE_INSTANCE_WIDGET_ITEM(ii))) {
969 write_c_string(" ", printcharfun);
970 print_internal(IMAGE_INSTANCE_WIDGET_TEXT(ii),
974 if (!NILP(IMAGE_INSTANCE_WIDGET_FACE(ii))) {
975 write_c_string(" face=", printcharfun);
977 (IMAGE_INSTANCE_WIDGET_FACE(ii), printcharfun, 0);
981 case IMAGE_SUBWINDOW:
982 write_fmt_str(printcharfun, " %dx%d", IMAGE_INSTANCE_WIDTH(ii),
983 IMAGE_INSTANCE_HEIGHT(ii));
985 /* This is stolen from frame.c. Subwindows are strange in that they
986 are specific to a particular frame so we want to print in their
987 description what that frame is. */
989 write_c_string(" on #<", printcharfun);
991 struct frame *f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
993 if (!FRAME_LIVE_P(f))
994 write_c_string("dead", printcharfun);
996 write_c_string(DEVICE_TYPE_NAME
997 (XDEVICE(FRAME_DEVICE(f))),
1000 write_c_string("-frame>", printcharfun);
1001 write_hex_ptr( IMAGE_INSTANCE_SUBWINDOW_ID(ii), printcharfun);
1010 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain), print_image_instance,
1011 (ii, printcharfun, escapeflag));
1012 write_fmt_str(printcharfun, " 0x%x>", ii->header.uid);
1015 static void finalize_image_instance(void *header, int for_disksave)
1017 Lisp_Image_Instance *i = (Lisp_Image_Instance *) header;
1019 /* objects like this exist at dump time, so don't bomb out. */
1020 if (IMAGE_INSTANCE_TYPE(i) == IMAGE_NOTHING
1021 || NILP(IMAGE_INSTANCE_DEVICE(i)))
1026 /* We can't use the domain here, because it might have
1028 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(i)),
1029 finalize_image_instance, (i));
1031 /* Make sure we don't try this twice. */
1032 IMAGE_INSTANCE_DEVICE(i) = Qnil;
1035 static int image_instance_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
1037 Lisp_Image_Instance *i1 = XIMAGE_INSTANCE(obj1);
1038 Lisp_Image_Instance *i2 = XIMAGE_INSTANCE(obj2);
1040 ERROR_CHECK_IMAGE_INSTANCE(obj1);
1041 ERROR_CHECK_IMAGE_INSTANCE(obj2);
1043 if (!EQ(IMAGE_INSTANCE_DOMAIN(i1), IMAGE_INSTANCE_DOMAIN(i2))
1044 || IMAGE_INSTANCE_TYPE(i1) != IMAGE_INSTANCE_TYPE(i2)
1045 || IMAGE_INSTANCE_WIDTH(i1) != IMAGE_INSTANCE_WIDTH(i2)
1046 || IMAGE_INSTANCE_MARGIN_WIDTH(i1) !=
1047 IMAGE_INSTANCE_MARGIN_WIDTH(i2)
1048 || IMAGE_INSTANCE_HEIGHT(i1) != IMAGE_INSTANCE_HEIGHT(i2)
1049 || IMAGE_INSTANCE_XOFFSET(i1) != IMAGE_INSTANCE_XOFFSET(i2)
1050 || IMAGE_INSTANCE_YOFFSET(i1) != IMAGE_INSTANCE_YOFFSET(i2))
1052 if (!internal_equal(IMAGE_INSTANCE_NAME(i1), IMAGE_INSTANCE_NAME(i2),
1055 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(i1),
1056 IMAGE_INSTANCE_INSTANTIATOR(i2), depth + 1))
1059 switch (IMAGE_INSTANCE_TYPE(i1)) {
1064 if (!internal_equal(IMAGE_INSTANCE_TEXT_STRING(i1),
1065 IMAGE_INSTANCE_TEXT_STRING(i2), depth + 1))
1069 case IMAGE_MONO_PIXMAP:
1070 case IMAGE_COLOR_PIXMAP:
1072 if (!(IMAGE_INSTANCE_PIXMAP_DEPTH(i1) ==
1073 IMAGE_INSTANCE_PIXMAP_DEPTH(i2) &&
1074 IMAGE_INSTANCE_PIXMAP_SLICE(i1) ==
1075 IMAGE_INSTANCE_PIXMAP_SLICE(i2) &&
1076 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i1),
1077 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i2)) &&
1078 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i1),
1079 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i2)) &&
1080 internal_equal(IMAGE_INSTANCE_PIXMAP_FILENAME(i1),
1081 IMAGE_INSTANCE_PIXMAP_FILENAME(i2),
1083 internal_equal(IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i1),
1084 IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i2),
1090 if (!(EQ(IMAGE_INSTANCE_WIDGET_TYPE(i1),
1091 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1092 && IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1093 IMAGE_INSTANCE_SUBWINDOW_ID(i2)
1095 EQ(IMAGE_INSTANCE_WIDGET_FACE(i1),
1096 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1097 && internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(i1),
1098 IMAGE_INSTANCE_WIDGET_ITEMS(i2),
1100 && internal_equal(IMAGE_INSTANCE_LAYOUT_CHILDREN(i1),
1101 IMAGE_INSTANCE_LAYOUT_CHILDREN(i2),
1103 && internal_equal(IMAGE_INSTANCE_WIDGET_PROPS(i1),
1104 IMAGE_INSTANCE_WIDGET_PROPS(i2),
1106 && internal_equal(IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i1),
1107 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i2),
1109 && internal_equal(IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i1),
1110 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i2),
1116 case IMAGE_SUBWINDOW:
1117 if (!(IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1118 IMAGE_INSTANCE_SUBWINDOW_ID(i2)))
1127 return DEVMETH_OR_GIVEN(DOMAIN_XDEVICE(i1->domain),
1128 image_instance_equal, (i1, i2, depth), 1);
1131 /* Image instance domain manipulators. We can't error check in these
1132 otherwise we get into infinite recursion. */
1133 Lisp_Object image_instance_device(Lisp_Object instance)
1135 return XIMAGE_INSTANCE_DEVICE(instance);
1138 Lisp_Object image_instance_frame(Lisp_Object instance)
1140 return XIMAGE_INSTANCE_FRAME(instance);
1143 Lisp_Object image_instance_window(Lisp_Object instance)
1145 return DOMAIN_WINDOW(XIMAGE_INSTANCE_DOMAIN(instance));
1148 int image_instance_live_p(Lisp_Object instance)
1150 return DOMAIN_LIVE_P(XIMAGE_INSTANCE_DOMAIN(instance));
1153 static unsigned long image_instance_hash(Lisp_Object obj, int depth)
1155 Lisp_Image_Instance *i = XIMAGE_INSTANCE(obj);
1156 unsigned long hash = HASH5(LISP_HASH(IMAGE_INSTANCE_DOMAIN(i)),
1157 IMAGE_INSTANCE_WIDTH(i),
1158 IMAGE_INSTANCE_MARGIN_WIDTH(i),
1159 IMAGE_INSTANCE_HEIGHT(i),
1160 internal_hash(IMAGE_INSTANCE_INSTANTIATOR(i),
1163 ERROR_CHECK_IMAGE_INSTANCE(obj);
1165 switch (IMAGE_INSTANCE_TYPE(i)) {
1170 hash = HASH2(hash, internal_hash(IMAGE_INSTANCE_TEXT_STRING(i),
1174 case IMAGE_MONO_PIXMAP:
1175 case IMAGE_COLOR_PIXMAP:
1177 hash = HASH4(hash, IMAGE_INSTANCE_PIXMAP_DEPTH(i),
1178 IMAGE_INSTANCE_PIXMAP_SLICE(i),
1179 internal_hash(IMAGE_INSTANCE_PIXMAP_FILENAME(i),
1184 /* We need the hash to be equivalent to what should be
1187 LISP_HASH(IMAGE_INSTANCE_WIDGET_TYPE(i)),
1188 internal_hash(IMAGE_INSTANCE_WIDGET_PROPS(i),
1190 internal_hash(IMAGE_INSTANCE_WIDGET_ITEMS(i),
1192 internal_hash(IMAGE_INSTANCE_LAYOUT_CHILDREN(i),
1194 case IMAGE_SUBWINDOW:
1195 hash = HASH2(hash, (EMACS_INT) IMAGE_INSTANCE_SUBWINDOW_ID(i));
1204 Lisp_Object tmp = image_instance_device(obj);
1205 return HASH2(hash, DEVMETH_OR_GIVEN(
1206 XDEVICE(tmp), image_instance_hash,
1211 DEFINE_LRECORD_IMPLEMENTATION("image-instance", image_instance,
1212 mark_image_instance, print_image_instance,
1213 finalize_image_instance, image_instance_equal,
1214 image_instance_hash, 0, Lisp_Image_Instance);
1217 allocate_image_instance(Lisp_Object governing_domain, Lisp_Object parent,
1218 Lisp_Object instantiator)
1220 Lisp_Image_Instance *lp =
1221 alloc_lcrecord_type(Lisp_Image_Instance, &lrecord_image_instance);
1225 /* It's not possible to simply keep a record of the domain in which
1226 the instance was instantiated. This is because caching may mean
1227 that the domain becomes invalid but the instance remains
1228 valid. However, the only truly relevant domain is the domain in
1229 which the instance is cached since this is the one that will be
1230 common to the instances. */
1231 lp->domain = governing_domain;
1232 /* The cache domain is not quite sufficient since the domain can get
1233 deleted before the image instance does. We need to know the
1234 domain device in order to finalize the image instance
1235 properly. We therefore record the device also. */
1236 lp->device = DOMAIN_DEVICE(governing_domain);
1237 lp->type = IMAGE_NOTHING;
1241 lp->width = IMAGE_UNSPECIFIED_GEOMETRY;
1242 lp->margin_width = 0;
1243 lp->height = IMAGE_UNSPECIFIED_GEOMETRY;
1244 lp->parent = parent;
1245 lp->instantiator = instantiator;
1246 /* So that layouts get done. */
1247 lp->layout_changed = 1;
1248 lp->initialized = 0;
1250 XSETIMAGE_INSTANCE(val, lp);
1251 MARK_GLYPHS_CHANGED;
1256 static enum image_instance_type
1257 decode_image_instance_type(Lisp_Object type, Error_behavior errb)
1259 if (ERRB_EQ(errb, ERROR_ME))
1262 if (EQ(type, Qnothing))
1263 return IMAGE_NOTHING;
1264 if (EQ(type, Qtext))
1266 if (EQ(type, Qmono_pixmap))
1267 return IMAGE_MONO_PIXMAP;
1268 if (EQ(type, Qcolor_pixmap))
1269 return IMAGE_COLOR_PIXMAP;
1270 if (EQ(type, Qpointer))
1271 return IMAGE_POINTER;
1272 if (EQ(type, Qsubwindow))
1273 return IMAGE_SUBWINDOW;
1274 if (EQ(type, Qwidget))
1275 return IMAGE_WIDGET;
1277 maybe_signal_simple_error("Invalid image-instance type", type,
1280 return IMAGE_UNKNOWN; /* not reached */
1283 static Lisp_Object encode_image_instance_type(enum image_instance_type type)
1290 case IMAGE_MONO_PIXMAP:
1291 return Qmono_pixmap;
1292 case IMAGE_COLOR_PIXMAP:
1293 return Qcolor_pixmap;
1296 case IMAGE_SUBWINDOW:
1306 return Qnil; /* not reached */
1309 static int decode_image_instance_type_list(Lisp_Object list)
1318 enum image_instance_type type =
1319 decode_image_instance_type(list, ERROR_ME);
1320 return image_instance_type_to_mask(type);
1323 EXTERNAL_LIST_LOOP(rest, list) {
1324 enum image_instance_type type =
1325 decode_image_instance_type(XCAR(rest), ERROR_ME);
1326 mask |= image_instance_type_to_mask(type);
1332 static Lisp_Object encode_image_instance_type_list(int mask)
1335 Lisp_Object result = Qnil;
1340 result = Fcons(encode_image_instance_type
1341 ((enum image_instance_type)count),
1346 return Fnreverse(result);
1350 incompatible_image_types(Lisp_Object instantiator, int given_dest_mask,
1351 int desired_dest_mask)
1353 signal_error(Qerror, list2(emacs_doprnt_string_lisp_2((const Bufbyte *)
1354 "No compatible image-instance types given: wanted one of %s, got %s",
1356 encode_image_instance_type_list
1357 (desired_dest_mask),
1358 encode_image_instance_type_list
1363 static int valid_image_instance_type_p(Lisp_Object type)
1365 return !NILP(memq_no_quit(type, Vimage_instance_type_list));
1368 DEFUN("valid-image-instance-type-p", Fvalid_image_instance_type_p, 1, 1, 0, /*
1369 Given an IMAGE-INSTANCE-TYPE, return non-nil if it is valid.
1370 Valid types are some subset of 'nothing, 'text, 'mono-pixmap, 'color-pixmap,
1371 'pointer, 'subwindow, and 'widget, depending on how SXEmacs was compiled.
1373 (image_instance_type))
1375 return valid_image_instance_type_p(image_instance_type) ? Qt : Qnil;
1378 DEFUN("image-instance-type-list", Fimage_instance_type_list, 0, 0, 0, /*
1379 Return a list of valid image-instance types.
1383 return Fcopy_sequence(Vimage_instance_type_list);
1386 Error_behavior decode_error_behavior_flag(Lisp_Object noerror)
1390 else if (EQ(noerror, Qt))
1391 return ERROR_ME_NOT;
1393 return ERROR_ME_WARN;
1396 Lisp_Object encode_error_behavior_flag(Error_behavior errb)
1398 if (ERRB_EQ(errb, ERROR_ME))
1400 else if (ERRB_EQ(errb, ERROR_ME_NOT))
1403 assert(ERRB_EQ(errb, ERROR_ME_WARN));
1408 /* Recurse up the hierarchy looking for the topmost glyph. This means
1409 that instances in layouts will inherit face properties from their
1411 Lisp_Object image_instance_parent_glyph(Lisp_Image_Instance * ii)
1413 if (IMAGE_INSTANCEP(IMAGE_INSTANCE_PARENT(ii))) {
1414 return image_instance_parent_glyph
1415 (XIMAGE_INSTANCE(IMAGE_INSTANCE_PARENT(ii)));
1417 return IMAGE_INSTANCE_PARENT(ii);
1421 make_image_instance_1(Lisp_Object data, Lisp_Object domain,
1422 Lisp_Object dest_types)
1425 struct gcpro gcpro1;
1427 Lisp_Object governing_domain;
1429 if (IMAGE_INSTANCEP(data))
1430 signal_simple_error("Image instances not allowed here", data);
1431 image_validate(data);
1432 domain = decode_domain(domain);
1433 /* instantiate_image_instantiator() will abort if given an
1434 image instance ... */
1435 dest_mask = decode_image_instance_type_list(dest_types);
1436 data = normalize_image_instantiator(data,
1437 DEVICE_TYPE(DOMAIN_XDEVICE(domain)),
1438 make_int(dest_mask));
1440 /* After normalizing the data, it's always either an image instance (which
1441 we filtered out above) or a vector. */
1442 if (EQ(INSTANTIATOR_TYPE(data), Qinherit))
1443 signal_simple_error("Inheritance not allowed here", data);
1445 get_image_instantiator_governing_domain(data, domain);
1446 ii = instantiate_image_instantiator(governing_domain, domain, data,
1447 Qnil, Qnil, dest_mask, Qnil);
1451 DEFUN("make-image-instance", Fmake_image_instance, 1, 4, 0, /*
1452 Return a new `image-instance' object.
1454 Image-instance objects encapsulate the way a particular image (pixmap,
1455 etc.) is displayed on a particular device. In most circumstances, you
1456 do not need to directly create image instances; use a glyph instead.
1457 However, it may occasionally be useful to explicitly create image
1458 instances, if you want more control over the instantiation process.
1460 DATA is an image instantiator, which describes the image; see
1461 `make-image-specifier' for a description of the allowed values.
1463 DEST-TYPES should be a list of allowed image instance types that can
1464 be generated. The recognized image instance types are
1467 Nothing is displayed.
1469 Displayed as text. The foreground and background colors and the
1470 font of the text are specified independent of the pixmap. Typically
1471 these attributes will come from the face of the surrounding text,
1472 unless a face is specified for the glyph in which the image appears.
1474 Displayed as a mono pixmap (a pixmap with only two colors where the
1475 foreground and background can be specified independent of the pixmap;
1476 typically the pixmap assumes the foreground and background colors of
1477 the text around it, unless a face is specified for the glyph in which
1480 Displayed as a color pixmap.
1482 Used as the mouse pointer for a window.
1484 A child window that is treated as an image. This allows (e.g.)
1485 another program to be responsible for drawing into the window.
1487 A child window that contains a window-system widget, e.g. a push
1488 button, text field, or slider.
1490 The DEST-TYPES list is unordered. If multiple destination types are
1491 possible for a given instantiator, the "most natural" type for the
1492 instantiator's format is chosen. (For XBM, the most natural types are
1493 `mono-pixmap', followed by `color-pixmap', followed by `pointer'. For
1494 the other normal image formats, the most natural types are
1495 `color-pixmap', followed by `mono-pixmap', followed by `pointer'. For
1496 the string and formatted-string formats, the most natural types are
1497 `text', followed by `mono-pixmap' (not currently implemented),
1498 followed by `color-pixmap' (not currently implemented). For MS
1499 Windows resources, the most natural type for pointer resources is
1500 `pointer', and for the others it's `color-pixmap'. The other formats
1501 can only be instantiated as one type. (If you want to control more
1502 specifically the order of the types into which an image is
1503 instantiated, just call `make-image-instance' repeatedly until it
1504 succeeds, passing less and less preferred destination types each
1507 See `make-image-specifier' for a description of the different image
1508 instantiator formats.
1510 If DEST-TYPES is omitted, all possible types are allowed.
1512 DOMAIN specifies the domain to which the image instance will be attached.
1513 This domain is termed the \"governing domain\". The type of the governing
1514 domain depends on the image instantiator format. (Although, more correctly,
1515 it should probably depend on the image instance type.) For example, pixmap
1516 image instances are specific to a device, but widget image instances are
1517 specific to a particular SXEmacs window because in order to display such a
1518 widget when two windows onto the same buffer want to display the widget,
1519 two separate underlying widgets must be created. (That's because a widget
1520 is actually a child window-system window, and all window-system windows have
1521 a unique existence on the screen.) This means that the governing domain for
1522 a pixmap image instance will be some device (most likely, the only existing
1523 device), whereas the governing domain for a widget image instance will be
1524 some SXEmacs window.
1526 If you specify an overly general DOMAIN (e.g. a frame when a window was
1527 wanted), an error is signaled. If you specify an overly specific DOMAIN
1528 \(e.g. a window when a device was wanted), the corresponding general domain
1529 is fetched and used instead. For `make-image-instance', it makes no
1530 difference whether you specify an overly specific domain or the properly
1531 general domain derived from it. However, it does matter when creating an
1532 image instance by instantiating a specifier or glyph (e.g. with
1533 `glyph-image-instance'), because the more specific domain causes spec lookup
1534 to start there and proceed to more general domains. (It would also matter
1535 when creating an image instance with an instantiator format of `inherit',
1536 but we currently disallow this. #### We should fix this.)
1538 If omitted, DOMAIN defaults to the selected window.
1540 NOERROR controls what happens when the image cannot be generated.
1541 If nil, an error message is generated. If t, no messages are
1542 generated and this function returns nil. If anything else, a warning
1543 message is generated and this function returns nil.
1545 (data, domain, dest_types, noerror))
1547 Error_behavior errb = decode_error_behavior_flag(noerror);
1549 return call_with_suspended_errors((lisp_fn_t) make_image_instance_1,
1551 3, data, domain, dest_types);
1554 DEFUN("image-instance-p", Fimage_instance_p, 1, 1, 0, /*
1555 Return non-nil if OBJECT is an image instance.
1559 return IMAGE_INSTANCEP(object) ? Qt : Qnil;
1562 DEFUN("image-instance-type", Fimage_instance_type, 1, 1, 0, /*
1563 Return the type of the given image instance.
1564 The return value will be one of 'nothing, 'text, 'mono-pixmap,
1565 'color-pixmap, 'pointer, or 'subwindow.
1569 CHECK_IMAGE_INSTANCE(image_instance);
1570 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1571 return encode_image_instance_type(XIMAGE_INSTANCE_TYPE(image_instance));
1574 DEFUN("image-instance-name", Fimage_instance_name, 1, 1, 0, /*
1575 Return the name of the given image instance.
1579 CHECK_IMAGE_INSTANCE(image_instance);
1580 return XIMAGE_INSTANCE_NAME(image_instance);
1583 DEFUN("image-instance-domain", Fimage_instance_domain, 1, 1, 0, /*
1584 Return the governing domain of the given image instance.
1585 The governing domain of an image instance is the domain that the image
1586 instance is specific to. It is NOT necessarily the domain that was
1587 given to the call to `specifier-instance' that resulted in the creation
1588 of this image instance. See `make-image-instance' for more information
1589 on governing domains.
1593 CHECK_IMAGE_INSTANCE(image_instance);
1594 return XIMAGE_INSTANCE_DOMAIN(image_instance);
1597 DEFUN("image-instance-string", Fimage_instance_string, 1, 1, 0, /*
1598 Return the string of the given image instance.
1599 This will only be non-nil for text image instances and widgets.
1603 CHECK_IMAGE_INSTANCE(image_instance);
1604 if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_TEXT)
1605 return XIMAGE_INSTANCE_TEXT_STRING(image_instance);
1606 else if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_WIDGET)
1607 return XIMAGE_INSTANCE_WIDGET_TEXT(image_instance);
1612 DEFUN("image-instance-property", Fimage_instance_property, 2, 2, 0, /*
1613 Return the given property of the given image instance.
1614 Returns nil if the property or the property method do not exist for
1615 the image instance in the domain.
1617 (image_instance, prop))
1619 Lisp_Image_Instance *ii;
1620 Lisp_Object type, ret;
1621 struct image_instantiator_methods *meths;
1623 CHECK_IMAGE_INSTANCE(image_instance);
1624 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1626 ii = XIMAGE_INSTANCE(image_instance);
1628 /* ... then try device specific methods ... */
1629 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1630 meths = decode_device_ii_format(image_instance_device(image_instance),
1631 type, ERROR_ME_NOT);
1632 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1635 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1638 /* ... then format specific methods ... */
1639 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1640 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1643 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1650 DEFUN("image-instance-file-name", Fimage_instance_file_name, 1, 1, 0, /*
1651 Return the file name from which IMAGE-INSTANCE was read, if known.
1655 CHECK_IMAGE_INSTANCE(image_instance);
1656 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1658 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1659 case IMAGE_MONO_PIXMAP:
1660 case IMAGE_COLOR_PIXMAP:
1662 return XIMAGE_INSTANCE_PIXMAP_FILENAME(image_instance);
1667 case IMAGE_SUBWINDOW:
1674 DEFUN("image-instance-mask-file-name", Fimage_instance_mask_file_name, 1, 1, 0, /*
1675 Return the file name from which IMAGE-INSTANCE's mask was read, if known.
1679 CHECK_IMAGE_INSTANCE(image_instance);
1680 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1682 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1683 case IMAGE_MONO_PIXMAP:
1684 case IMAGE_COLOR_PIXMAP:
1686 return XIMAGE_INSTANCE_PIXMAP_MASK_FILENAME(image_instance);
1691 case IMAGE_SUBWINDOW:
1698 DEFUN("image-instance-depth", Fimage_instance_depth, 1, 1, 0, /*
1699 Return the depth of the image instance.
1700 This is 0 for a bitmap, or a positive integer for a pixmap.
1704 CHECK_IMAGE_INSTANCE(image_instance);
1705 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1707 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1708 case IMAGE_MONO_PIXMAP:
1709 case IMAGE_COLOR_PIXMAP:
1711 return make_int(XIMAGE_INSTANCE_PIXMAP_DEPTH(image_instance));
1716 case IMAGE_SUBWINDOW:
1723 DEFUN("image-instance-height", Fimage_instance_height, 1, 1, 0, /*
1724 Return the height of the image instance, in pixels.
1728 CHECK_IMAGE_INSTANCE(image_instance);
1729 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1731 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1732 case IMAGE_MONO_PIXMAP:
1733 case IMAGE_COLOR_PIXMAP:
1735 case IMAGE_SUBWINDOW:
1737 return make_int(XIMAGE_INSTANCE_HEIGHT(image_instance));
1747 DEFUN("image-instance-width", Fimage_instance_width, 1, 1, 0, /*
1748 Return the width of the image instance, in pixels.
1752 CHECK_IMAGE_INSTANCE(image_instance);
1753 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1755 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1756 case IMAGE_MONO_PIXMAP:
1757 case IMAGE_COLOR_PIXMAP:
1759 case IMAGE_SUBWINDOW:
1761 return make_int(XIMAGE_INSTANCE_WIDTH(image_instance));
1771 DEFUN("image-instance-hotspot-x", Fimage_instance_hotspot_x, 1, 1, 0, /*
1772 Return the X coordinate of the image instance's hotspot, if known.
1773 This is a point relative to the origin of the pixmap. When an image is
1774 used as a mouse pointer, the hotspot is the point on the image that sits
1775 over the location that the pointer points to. This is, for example, the
1776 tip of the arrow or the center of the crosshairs.
1777 This will always be nil for a non-pointer image instance.
1781 CHECK_IMAGE_INSTANCE(image_instance);
1782 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1784 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1785 case IMAGE_MONO_PIXMAP:
1786 case IMAGE_COLOR_PIXMAP:
1788 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_X(image_instance);
1793 case IMAGE_SUBWINDOW:
1800 DEFUN("image-instance-hotspot-y", Fimage_instance_hotspot_y, 1, 1, 0, /*
1801 Return the Y coordinate of the image instance's hotspot, if known.
1802 This is a point relative to the origin of the pixmap. When an image is
1803 used as a mouse pointer, the hotspot is the point on the image that sits
1804 over the location that the pointer points to. This is, for example, the
1805 tip of the arrow or the center of the crosshairs.
1806 This will always be nil for a non-pointer image instance.
1810 CHECK_IMAGE_INSTANCE(image_instance);
1811 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1813 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1814 case IMAGE_MONO_PIXMAP:
1815 case IMAGE_COLOR_PIXMAP:
1817 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(image_instance);
1822 case IMAGE_SUBWINDOW:
1829 DEFUN("image-instance-foreground", Fimage_instance_foreground, 1, 1, 0, /*
1830 Return the foreground color of IMAGE-INSTANCE, if applicable.
1831 This will be a color instance or nil. (It will only be non-nil for
1832 colorized mono pixmaps and for pointers.)
1836 CHECK_IMAGE_INSTANCE(image_instance);
1837 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1839 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1840 case IMAGE_MONO_PIXMAP:
1841 case IMAGE_COLOR_PIXMAP:
1843 return XIMAGE_INSTANCE_PIXMAP_FG(image_instance);
1847 FACE_FOREGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1848 XIMAGE_INSTANCE_FRAME(image_instance));
1853 case IMAGE_SUBWINDOW:
1859 DEFUN("image-instance-background", Fimage_instance_background, 1, 1, 0, /*
1860 Return the background color of IMAGE-INSTANCE, if applicable.
1861 This will be a color instance or nil. (It will only be non-nil for
1862 colorized mono pixmaps and for pointers.)
1866 CHECK_IMAGE_INSTANCE(image_instance);
1867 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1869 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1870 case IMAGE_MONO_PIXMAP:
1871 case IMAGE_COLOR_PIXMAP:
1873 return XIMAGE_INSTANCE_PIXMAP_BG(image_instance);
1877 FACE_BACKGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1878 XIMAGE_INSTANCE_FRAME(image_instance));
1883 case IMAGE_SUBWINDOW:
1889 DEFUN("colorize-image-instance", Fcolorize_image_instance, 3, 3, 0, /*
1890 Make the image instance be displayed in the given colors.
1891 This function returns a new image instance that is exactly like the
1892 specified one except that (if possible) the foreground and background
1893 colors and as specified. Currently, this only does anything if the image
1894 instance is a mono pixmap; otherwise, the same image instance is returned.
1896 (image_instance, foreground, background))
1901 CHECK_IMAGE_INSTANCE(image_instance);
1902 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1903 CHECK_COLOR_INSTANCE(foreground);
1904 CHECK_COLOR_INSTANCE(background);
1906 device = image_instance_device(image_instance);
1907 if (!HAS_DEVMETH_P(XDEVICE(device), colorize_image_instance))
1908 return image_instance;
1910 /* #### There should be a copy_image_instance(), which calls a
1911 device-specific method to copy the window-system subobject. */
1912 new = allocate_image_instance(XIMAGE_INSTANCE_DOMAIN(image_instance),
1914 copy_lcrecord(XIMAGE_INSTANCE(new), XIMAGE_INSTANCE(image_instance));
1915 /* note that if this method returns non-zero, this method MUST
1916 copy any window-system resources, so that when one image instance is
1917 freed, the other one is not hosed. */
1918 if (!DEVMETH(XDEVICE(device), colorize_image_instance, (new, foreground,
1920 return image_instance;
1924 /************************************************************************/
1925 /* Geometry calculations */
1926 /************************************************************************/
1928 /* Find out desired geometry of the image instance. If there is no
1929 special function then just return the width and / or height. */
1931 image_instance_query_geometry(Lisp_Object image_instance,
1932 int *width, int *height,
1933 enum image_instance_geometry disp,
1936 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1938 struct image_instantiator_methods *meths;
1939 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1941 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1942 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1944 if (meths && HAS_IIFORMAT_METH_P(meths, query_geometry)) {
1945 IIFORMAT_METH(meths, query_geometry,
1946 (image_instance, width, height, disp, domain));
1949 *width = IMAGE_INSTANCE_WIDTH(ii);
1951 *height = IMAGE_INSTANCE_HEIGHT(ii);
1955 /* Layout the image instance using the provided dimensions. Layout
1956 widgets are going to do different kinds of calculations to
1957 determine what size to give things so we could make the layout
1958 function relatively simple to take account of that. An alternative
1959 approach is to consider separately the two cases, one where you
1960 don't mind what size you have (normal widgets) and one where you
1961 want to specify something (layout widgets). */
1963 image_instance_layout(Lisp_Object image_instance,
1964 int width, int height,
1965 int xoffset, int yoffset, Lisp_Object domain)
1967 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1969 struct image_instantiator_methods *meths;
1971 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1973 /* Nothing is as nothing does. */
1974 if (NOTHING_IMAGE_INSTANCEP(image_instance))
1977 /* We don't want carefully calculated offsets to be mucked up by
1979 if (xoffset != IMAGE_UNCHANGED_GEOMETRY)
1980 XIMAGE_INSTANCE_XOFFSET(image_instance) = xoffset;
1981 if (yoffset != IMAGE_UNCHANGED_GEOMETRY)
1982 XIMAGE_INSTANCE_YOFFSET(image_instance) = yoffset;
1984 /* If geometry is unspecified then get some reasonable values for it. */
1985 if (width == IMAGE_UNSPECIFIED_GEOMETRY
1986 || height == IMAGE_UNSPECIFIED_GEOMETRY) {
1987 int dwidth = IMAGE_UNSPECIFIED_GEOMETRY;
1988 int dheight = IMAGE_UNSPECIFIED_GEOMETRY;
1989 /* Get the desired geometry. */
1990 image_instance_query_geometry(image_instance,
1992 IMAGE_DESIRED_GEOMETRY, domain);
1993 /* Compare with allowed geometry. */
1994 if (width == IMAGE_UNSPECIFIED_GEOMETRY)
1996 if (height == IMAGE_UNSPECIFIED_GEOMETRY)
2000 /* If we don't have sane values then we cannot layout at this point and
2001 must just return. */
2002 if (width == IMAGE_UNSPECIFIED_GEOMETRY
2003 || height == IMAGE_UNSPECIFIED_GEOMETRY)
2006 /* At this point width and height should contain sane values. Thus
2007 we set the glyph geometry and lay it out. */
2008 if (IMAGE_INSTANCE_WIDTH(ii) != width
2009 || IMAGE_INSTANCE_HEIGHT(ii) != height) {
2010 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
2013 IMAGE_INSTANCE_WIDTH(ii) = width;
2014 IMAGE_INSTANCE_HEIGHT(ii) = height;
2016 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2017 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2019 MAYBE_IIFORMAT_METH(meths, layout,
2020 (image_instance, width, height, xoffset, yoffset,
2022 /* Do not clear the dirty flag here - redisplay will do this for
2024 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 0;
2027 /* Update an image instance from its changed instantiator. */
2029 update_image_instance(Lisp_Object image_instance, Lisp_Object instantiator)
2031 struct image_instantiator_methods *meths;
2032 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2034 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
2036 if (NOTHING_IMAGE_INSTANCEP(image_instance))
2039 assert(!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2041 (internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2042 && internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator,
2045 /* If the instantiator is identical then do nothing. We must use
2046 equal here because the specifier code copies the instantiator. */
2047 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)) {
2048 /* Extract the changed properties so that device / format
2049 methods only have to cope with these. We assume that
2050 normalization has already been done. */
2051 Lisp_Object diffs = find_instantiator_differences(instantiator,
2052 IMAGE_INSTANCE_INSTANTIATOR
2055 encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2056 struct gcpro gcpro1;
2059 /* try device specific methods first ... */
2061 decode_device_ii_format(image_instance_device
2062 (image_instance), type,
2064 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2065 /* ... then format specific methods ... */
2066 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2067 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2069 /* Instance and therefore glyph has changed so mark as dirty.
2070 If we don't do this output optimizations will assume the
2071 glyph is unchanged. */
2072 set_image_instance_dirty_p(image_instance, 1);
2073 /* Structure has changed. */
2074 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2078 /* We should now have a consistent instantiator so keep a record of
2079 it. It is important that we don't actually update the window
2080 system widgets here - we must do that when redisplay tells us
2083 #### should we delay doing this until the display is up-to-date
2085 IMAGE_INSTANCE_INSTANTIATOR(ii) = instantiator;
2089 * Mark image instance in W as dirty if (a) W's faces have changed and
2090 * (b) GLYPH_OR_II instance in W is a string.
2092 * Return non-zero if instance has been marked dirty.
2094 int invalidate_glyph_geometry_maybe(Lisp_Object glyph_or_ii, struct window *w)
2096 if (XFRAME(WINDOW_FRAME(w))->faces_changed) {
2097 Lisp_Object image = glyph_or_ii;
2099 if (GLYPHP(glyph_or_ii)) {
2101 XSETWINDOW(window, w);
2103 glyph_image_instance(glyph_or_ii, window,
2107 if (TEXT_IMAGE_INSTANCEP(image)) {
2108 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image);
2109 IMAGE_INSTANCE_DIRTYP(ii) = 1;
2110 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2111 if (GLYPHP(glyph_or_ii))
2112 XGLYPH_DIRTYP(glyph_or_ii) = 1;
2120 /************************************************************************/
2122 /************************************************************************/
2123 DOESNT_RETURN signal_image_error(const char *reason, Lisp_Object frob)
2125 signal_error(Qimage_conversion_error,
2126 list2(build_translated_string(reason), frob));
2130 signal_image_error_2(const char *reason, Lisp_Object frob0, Lisp_Object frob1)
2132 signal_error(Qimage_conversion_error,
2133 list3(build_translated_string(reason), frob0, frob1));
2136 /****************************************************************************
2138 ****************************************************************************/
2140 static int nothing_possible_dest_types(void)
2142 return IMAGE_NOTHING_MASK;
2146 nothing_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2147 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2148 int dest_mask, Lisp_Object domain)
2150 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2152 if (dest_mask & IMAGE_NOTHING_MASK) {
2153 IMAGE_INSTANCE_TYPE(ii) = IMAGE_NOTHING;
2154 IMAGE_INSTANCE_HEIGHT(ii) = 0;
2155 IMAGE_INSTANCE_WIDTH(ii) = 0;
2157 incompatible_image_types(instantiator, dest_mask,
2158 IMAGE_NOTHING_MASK);
2161 /****************************************************************************
2163 ****************************************************************************/
2165 static void inherit_validate(Lisp_Object instantiator)
2167 face_must_be_present(instantiator);
2171 inherit_normalize(Lisp_Object inst, Lisp_Object console_type,
2172 Lisp_Object dest_mask)
2176 assert(XVECTOR_LENGTH(inst) == 3);
2177 face = XVECTOR_DATA(inst)[2];
2179 inst = vector3(Qinherit, Q_face, Fget_face(face));
2183 static int inherit_possible_dest_types(void)
2185 return IMAGE_MONO_PIXMAP_MASK;
2189 inherit_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2190 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2191 int dest_mask, Lisp_Object domain)
2193 /* handled specially in image_instantiate */
2197 /****************************************************************************
2199 ****************************************************************************/
2201 static void string_validate(Lisp_Object instantiator)
2203 data_must_be_present(instantiator);
2206 static int string_possible_dest_types(void)
2208 return IMAGE_TEXT_MASK;
2211 /* Called from autodetect_instantiate() */
2213 string_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2214 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2215 int dest_mask, Lisp_Object domain)
2217 Lisp_Object string = find_keyword_in_vector(instantiator, Q_data);
2218 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2220 /* Should never get here with a domain other than a window. */
2221 assert(!NILP(string) && WINDOWP(DOMAIN_WINDOW(domain)));
2222 if (dest_mask & IMAGE_TEXT_MASK) {
2223 IMAGE_INSTANCE_TYPE(ii) = IMAGE_TEXT;
2224 IMAGE_INSTANCE_TEXT_STRING(ii) = string;
2226 incompatible_image_types(instantiator, dest_mask,
2230 /* Sort out the size of the text that is being displayed. Calculating
2231 it dynamically allows us to change the text and still see
2232 everything. Note that the following methods are for text not string
2233 since that is what the instantiated type is. The first method is a
2234 helper that is used elsewhere for calculating text geometry. */
2236 query_string_geometry(Lisp_Object string, Lisp_Object face,
2237 int *width, int *height, int *descent, Lisp_Object domain)
2239 struct font_metric_info fm;
2240 unsigned char charsets[NUM_LEADING_BYTES];
2241 struct face_cachel frame_cachel;
2242 struct face_cachel *cachel;
2243 Lisp_Object frame = DOMAIN_FRAME(domain);
2245 CHECK_STRING(string);
2247 /* Compute height */
2249 /* Compute string metric info */
2250 find_charsets_in_bufbyte_string(charsets,
2251 XSTRING_DATA(string),
2252 XSTRING_LENGTH(string));
2254 /* Fallback to the default face if none was provided. */
2256 reset_face_cachel(&frame_cachel);
2257 update_face_cachel_data(&frame_cachel, frame, face);
2258 cachel = &frame_cachel;
2260 cachel = WINDOW_FACE_CACHEL(DOMAIN_XWINDOW(domain),
2264 ensure_face_cachel_complete(cachel, domain, charsets);
2265 face_cachel_charset_font_metric_info(cachel, charsets, &fm);
2267 *height = fm.ascent + fm.descent;
2268 /* #### descent only gets set if we query the height as well. */
2270 *descent = fm.descent;
2277 redisplay_frame_text_width_string(XFRAME(frame),
2282 redisplay_frame_text_width_string(XFRAME(frame),
2289 query_string_font(Lisp_Object string, Lisp_Object face, Lisp_Object domain)
2291 unsigned char charsets[NUM_LEADING_BYTES];
2292 struct face_cachel frame_cachel;
2293 struct face_cachel *cachel;
2295 Lisp_Object frame = DOMAIN_FRAME(domain);
2297 /* Compute string font info */
2298 find_charsets_in_bufbyte_string(charsets,
2299 XSTRING_DATA(string),
2300 XSTRING_LENGTH(string));
2302 reset_face_cachel(&frame_cachel);
2303 update_face_cachel_data(&frame_cachel, frame, face);
2304 cachel = &frame_cachel;
2306 ensure_face_cachel_complete(cachel, domain, charsets);
2308 for (i = 0; i < NUM_LEADING_BYTES; i++) {
2311 CHARSET_BY_LEADING_BYTE(i + MIN_LEADING_BYTE);
2312 return FACE_CACHEL_FONT(cachel, tmp);
2316 return Qnil; /* NOT REACHED */
2320 text_query_geometry(Lisp_Object image_instance,
2321 int *width, int *height,
2322 enum image_instance_geometry disp, Lisp_Object domain)
2324 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2327 query_string_geometry(IMAGE_INSTANCE_TEXT_STRING(ii),
2328 IMAGE_INSTANCE_FACE(ii),
2329 width, height, &descent, domain);
2331 /* The descent gets set as a side effect of querying the
2333 IMAGE_INSTANCE_TEXT_DESCENT(ii) = descent;
2336 /* set the properties of a string */
2337 static void text_update(Lisp_Object image_instance, Lisp_Object instantiator)
2339 Lisp_Object val = find_keyword_in_vector(instantiator, Q_data);
2343 XIMAGE_INSTANCE_TEXT_STRING(image_instance) = val;
2347 /****************************************************************************
2348 * formatted-string *
2349 ****************************************************************************/
2351 static void formatted_string_validate(Lisp_Object instantiator)
2353 data_must_be_present(instantiator);
2356 static int formatted_string_possible_dest_types(void)
2358 return IMAGE_TEXT_MASK;
2362 formatted_string_instantiate(Lisp_Object image_instance,
2363 Lisp_Object instantiator,
2364 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2365 int dest_mask, Lisp_Object domain)
2367 /* #### implement this */
2368 warn_when_safe(Qunimplemented, Qnotice,
2369 "`formatted-string' not yet implemented; assuming `string'");
2371 string_instantiate(image_instance, instantiator,
2372 pointer_fg, pointer_bg, dest_mask, domain);
2375 /************************************************************************/
2376 /* pixmap file functions */
2377 /************************************************************************/
2379 /* If INSTANTIATOR refers to inline data, return Qnil.
2380 If INSTANTIATOR refers to data in a file, return the full filename
2381 if it exists; otherwise, return a cons of (filename).
2383 FILE_KEYWORD and DATA_KEYWORD are symbols specifying the
2384 keywords used to look up the file and inline data,
2385 respectively, in the instantiator. Normally these would
2386 be Q_file and Q_data, but might be different for mask data. */
2389 potential_pixmap_file_instantiator(Lisp_Object instantiator,
2390 Lisp_Object file_keyword,
2391 Lisp_Object data_keyword,
2392 Lisp_Object console_type)
2397 assert(VECTORP(instantiator));
2399 data = find_keyword_in_vector(instantiator, data_keyword);
2400 file = find_keyword_in_vector(instantiator, file_keyword);
2402 if (!NILP(file) && NILP(data)) {
2403 Lisp_Object retval = MAYBE_LISP_CONTYPE_METH
2404 (decode_console_type(console_type, ERROR_ME),
2405 locate_pixmap_file, (file));
2410 return Fcons(file, Qnil); /* should have been file */
2417 simple_image_type_normalize(Lisp_Object inst, Lisp_Object console_type,
2418 Lisp_Object image_type_tag)
2420 /* This function can call lisp */
2421 Lisp_Object file = Qnil;
2422 struct gcpro gcpro1, gcpro2;
2423 Lisp_Object alist = Qnil;
2425 GCPRO2(file, alist);
2427 /* Now, convert any file data into inline data. At the end of this,
2428 `data' will contain the inline data (if any) or Qnil, and `file'
2429 will contain the name this data was derived from (if known) or
2432 Note that if we cannot generate any regular inline data, we
2435 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2438 if (CONSP(file)) /* failure locating filename */
2439 signal_double_file_error("Opening pixmap file",
2440 "no such file or directory",
2443 if (NILP(file)) /* no conversion necessary */
2444 RETURN_UNGCPRO(inst);
2446 alist = tagged_vector_to_alist(inst);
2449 Lisp_Object data = make_string_from_file(file);
2450 alist = remassq_no_quit(Q_file, alist);
2451 /* there can't be a :data at this point. */
2452 alist = Fcons(Fcons(Q_file, file),
2453 Fcons(Fcons(Q_data, data), alist));
2457 Lisp_Object result =
2458 alist_to_tagged_vector(image_type_tag, alist);
2460 RETURN_UNGCPRO(result);
2464 #ifdef HAVE_WINDOW_SYSTEM
2465 /**********************************************************************
2467 **********************************************************************/
2469 /* Check if DATA represents a valid inline XBM spec (i.e. a list
2470 of (width height bits), with checking done on the dimensions).
2471 If not, signal an error. */
2473 static void check_valid_xbm_inline(Lisp_Object data)
2475 Lisp_Object width, height, bits;
2478 !CONSP(XCDR(data)) ||
2479 !CONSP(XCDR(XCDR(data))) || !NILP(XCDR(XCDR(XCDR(data)))))
2480 signal_simple_error("Must be list of 3 elements", data);
2483 height = XCAR(XCDR(data));
2484 bits = XCAR(XCDR(XCDR(data)));
2488 if (!NATNUMP(width))
2489 signal_simple_error("Width must be a natural number", width);
2491 if (!NATNUMP(height))
2492 signal_simple_error("Height must be a natural number", height);
2494 if (((XINT(width) * XINT(height)) / 8) > XSTRING_CHAR_LENGTH(bits))
2495 signal_simple_error("data is too short for width and height",
2496 vector3(width, height, bits));
2499 /* Validate method for XBM's. */
2501 static void xbm_validate(Lisp_Object instantiator)
2503 file_or_data_must_be_present(instantiator);
2506 /* Given a filename that is supposed to contain XBM data, return
2507 the inline representation of it as (width height bits). Return
2508 the hotspot through XHOT and YHOT, if those pointers are not 0.
2509 If there is no hotspot, XHOT and YHOT will contain -1.
2511 If the function fails:
2513 -- if OK_IF_DATA_INVALID is set and the data was invalid,
2515 -- maybe return an error, or return Qnil.
2518 #ifdef HAVE_X_WINDOWS
2519 #include <X11/Xlib.h>
2521 #define XFree(data) free(data)
2525 bitmap_to_lisp_data(Lisp_Object name, int *xhot, int *yhot,
2526 int ok_if_data_invalid)
2531 const char *filename_ext;
2533 LISP_STRING_TO_EXTERNAL(name, filename_ext, Qfile_name);
2534 result = read_bitmap_data_from_file(filename_ext, &w, &h,
2535 (unsigned char **)((void*)&data),
2538 if (result == BitmapSuccess) {
2540 int len = (w + 7) / 8 * h;
2542 retval = list3(make_int(w), make_int(h),
2543 make_ext_string(data, len, Qbinary));
2549 case BitmapOpenFailed:
2551 /* should never happen */
2552 signal_double_file_error("Opening bitmap file",
2553 "no such file or directory",
2556 case BitmapFileInvalid:
2558 if (ok_if_data_invalid)
2560 signal_double_file_error("Reading bitmap file",
2561 "invalid data in file", name);
2563 case BitmapNoMemory:
2565 signal_double_file_error("Reading bitmap file",
2566 "out of memory", name);
2570 signal_double_file_error_2("Reading bitmap file",
2571 "unknown error code",
2572 make_int(result), name);
2576 return Qnil; /* not reached */
2580 xbm_mask_file_munging(Lisp_Object alist, Lisp_Object file,
2581 Lisp_Object mask_file, Lisp_Object console_type)
2583 /* This is unclean but it's fairly standard -- a number of the
2584 bitmaps in /usr/include/X11/bitmaps use it -- so we support
2587 /* don't override explicitly specified mask data. */
2588 && NILP(assq_no_quit(Q_mask_data, alist))
2590 mask_file = MAYBE_LISP_CONTYPE_METH
2591 (decode_console_type(console_type, ERROR_ME),
2592 locate_pixmap_file, (concat2(file, build_string("Mask"))));
2593 if (NILP(mask_file))
2594 mask_file = MAYBE_LISP_CONTYPE_METH
2595 (decode_console_type(console_type, ERROR_ME),
2597 (concat2(file, build_string("msk"))));
2600 if (!NILP(mask_file)) {
2601 Lisp_Object mask_data = bitmap_to_lisp_data(mask_file, 0, 0, 0);
2602 alist = remassq_no_quit(Q_mask_file, alist);
2603 /* there can't be a :mask-data at this point. */
2604 alist = Fcons(Fcons(Q_mask_file, mask_file),
2605 Fcons(Fcons(Q_mask_data, mask_data), alist));
2611 /* Normalize method for XBM's. */
2614 xbm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2616 Lisp_Object file = Qnil, mask_file = Qnil;
2617 struct gcpro gcpro1, gcpro2, gcpro3;
2618 Lisp_Object alist = Qnil;
2620 GCPRO3(file, mask_file, alist);
2622 /* Now, convert any file data into inline data for both the regular
2623 data and the mask data. At the end of this, `data' will contain
2624 the inline data (if any) or Qnil, and `file' will contain
2625 the name this data was derived from (if known) or Qnil.
2626 Likewise for `mask_file' and `mask_data'.
2628 Note that if we cannot generate any regular inline data, we
2631 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2633 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2637 if (CONSP(file)) /* failure locating filename */
2638 signal_double_file_error("Opening bitmap file",
2639 "no such file or directory",
2642 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2643 RETURN_UNGCPRO(inst);
2645 alist = tagged_vector_to_alist(inst);
2649 Lisp_Object data = bitmap_to_lisp_data(file, &xhot, &yhot, 0);
2650 alist = remassq_no_quit(Q_file, alist);
2651 /* there can't be a :data at this point. */
2652 alist = Fcons(Fcons(Q_file, file),
2653 Fcons(Fcons(Q_data, data), alist));
2655 if (xhot != -1 && NILP(assq_no_quit(Q_hotspot_x, alist)))
2656 alist = Fcons(Fcons(Q_hotspot_x, make_int(xhot)),
2658 if (yhot != -1 && NILP(assq_no_quit(Q_hotspot_y, alist)))
2659 alist = Fcons(Fcons(Q_hotspot_y, make_int(yhot)),
2663 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2666 Lisp_Object result = alist_to_tagged_vector(Qxbm, alist);
2668 RETURN_UNGCPRO(result);
2672 static int xbm_possible_dest_types(void)
2675 IMAGE_MONO_PIXMAP_MASK |
2676 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2682 /**********************************************************************
2684 **********************************************************************/
2686 static void xface_validate(Lisp_Object instantiator)
2688 file_or_data_must_be_present(instantiator);
2692 xface_normalize(Lisp_Object inst, Lisp_Object console_type,
2693 Lisp_Object dest_mask)
2695 /* This function can call lisp */
2696 Lisp_Object file = Qnil, mask_file = Qnil;
2697 struct gcpro gcpro1, gcpro2, gcpro3;
2698 Lisp_Object alist = Qnil;
2700 GCPRO3(file, mask_file, alist);
2702 /* Now, convert any file data into inline data for both the regular
2703 data and the mask data. At the end of this, `data' will contain
2704 the inline data (if any) or Qnil, and `file' will contain
2705 the name this data was derived from (if known) or Qnil.
2706 Likewise for `mask_file' and `mask_data'.
2708 Note that if we cannot generate any regular inline data, we
2711 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2713 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2717 if (CONSP(file)) /* failure locating filename */
2718 signal_double_file_error("Opening bitmap file",
2719 "no such file or directory",
2722 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2723 RETURN_UNGCPRO(inst);
2725 #ifdef HAVE_WINDOW_SYSTEM
2726 alist = tagged_vector_to_alist(inst);
2729 Lisp_Object data = make_string_from_file(file);
2730 alist = remassq_no_quit(Q_file, alist);
2731 /* there can't be a :data at this point. */
2732 alist = Fcons(Fcons(Q_file, file),
2733 Fcons(Fcons(Q_data, data), alist));
2736 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2739 Lisp_Object result = alist_to_tagged_vector(Qxface, alist);
2741 RETURN_UNGCPRO(result);
2744 RETURN_UNGCPRO(Qnil);
2748 static int xface_possible_dest_types(void)
2751 IMAGE_MONO_PIXMAP_MASK |
2752 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2755 #endif /* HAVE_XFACE */
2759 /**********************************************************************
2761 **********************************************************************/
2763 Lisp_Object pixmap_to_lisp_data(Lisp_Object name, int ok_if_data_invalid)
2769 LISP_STRING_TO_EXTERNAL(name, fname, Qfile_name);
2770 result = XpmReadFileToData(fname, &data);
2772 if (result == XpmSuccess) {
2773 Lisp_Object retval = Qnil;
2774 struct buffer *old_buffer = current_buffer;
2775 Lisp_Object temp_buffer =
2776 Fget_buffer_create(build_string(" *pixmap conversion*"));
2778 int height, width, ncolors;
2779 struct gcpro gcpro1, gcpro2, gcpro3;
2780 int speccount = specpdl_depth();
2782 GCPRO3(name, retval, temp_buffer);
2784 specbind(Qinhibit_quit, Qt);
2785 set_buffer_internal(XBUFFER(temp_buffer));
2786 Ferase_buffer(Qnil);
2788 buffer_insert_c_string(current_buffer, "/* XPM */\r");
2789 buffer_insert_c_string(current_buffer,
2790 "static char *pixmap[] = {\r");
2792 sscanf(data[0], "%d %d %d", &height, &width, &ncolors);
2793 for (elt = 0; elt <= width + ncolors; elt++) {
2794 buffer_insert_c_string(current_buffer, "\"");
2795 buffer_insert_c_string(current_buffer, data[elt]);
2797 if (elt < width + ncolors)
2798 buffer_insert_c_string(current_buffer, "\",\r");
2800 buffer_insert_c_string(current_buffer,
2804 retval = Fbuffer_substring(Qnil, Qnil, Qnil);
2807 set_buffer_internal(old_buffer);
2808 unbind_to(speccount, Qnil);
2810 RETURN_UNGCPRO(retval);
2814 case XpmFileInvalid:
2816 if (ok_if_data_invalid)
2818 signal_image_error("invalid XPM data in file", name);
2822 signal_double_file_error("Reading pixmap file",
2823 "out of memory", name);
2827 /* should never happen? */
2828 signal_double_file_error("Opening pixmap file",
2829 "no such file or directory",
2834 signal_double_file_error_2("Parsing pixmap file",
2835 "unknown error code",
2836 make_int(result), name);
2841 return Qnil; /* not reached */
2844 static void check_valid_xpm_color_symbols(Lisp_Object data)
2848 for (rest = data; !NILP(rest); rest = XCDR(rest)) {
2850 !CONSP(XCAR(rest)) ||
2851 !STRINGP(XCAR(XCAR(rest))) ||
2852 (!STRINGP(XCDR(XCAR(rest))) &&
2853 !COLOR_SPECIFIERP(XCDR(XCAR(rest)))))
2854 signal_simple_error("Invalid color symbol alist", data);
2858 static void xpm_validate(Lisp_Object instantiator)
2860 file_or_data_must_be_present(instantiator);
2863 Lisp_Object Vxpm_color_symbols;
2865 Lisp_Object evaluate_xpm_color_symbols(void)
2867 Lisp_Object rest, results = Qnil;
2868 struct gcpro gcpro1, gcpro2;
2870 GCPRO2(rest, results);
2871 for (rest = Vxpm_color_symbols; !NILP(rest); rest = XCDR(rest)) {
2872 Lisp_Object name, value, cons;
2881 value = XCAR(value);
2882 value = Feval(value);
2885 if (!STRINGP(value) && !COLOR_SPECIFIERP(value))
2887 ("Result from xpm-color-symbols eval must be nil, string, or color",
2889 results = Fcons(Fcons(name, value), results);
2891 UNGCPRO; /* no more evaluation */
2896 xpm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2898 Lisp_Object file = Qnil;
2899 Lisp_Object color_symbols;
2900 struct gcpro gcpro1, gcpro2;
2901 Lisp_Object alist = Qnil;
2903 GCPRO2(file, alist);
2905 /* Now, convert any file data into inline data. At the end of this,
2906 `data' will contain the inline data (if any) or Qnil, and
2907 `file' will contain the name this data was derived from (if
2910 Note that if we cannot generate any regular inline data, we
2913 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2916 if (CONSP(file)) /* failure locating filename */
2917 signal_double_file_error("Opening pixmap file",
2918 "no such file or directory",
2921 color_symbols = find_keyword_in_vector_or_given(inst, Q_color_symbols,
2924 if (NILP(file) && !UNBOUNDP(color_symbols))
2925 /* no conversion necessary */
2926 RETURN_UNGCPRO(inst);
2928 alist = tagged_vector_to_alist(inst);
2931 Lisp_Object data = pixmap_to_lisp_data(file, 0);
2932 alist = remassq_no_quit(Q_file, alist);
2933 /* there can't be a :data at this point. */
2934 alist = Fcons(Fcons(Q_file, file),
2935 Fcons(Fcons(Q_data, data), alist));
2938 if (UNBOUNDP(color_symbols)) {
2939 color_symbols = evaluate_xpm_color_symbols();
2940 alist = Fcons(Fcons(Q_color_symbols, color_symbols), alist);
2944 Lisp_Object result = alist_to_tagged_vector(Qxpm, alist);
2946 RETURN_UNGCPRO(result);
2950 static int xpm_possible_dest_types(void)
2953 IMAGE_MONO_PIXMAP_MASK |
2954 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2957 #endif /* HAVE_XPM */
2959 /****************************************************************************
2960 * Image Specifier Object *
2961 ****************************************************************************/
2963 DEFINE_SPECIFIER_TYPE(image);
2965 static void image_create(Lisp_Object obj)
2967 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2969 IMAGE_SPECIFIER_ALLOWED(image) = ~0; /* all are allowed */
2970 IMAGE_SPECIFIER_ATTACHEE(image) = Qnil;
2971 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = Qnil;
2974 static void image_mark(Lisp_Object obj)
2976 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2978 mark_object(IMAGE_SPECIFIER_ATTACHEE(image));
2979 mark_object(IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image));
2982 static int instantiator_eq_equal(Lisp_Object obj1, Lisp_Object obj2)
2987 else if (CONSP(obj1) && CONSP(obj2)) {
2988 return instantiator_eq_equal(XCAR(obj1), XCAR(obj2))
2989 && instantiator_eq_equal(XCDR(obj1), XCDR(obj2));
2994 static hcode_t instantiator_eq_hash(Lisp_Object obj)
2997 /* no point in worrying about tail recursion, since we're not
2999 return HASH2(instantiator_eq_hash(XCAR(obj)),
3000 instantiator_eq_hash(XCDR(obj)));
3002 return LISP_HASH(obj);
3005 /* We need a special hash table for storing image instances. */
3006 Lisp_Object make_image_instance_cache_hash_table(void)
3008 return make_general_lisp_hash_table
3009 (instantiator_eq_hash, instantiator_eq_equal,
3010 30, -1.0, -1.0, HASH_TABLE_KEY_CAR_VALUE_WEAK);
3013 static Lisp_Object image_instantiate_cache_result(Lisp_Object locative)
3015 /* locative = (instance instantiator . subtable)
3017 So we are using the instantiator as the key and the instance as
3018 the value. Since the hashtable is key-weak this means that the
3019 image instance will stay around as long as the instantiator stays
3020 around. The instantiator is stored in the `image' slot of the
3021 glyph, so as long as the glyph is marked the instantiator will be
3022 as well and hence the cached image instance also. */
3023 Fputhash(XCAR(XCDR(locative)), XCAR(locative), XCDR(XCDR(locative)));
3024 free_cons(XCONS(XCDR(locative)));
3025 free_cons(XCONS(locative));
3029 /* Given a specification for an image, return an instance of
3030 the image which matches the given instantiator and which can be
3031 displayed in the given domain. */
3034 image_instantiate(Lisp_Object specifier, Lisp_Object matchspec,
3035 Lisp_Object domain, Lisp_Object instantiator,
3039 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3040 int dest_mask = XIMAGE_SPECIFIER_ALLOWED(specifier);
3041 int pointerp = dest_mask & image_instance_type_to_mask(IMAGE_POINTER);
3043 if (IMAGE_INSTANCEP(instantiator)) {
3044 /* make sure that the image instance's governing domain and type are
3046 Lisp_Object governing_domain =
3047 XIMAGE_INSTANCE_DOMAIN(instantiator);
3049 if ((DEVICEP(governing_domain)
3050 && EQ(governing_domain, DOMAIN_DEVICE(domain)))
3051 || (FRAMEP(governing_domain)
3052 && EQ(governing_domain, DOMAIN_FRAME(domain)))
3053 || (WINDOWP(governing_domain)
3054 && EQ(governing_domain, DOMAIN_WINDOW(domain)))) {
3056 image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE
3058 if (mask & dest_mask)
3059 return instantiator;
3062 ("Type of image instance not allowed here",
3065 signal_simple_error_2("Wrong domain for image instance",
3066 instantiator, domain);
3068 /* How ugly !! An image instanciator that uses a kludgy syntax to snarf in
3069 face properties. There's a design flaw here. -- didier */
3070 else if (VECTORP(instantiator)
3071 && EQ(INSTANTIATOR_TYPE(instantiator), Qinherit)) {
3072 assert(XVECTOR_LENGTH(instantiator) == 3);
3073 return (FACE_PROPERTY_INSTANCE
3074 (Fget_face(XVECTOR_DATA(instantiator)[2]),
3075 Qbackground_pixmap, domain, 1, depth));
3077 Lisp_Object instance = Qnil;
3078 Lisp_Object subtable = Qnil;
3079 /* #### Should this be GCPRO'd? */
3080 Lisp_Object hash_key = Qnil;
3081 Lisp_Object pointer_fg = Qnil;
3082 Lisp_Object pointer_bg = Qnil;
3083 Lisp_Object governing_domain =
3084 get_image_instantiator_governing_domain(instantiator,
3086 struct gcpro gcpro1;
3090 /* We have to put subwindow, widget and text image instances in
3091 a per-window cache so that we can see the same glyph in
3092 different windows. We use governing_domain to determine the type
3093 of image_instance that will be created. */
3096 pointer_fg = FACE_FOREGROUND(Vpointer_face, domain);
3097 pointer_bg = FACE_BACKGROUND(Vpointer_face, domain);
3098 hash_key = list4(glyph, INSTANTIATOR_TYPE(instantiator),
3099 pointer_fg, pointer_bg);
3101 /* We cannot simply key on the glyph since fallbacks could use
3102 the same glyph but have a totally different instantiator
3103 type. Thus we key on the glyph and the type (but not any
3104 other parts of the instantiator. */
3106 list2(glyph, INSTANTIATOR_TYPE(instantiator));
3108 /* First look in the device cache. */
3109 if (DEVICEP(governing_domain)) {
3110 subtable = Fgethash(make_int(dest_mask),
3111 XDEVICE(governing_domain)->
3112 image_instance_cache, Qunbound);
3113 if (UNBOUNDP(subtable)) {
3114 /* For the image instance cache, we do comparisons with
3115 EQ rather than with EQUAL, as we do for color and
3116 font names. The reasons are:
3118 1) pixmap data can be very long, and thus the hashing
3119 and comparing will take awhile.
3121 2) It's not so likely that we'll run into things that
3122 are EQUAL but not EQ (that can happen a lot with
3123 faces, because their specifiers are copied around);
3124 but pixmaps tend not to be in faces.
3126 However, if the image-instance could be a pointer, we
3127 have to use EQUAL because we massaged the
3128 instantiator into a cons3 also containing the
3129 foreground and background of the pointer face. */
3131 make_image_instance_cache_hash_table();
3133 Fputhash(make_int(dest_mask), subtable,
3134 XDEVICE(governing_domain)->
3135 image_instance_cache);
3136 instance = Qunbound;
3139 Fgethash(hash_key, subtable, Qunbound);
3141 } else if (WINDOWP(governing_domain)) {
3142 /* Subwindows have a per-window cache and have to be treated
3146 XWINDOW(governing_domain)->
3147 subwindow_instance_cache, Qunbound);
3149 abort(); /* We're not allowed anything else currently. */
3151 /* If we don't have an instance at this point then create
3153 if (UNBOUNDP(instance)) {
3154 Lisp_Object locative = noseeum_cons(Qnil,
3163 subwindow_instance_cache));
3164 int speccount = specpdl_depth();
3166 /* Make sure we cache the failures, too. Use an
3167 unwind-protect to catch such errors. If we fail, the
3168 unwind-protect records nil in the hash table. If we
3169 succeed, we change the car of the locative to the
3170 resulting instance, which gets recorded instead. */
3171 record_unwind_protect(image_instantiate_cache_result,
3174 instantiate_image_instantiator(governing_domain,
3175 domain, instantiator,
3180 /* We need a per-frame cache for redisplay. */
3181 cache_subwindow_instance_in_frame_maybe(instance);
3183 Fsetcar(locative, instance);
3184 #ifdef ERROR_CHECK_GLYPHS
3185 if (image_instance_type_to_mask
3186 (XIMAGE_INSTANCE_TYPE(instance))
3187 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3188 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3189 DOMAIN_FRAME(domain)));
3191 unbind_to(speccount, Qnil);
3192 #ifdef ERROR_CHECK_GLYPHS
3193 if (image_instance_type_to_mask
3194 (XIMAGE_INSTANCE_TYPE(instance))
3195 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3196 assert(EQ(Fgethash(hash_key,
3197 XWINDOW(governing_domain)
3198 ->subwindow_instance_cache,
3199 Qunbound), instance));
3201 } else if (NILP(instance))
3203 ("Can't instantiate image (probably cached)",
3205 /* We found an instance. However, because we are using the glyph
3206 as the hash key instead of the instantiator, the current
3207 instantiator may not be the same as the original. Thus we
3208 must update the instance based on the new
3209 instantiator. Preserving instance identity like this is
3210 important to stop excessive window system widget creation and
3211 deletion - and hence flashing. */
3213 /* #### This function should be able to cope with *all*
3214 changes to the instantiator, but currently only copes
3215 with the most used properties. This means that it is
3216 possible to make changes that don't get reflected in the
3218 update_image_instance(instance, instantiator);
3219 free_list(hash_key);
3222 #ifdef ERROR_CHECK_GLYPHS
3223 if (image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE(instance))
3224 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3225 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3226 DOMAIN_FRAME(domain)));
3228 ERROR_CHECK_IMAGE_INSTANCE(instance);
3229 RETURN_UNGCPRO(instance);
3233 return Qnil; /* not reached */
3236 /* Validate an image instantiator. */
3238 static void image_validate(Lisp_Object instantiator)
3240 if (IMAGE_INSTANCEP(instantiator) || STRINGP(instantiator))
3242 else if (VECTORP(instantiator)) {
3243 Lisp_Object *elt = XVECTOR_DATA(instantiator);
3244 int instantiator_len = XVECTOR_LENGTH(instantiator);
3245 struct image_instantiator_methods *meths;
3246 Lisp_Object already_seen = Qnil;
3247 struct gcpro gcpro1;
3250 if (instantiator_len < 1)
3251 signal_simple_error("Vector length must be at least 1",
3254 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3255 if (!(instantiator_len & 1))
3257 ("Must have alternating keyword/value pairs",
3260 GCPRO1(already_seen);
3262 for (i = 1; i < instantiator_len; i += 2) {
3263 Lisp_Object keyword = elt[i];
3264 Lisp_Object value = elt[i + 1];
3267 CHECK_SYMBOL(keyword);
3268 if (!SYMBOL_IS_KEYWORD(keyword))
3270 ("Symbol must begin with a colon", keyword);
3272 for (j = 0; j < Dynarr_length(meths->keywords); j++)
3275 Dynarr_at(meths->keywords, j).keyword))
3278 if (j == Dynarr_length(meths->keywords))
3279 signal_simple_error("Unrecognized keyword",
3282 if (!Dynarr_at(meths->keywords, j).multiple_p) {
3283 if (!NILP(memq_no_quit(keyword, already_seen)))
3285 ("Keyword may not appear more than once",
3287 already_seen = Fcons(keyword, already_seen);
3290 (Dynarr_at(meths->keywords, j).validate) (value);
3295 MAYBE_IIFORMAT_METH(meths, validate, (instantiator));
3297 signal_simple_error("Must be string or vector", instantiator);
3300 static void image_after_change(Lisp_Object specifier, Lisp_Object locale)
3302 Lisp_Object attachee =
3303 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3304 Lisp_Object property =
3305 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(XIMAGE_SPECIFIER(specifier));
3306 if (FACEP(attachee)) {
3307 face_property_was_changed(attachee, property, locale);
3308 if (BUFFERP(locale))
3309 XBUFFER(locale)->buffer_local_face_property = 1;
3310 } else if (GLYPHP(attachee))
3311 glyph_property_was_changed(attachee, property, locale);
3315 set_image_attached_to(Lisp_Object obj, Lisp_Object face_or_glyph,
3316 Lisp_Object property)
3318 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
3320 IMAGE_SPECIFIER_ATTACHEE(image) = face_or_glyph;
3321 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = property;
3325 image_going_to_add(Lisp_Object specifier, Lisp_Object locale,
3326 Lisp_Object tag_set, Lisp_Object instantiator)
3328 Lisp_Object possible_console_types = Qnil;
3330 Lisp_Object retlist = Qnil;
3331 struct gcpro gcpro1, gcpro2;
3333 LIST_LOOP(rest, Vconsole_type_list) {
3334 Lisp_Object contype = XCAR(rest);
3335 if (!NILP(memq_no_quit(contype, tag_set)))
3336 possible_console_types =
3337 Fcons(contype, possible_console_types);
3340 if (XINT(Flength(possible_console_types)) > 1)
3341 /* two conflicting console types specified */
3344 if (NILP(possible_console_types))
3345 possible_console_types = Vconsole_type_list;
3347 GCPRO2(retlist, possible_console_types);
3349 LIST_LOOP(rest, possible_console_types) {
3350 Lisp_Object contype = XCAR(rest);
3351 Lisp_Object newinst = call_with_suspended_errors
3352 ((lisp_fn_t) normalize_image_instantiator,
3353 Qnil, Qimage, ERROR_ME_NOT, 3, instantiator, contype,
3354 make_int(XIMAGE_SPECIFIER_ALLOWED(specifier)));
3356 if (!NILP(newinst)) {
3358 if (NILP(memq_no_quit(contype, tag_set)))
3359 newtag = Fcons(contype, tag_set);
3362 retlist = Fcons(Fcons(newtag, newinst), retlist);
3371 /* Copy an image instantiator. We can't use Fcopy_tree since widgets
3372 may contain circular references which would send Fcopy_tree into
3374 static Lisp_Object image_copy_vector_instantiator(Lisp_Object instantiator)
3377 struct image_instantiator_methods *meths;
3379 int instantiator_len;
3381 CHECK_VECTOR(instantiator);
3383 instantiator = Fcopy_sequence(instantiator);
3384 elt = XVECTOR_DATA(instantiator);
3385 instantiator_len = XVECTOR_LENGTH(instantiator);
3387 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3389 for (i = 1; i < instantiator_len; i += 2) {
3391 Lisp_Object keyword = elt[i];
3392 Lisp_Object value = elt[i + 1];
3394 /* Find the keyword entry. */
3395 for (j = 0; j < Dynarr_length(meths->keywords); j++) {
3396 if (EQ(keyword, Dynarr_at(meths->keywords, j).keyword))
3400 /* Only copy keyword values that should be copied. */
3401 if (Dynarr_at(meths->keywords, j).copy_p
3402 && (CONSP(value) || VECTORP(value))) {
3403 elt[i + 1] = Fcopy_tree(value, Qt);
3407 return instantiator;
3410 static Lisp_Object image_copy_instantiator(Lisp_Object arg)
3414 rest = arg = Fcopy_sequence(arg);
3415 while (CONSP(rest)) {
3416 Lisp_Object elt = XCAR(rest);
3418 XCAR(rest) = Fcopy_tree(elt, Qt);
3419 else if (VECTORP(elt))
3421 image_copy_vector_instantiator(elt);
3422 if (VECTORP(XCDR(rest))) /* hack for (a b . [c d]) */
3423 XCDR(rest) = Fcopy_tree(XCDR(rest), Qt);
3426 } else if (VECTORP(arg)) {
3427 arg = image_copy_vector_instantiator(arg);
3432 DEFUN("image-specifier-p", Fimage_specifier_p, 1, 1, 0, /*
3433 Return non-nil if OBJECT is an image specifier.
3434 See `make-image-specifier' for a description of image instantiators.
3438 return IMAGE_SPECIFIERP(object) ? Qt : Qnil;
3441 /****************************************************************************
3443 ****************************************************************************/
3445 static Lisp_Object mark_glyph(Lisp_Object obj)
3447 Lisp_Glyph *glyph = XGLYPH(obj);
3449 mark_object(glyph->image);
3450 mark_object(glyph->contrib_p);
3451 mark_object(glyph->baseline);
3452 mark_object(glyph->face);
3454 return glyph->plist;
3458 print_glyph(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
3460 Lisp_Glyph *glyph = XGLYPH(obj);
3462 error("printing unreadable object #<glyph 0x%x>",
3465 write_c_string("#<glyph (", printcharfun);
3466 print_internal(Fglyph_type(obj), printcharfun, 0);
3467 write_c_string(") ", printcharfun);
3468 print_internal(glyph->image, printcharfun, 1);
3469 write_fmt_str(printcharfun, "0x%x>", glyph->header.uid);
3472 /* Glyphs are equal if all of their display attributes are equal. We
3473 don't compare names or doc-strings, because that would make equal
3476 This isn't concerned with "unspecified" attributes, that's what
3477 #'glyph-differs-from-default-p is for. */
3478 static int glyph_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
3480 Lisp_Glyph *g1 = XGLYPH(obj1);
3481 Lisp_Glyph *g2 = XGLYPH(obj2);
3485 return (internal_equal(g1->image, g2->image, depth) &&
3486 internal_equal(g1->contrib_p, g2->contrib_p, depth) &&
3487 internal_equal(g1->baseline, g2->baseline, depth) &&
3488 internal_equal(g1->face, g2->face, depth) &&
3489 !plists_differ(g1->plist, g2->plist, 0, 0, depth + 1));
3492 static unsigned long glyph_hash(Lisp_Object obj, int depth)
3496 /* No need to hash all of the elements; that would take too long.
3497 Just hash the most common ones. */
3498 return HASH2(internal_hash(XGLYPH(obj)->image, depth),
3499 internal_hash(XGLYPH(obj)->face, depth));
3502 static Lisp_Object glyph_getprop(Lisp_Object obj, Lisp_Object prop)
3504 Lisp_Glyph *g = XGLYPH(obj);
3506 if (EQ(prop, Qimage))
3508 if (EQ(prop, Qcontrib_p))
3509 return g->contrib_p;
3510 if (EQ(prop, Qbaseline))
3512 if (EQ(prop, Qface))
3515 return external_plist_get(&g->plist, prop, 0, ERROR_ME);
3518 static int glyph_putprop(Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
3520 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3523 if (EQ(prop, Qface)) {
3524 XGLYPH(obj)->face = Fget_face(value);
3528 external_plist_put(&XGLYPH(obj)->plist, prop, value, 0, ERROR_ME);
3532 static int glyph_remprop(Lisp_Object obj, Lisp_Object prop)
3534 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3537 if (EQ(prop, Qface)) {
3538 XGLYPH(obj)->face = Qnil;
3542 return external_remprop(&XGLYPH(obj)->plist, prop, 0, ERROR_ME);
3545 static Lisp_Object glyph_plist(Lisp_Object obj)
3547 Lisp_Glyph *glyph = XGLYPH(obj);
3548 Lisp_Object result = glyph->plist;
3550 result = cons3(Qface, glyph->face, result);
3551 result = cons3(Qbaseline, glyph->baseline, result);
3552 result = cons3(Qcontrib_p, glyph->contrib_p, result);
3553 result = cons3(Qimage, glyph->image, result);
3558 static const struct lrecord_description glyph_description[] = {
3559 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, image)},
3560 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, contrib_p)},
3561 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, baseline)},
3562 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, face)},
3563 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, plist)},
3567 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS("glyph", glyph,
3568 mark_glyph, print_glyph, 0,
3569 glyph_equal, glyph_hash,
3570 glyph_description, glyph_getprop,
3571 glyph_putprop, glyph_remprop,
3572 glyph_plist, Lisp_Glyph);
3575 allocate_glyph(enum glyph_type type,
3576 void (*after_change) (Lisp_Object glyph, Lisp_Object property,
3577 Lisp_Object locale))
3579 /* This function can GC */
3580 Lisp_Object obj = Qnil;
3581 Lisp_Glyph *g = alloc_lcrecord_type(Lisp_Glyph, &lrecord_glyph);
3584 g->image = Fmake_specifier(Qimage); /* This function can GC */
3588 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3589 IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK
3590 | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
3591 | IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK;
3594 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3595 IMAGE_NOTHING_MASK | IMAGE_POINTER_MASK;
3598 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3599 IMAGE_NOTHING_MASK | IMAGE_MONO_PIXMAP_MASK
3600 | IMAGE_COLOR_PIXMAP_MASK;
3607 /* I think Fmake_specifier can GC. I think set_specifier_fallback can GC. */
3608 /* We're getting enough reports of odd behavior in this area it seems */
3609 /* best to GCPRO everything. */
3611 Lisp_Object tem1 = list1(Fcons(Qnil, Vthe_nothing_vector));
3612 Lisp_Object tem2 = list1(Fcons(Qnil, Qt));
3613 Lisp_Object tem3 = list1(Fcons(Qnil, Qnil));
3614 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3616 GCPRO4(obj, tem1, tem2, tem3);
3618 set_specifier_fallback(g->image, tem1);
3619 g->contrib_p = Fmake_specifier(Qboolean);
3620 set_specifier_fallback(g->contrib_p, tem2);
3621 /* #### should have a specifier for the following */
3622 g->baseline = Fmake_specifier(Qgeneric);
3623 set_specifier_fallback(g->baseline, tem3);
3626 g->after_change = after_change;
3629 set_image_attached_to(g->image, obj, Qimage);
3636 static enum glyph_type decode_glyph_type(Lisp_Object type, Error_behavior errb)
3639 return GLYPH_BUFFER;
3641 if (ERRB_EQ(errb, ERROR_ME))
3644 if (EQ(type, Qbuffer))
3645 return GLYPH_BUFFER;
3646 if (EQ(type, Qpointer))
3647 return GLYPH_POINTER;
3648 if (EQ(type, Qicon))
3651 maybe_signal_simple_error("Invalid glyph type", type, Qimage, errb);
3653 return GLYPH_UNKNOWN;
3656 static int valid_glyph_type_p(Lisp_Object type)
3658 return !NILP(memq_no_quit(type, Vglyph_type_list));
3661 DEFUN("valid-glyph-type-p", Fvalid_glyph_type_p, 1, 1, 0, /*
3662 Given a GLYPH-TYPE, return non-nil if it is valid.
3663 Valid types are `buffer', `pointer', and `icon'.
3667 return valid_glyph_type_p(glyph_type) ? Qt : Qnil;
3670 DEFUN("glyph-type-list", Fglyph_type_list, 0, 0, 0, /*
3671 Return a list of valid glyph types.
3675 return Fcopy_sequence(Vglyph_type_list);
3678 DEFUN("make-glyph-internal", Fmake_glyph_internal, 0, 1, 0, /*
3679 Create and return a new uninitialized glyph of type TYPE.
3681 TYPE specifies the type of the glyph; this should be one of `buffer',
3682 `pointer', or `icon', and defaults to `buffer'. The type of the glyph
3683 specifies in which contexts the glyph can be used, and controls the
3684 allowable image types into which the glyph's image can be
3687 `buffer' glyphs can be used as the begin-glyph or end-glyph of an
3688 extent, in the modeline, and in the toolbar. Their image can be
3689 instantiated as `nothing', `mono-pixmap', `color-pixmap', `text',
3692 `pointer' glyphs can be used to specify the mouse pointer. Their
3693 image can be instantiated as `pointer'.
3695 `icon' glyphs can be used to specify the icon used when a frame is
3696 iconified. Their image can be instantiated as `mono-pixmap' and
3701 enum glyph_type typeval = decode_glyph_type(type, ERROR_ME);
3702 return allocate_glyph(typeval, 0);
3705 DEFUN("glyphp", Fglyphp, 1, 1, 0, /*
3706 Return non-nil if OBJECT is a glyph.
3708 A glyph is an object used for pixmaps, widgets and the like. It is used
3709 in begin-glyphs and end-glyphs attached to extents, in marginal and textual
3710 annotations, in overlay arrows (overlay-arrow-* variables), in toolbar
3711 buttons, and the like. Much more detailed information can be found at
3712 `make-glyph'. Its image is described using an image specifier --
3713 see `make-image-specifier'. See also `make-image-instance' for further
3718 return GLYPHP(object) ? Qt : Qnil;
3721 DEFUN("glyph-type", Fglyph_type, 1, 1, 0, /*
3722 Return the type of the given glyph.
3723 The return value will be one of 'buffer, 'pointer, or 'icon.
3728 switch (XGLYPH_TYPE(glyph)) {
3744 glyph_image_instance(Lisp_Object glyph, Lisp_Object domain,
3745 Error_behavior errb, int no_quit)
3747 Lisp_Object specifier = GLYPH_IMAGE(XGLYPH(glyph));
3749 /* This can never return Qunbound. All glyphs have 'nothing as
3751 Lisp_Object image_instance = specifier_instance(specifier, Qunbound,
3752 domain, errb, no_quit,
3755 assert(!UNBOUNDP(image_instance));
3756 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
3758 return image_instance;
3762 glyph_image_instance_maybe(Lisp_Object glyph_or_image, Lisp_Object window)
3764 Lisp_Object instance = glyph_or_image;
3766 if (GLYPHP(glyph_or_image))
3768 glyph_image_instance(glyph_or_image, window, ERROR_ME_NOT,
3774 /*****************************************************************************
3777 Return the width of the given GLYPH on the given WINDOW.
3778 Calculations are done based on recursively querying the geometry of
3779 the associated image instances.
3780 ****************************************************************************/
3781 unsigned short glyph_width(Lisp_Object glyph_or_image, Lisp_Object domain)
3783 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3785 if (!IMAGE_INSTANCEP(instance))
3788 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3789 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3790 IMAGE_UNSPECIFIED_GEOMETRY,
3791 IMAGE_UNCHANGED_GEOMETRY,
3792 IMAGE_UNCHANGED_GEOMETRY, domain);
3794 return XIMAGE_INSTANCE_WIDTH(instance);
3797 DEFUN("glyph-width", Fglyph_width, 1, 2, 0, /*
3798 Return the width of GLYPH on WINDOW.
3799 This may not be exact as it does not take into account all of the context
3800 that redisplay will.
3804 XSETWINDOW(window, decode_window(window));
3807 return make_int(glyph_width(glyph, window));
3810 unsigned short glyph_ascent(Lisp_Object glyph_or_image, Lisp_Object domain)
3812 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3814 if (!IMAGE_INSTANCEP(instance))
3817 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3818 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3819 IMAGE_UNSPECIFIED_GEOMETRY,
3820 IMAGE_UNCHANGED_GEOMETRY,
3821 IMAGE_UNCHANGED_GEOMETRY, domain);
3823 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3824 return XIMAGE_INSTANCE_TEXT_ASCENT(instance);
3826 return XIMAGE_INSTANCE_HEIGHT(instance);
3829 unsigned short glyph_descent(Lisp_Object glyph_or_image, Lisp_Object domain)
3831 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3833 if (!IMAGE_INSTANCEP(instance))
3836 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3837 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3838 IMAGE_UNSPECIFIED_GEOMETRY,
3839 IMAGE_UNCHANGED_GEOMETRY,
3840 IMAGE_UNCHANGED_GEOMETRY, domain);
3842 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3843 return XIMAGE_INSTANCE_TEXT_DESCENT(instance);
3848 /* strictly a convenience function. */
3849 unsigned short glyph_height(Lisp_Object glyph_or_image, Lisp_Object domain)
3851 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3854 if (!IMAGE_INSTANCEP(instance))
3857 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3858 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3859 IMAGE_UNSPECIFIED_GEOMETRY,
3860 IMAGE_UNCHANGED_GEOMETRY,
3861 IMAGE_UNCHANGED_GEOMETRY, domain);
3863 return XIMAGE_INSTANCE_HEIGHT(instance);
3866 DEFUN("glyph-ascent", Fglyph_ascent, 1, 2, 0, /*
3867 Return the ascent value of GLYPH on WINDOW.
3868 This may not be exact as it does not take into account all of the context
3869 that redisplay will.
3873 XSETWINDOW(window, decode_window(window));
3876 return make_int(glyph_ascent(glyph, window));
3879 DEFUN("glyph-descent", Fglyph_descent, 1, 2, 0, /*
3880 Return the descent value of GLYPH on WINDOW.
3881 This may not be exact as it does not take into account all of the context
3882 that redisplay will.
3886 XSETWINDOW(window, decode_window(window));
3889 return make_int(glyph_descent(glyph, window));
3892 /* This is redundant but I bet a lot of people expect it to exist. */
3893 DEFUN("glyph-height", Fglyph_height, 1, 2, 0, /*
3894 Return the height of GLYPH on WINDOW.
3895 This may not be exact as it does not take into account all of the context
3896 that redisplay will.
3900 XSETWINDOW(window, decode_window(window));
3903 return make_int(glyph_height(glyph, window));
3907 set_glyph_dirty_p(Lisp_Object glyph_or_image, Lisp_Object window, int dirty)
3909 Lisp_Object instance = glyph_or_image;
3911 if (!NILP(glyph_or_image)) {
3912 if (GLYPHP(glyph_or_image)) {
3913 instance = glyph_image_instance(glyph_or_image, window,
3915 XGLYPH_DIRTYP(glyph_or_image) = dirty;
3918 if (!IMAGE_INSTANCEP(instance))
3921 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3925 static void set_image_instance_dirty_p(Lisp_Object instance, int dirty)
3927 if (IMAGE_INSTANCEP(instance)) {
3928 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3929 /* Now cascade up the hierarchy. */
3930 set_image_instance_dirty_p(XIMAGE_INSTANCE_PARENT(instance),
3932 } else if (GLYPHP(instance)) {
3933 XGLYPH_DIRTYP(instance) = dirty;
3937 /* #### do we need to cache this info to speed things up? */
3939 Lisp_Object glyph_baseline(Lisp_Object glyph, Lisp_Object domain)
3944 Lisp_Object retval =
3945 specifier_instance_no_quit(GLYPH_BASELINE(XGLYPH(glyph)),
3946 /* #### look into ERROR_ME_NOT */
3947 Qunbound, domain, ERROR_ME_NOT,
3949 if (!NILP(retval) && !INTP(retval))
3951 else if (INTP(retval)) {
3952 if (XINT(retval) < 0)
3954 if (XINT(retval) > 100)
3955 retval = make_int(100);
3961 Lisp_Object glyph_face(Lisp_Object glyph, Lisp_Object domain)
3963 /* #### Domain parameter not currently used but it will be */
3964 return GLYPHP(glyph) ? GLYPH_FACE(XGLYPH(glyph)) : Qnil;
3967 int glyph_contrib_p(Lisp_Object glyph, Lisp_Object domain)
3972 return !NILP(specifier_instance_no_quit
3973 (GLYPH_CONTRIB_P(XGLYPH(glyph)), Qunbound, domain,
3974 /* #### look into ERROR_ME_NOT */
3975 ERROR_ME_NOT, 0, Qzero));
3979 glyph_property_was_changed(Lisp_Object glyph, Lisp_Object property,
3982 if (XGLYPH(glyph)->after_change)
3983 (XGLYPH(glyph)->after_change) (glyph, property, locale);
3987 glyph_query_geometry(Lisp_Object glyph_or_image, int *width, int *height,
3988 enum image_instance_geometry disp, Lisp_Object domain)
3990 Lisp_Object instance = glyph_or_image;
3992 if (GLYPHP(glyph_or_image))
3994 glyph_image_instance(glyph_or_image, domain, ERROR_ME_NOT,
3997 image_instance_query_geometry(instance, width, height, disp, domain);
4001 glyph_do_layout(Lisp_Object glyph_or_image, int width, int height,
4002 int xoffset, int yoffset, Lisp_Object domain)
4004 Lisp_Object instance = glyph_or_image;
4006 if (GLYPHP(glyph_or_image))
4008 glyph_image_instance(glyph_or_image, domain, ERROR_ME_NOT,
4011 image_instance_layout(instance, width, height, xoffset, yoffset,
4015 /*****************************************************************************
4016 * glyph cachel functions *
4017 *****************************************************************************/
4019 /* #### All of this is 95% copied from face cachels. Consider
4022 Why do we need glyph_cachels? Simply because a glyph_cachel captures
4023 per-window information about a particular glyph. A glyph itself is
4024 not created in any particular context, so if we were to rely on a
4025 glyph to tell us about its dirtiness we would not be able to reset
4026 the dirty flag after redisplaying it as it may exist in other
4027 contexts. When we have redisplayed we need to know which glyphs to
4028 reset the dirty flags on - the glyph_cachels give us a nice list we
4029 can iterate through doing this. */
4030 void mark_glyph_cachels(glyph_cachel_dynarr * elements)
4037 for (elt = 0; elt < Dynarr_length(elements); elt++) {
4038 struct glyph_cachel *cachel = Dynarr_atp(elements, elt);
4039 mark_object(cachel->glyph);
4044 update_glyph_cachel_data(struct window *w, Lisp_Object glyph,
4045 struct glyph_cachel *cachel)
4047 if (!cachel->updated || NILP(cachel->glyph) || !EQ(cachel->glyph, glyph)
4048 || XGLYPH_DIRTYP(cachel->glyph)
4049 || XFRAME(WINDOW_FRAME(w))->faces_changed) {
4050 Lisp_Object window, instance;
4052 XSETWINDOW(window, w);
4054 cachel->glyph = glyph;
4055 /* Speed things up slightly by grabbing the glyph instantiation
4056 and passing it to the size functions. */
4057 instance = glyph_image_instance(glyph, window, ERROR_ME_NOT, 1);
4059 if (!IMAGE_INSTANCEP(instance))
4062 /* Mark text instance of the glyph dirty if faces have changed,
4063 because its geometry might have changed. */
4064 invalidate_glyph_geometry_maybe(instance, w);
4066 /* #### Do the following 2 lines buy us anything? --kkm */
4067 XGLYPH_DIRTYP(glyph) = XIMAGE_INSTANCE_DIRTYP(instance);
4068 cachel->dirty = XGLYPH_DIRTYP(glyph);
4069 cachel->width = glyph_width(instance, window);
4070 cachel->ascent = glyph_ascent(instance, window);
4071 cachel->descent = glyph_descent(instance, window);
4074 cachel->updated = 1;
4077 static void add_glyph_cachel(struct window *w, Lisp_Object glyph)
4079 struct glyph_cachel new_cachel;
4082 new_cachel.glyph = Qnil;
4084 update_glyph_cachel_data(w, glyph, &new_cachel);
4085 Dynarr_add(w->glyph_cachels, new_cachel);
4088 glyph_index get_glyph_cachel_index(struct window *w, Lisp_Object glyph)
4095 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4096 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4098 if (EQ(cachel->glyph, glyph) && !NILP(glyph)) {
4099 update_glyph_cachel_data(w, glyph, cachel);
4104 /* If we didn't find the glyph, add it and then return its index. */
4105 add_glyph_cachel(w, glyph);
4109 void reset_glyph_cachels(struct window *w)
4111 Dynarr_reset(w->glyph_cachels);
4112 get_glyph_cachel_index(w, Vcontinuation_glyph);
4113 get_glyph_cachel_index(w, Vtruncation_glyph);
4114 get_glyph_cachel_index(w, Vhscroll_glyph);
4115 get_glyph_cachel_index(w, Vcontrol_arrow_glyph);
4116 get_glyph_cachel_index(w, Voctal_escape_glyph);
4117 get_glyph_cachel_index(w, Vinvisible_text_glyph);
4120 void mark_glyph_cachels_as_not_updated(struct window *w)
4124 /* We need to have a dirty flag to tell if the glyph has changed.
4125 We can check to see if each glyph variable is actually a
4126 completely different glyph, though. */
4127 #define FROB(glyph_obj, gindex) \
4128 update_glyph_cachel_data (w, glyph_obj, \
4129 Dynarr_atp (w->glyph_cachels, gindex))
4131 FROB(Vcontinuation_glyph, CONT_GLYPH_INDEX);
4132 FROB(Vtruncation_glyph, TRUN_GLYPH_INDEX);
4133 FROB(Vhscroll_glyph, HSCROLL_GLYPH_INDEX);
4134 FROB(Vcontrol_arrow_glyph, CONTROL_GLYPH_INDEX);
4135 FROB(Voctal_escape_glyph, OCT_ESC_GLYPH_INDEX);
4136 FROB(Vinvisible_text_glyph, INVIS_GLYPH_INDEX);
4139 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4140 Dynarr_atp(w->glyph_cachels, elt)->updated = 0;
4144 /* Unset the dirty bit on all the glyph cachels that have it. */
4145 void mark_glyph_cachels_as_clean(struct window *w)
4149 XSETWINDOW(window, w);
4150 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4151 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4153 set_glyph_dirty_p(cachel->glyph, window, 0);
4157 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
4160 compute_glyph_cachel_usage(glyph_cachel_dynarr * glyph_cachels,
4161 struct overhead_stats *ovstats)
4166 total += Dynarr_memory_usage(glyph_cachels, ovstats);
4171 #endif /* MEMORY_USAGE_STATS */
4173 /*****************************************************************************
4174 * subwindow cachel functions *
4175 *****************************************************************************/
4176 /* Subwindows are curious in that you have to physically unmap them to
4177 not display them. It is problematic deciding what to do in
4178 redisplay. We have two caches - a per-window instance cache that
4179 keeps track of subwindows on a window, these are linked to their
4180 instantiator in the hashtable and when the instantiator goes away
4181 we want the instance to go away also. However we also have a
4182 per-frame instance cache that we use to determine if a subwindow is
4183 obscuring an area that we want to clear. We need to be able to flip
4184 through this quickly so a hashtable is not suitable hence the
4185 subwindow_cachels. This is a weak list so unreference instances
4186 will get deleted properly. */
4188 /* redisplay in general assumes that drawing something will erase
4189 what was there before. unfortunately this does not apply to
4190 subwindows that need to be specifically unmapped in order to
4191 disappear. we take a brute force approach - on the basis that its
4192 cheap - and unmap all subwindows in a display line */
4194 /* Put new instances in the frame subwindow cache. This is less costly than
4195 doing it every time something gets mapped, and deleted instances will be
4196 removed automatically. */
4197 static void cache_subwindow_instance_in_frame_maybe(Lisp_Object instance)
4199 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(instance);
4200 if (!NILP(DOMAIN_FRAME(IMAGE_INSTANCE_DOMAIN(ii)))) {
4201 struct frame *f = DOMAIN_XFRAME(IMAGE_INSTANCE_DOMAIN(ii));
4202 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4204 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f)));
4208 /* Unmap and finalize all subwindow instances in the frame cache. This
4209 is necessary because GC will not guarantee the order things get
4210 deleted in and moreover, frame finalization deletes the window
4211 system windows before deleting SXEmacs windows, and hence
4214 unmap_subwindow_instance_cache_mapper(Lisp_Object key, Lisp_Object value,
4217 /* value can be nil; we cache failures as well as successes */
4219 struct frame *f = XFRAME(XIMAGE_INSTANCE_FRAME(value));
4220 unmap_subwindow(value);
4222 /* In case GC doesn't catch up fast enough, remove from the frame
4223 cache also. Otherwise code that checks the sanity of the instance
4225 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4226 = delq_no_quit(value,
4227 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE
4229 finalize_image_instance(XIMAGE_INSTANCE(value), 0);
4235 static void finalize_all_subwindow_instances(struct window *w)
4238 finalize_all_subwindow_instances(XWINDOW(w->next));
4239 if (!NILP(w->vchild))
4240 finalize_all_subwindow_instances(XWINDOW(w->vchild));
4241 if (!NILP(w->hchild))
4242 finalize_all_subwindow_instances(XWINDOW(w->hchild));
4244 elisp_maphash(unmap_subwindow_instance_cache_mapper,
4245 w->subwindow_instance_cache, (void *)1);
4248 void free_frame_subwindow_instances(struct frame *f)
4250 /* Make sure all instances are finalized. We have to do this via the
4251 instance cache since some instances may be extant but not
4252 displayed (and hence not in the frame cache). */
4253 finalize_all_subwindow_instances(XWINDOW(f->root_window));
4256 /* Unmap all instances in the frame cache. */
4257 void reset_frame_subwindow_instance_cache(struct frame *f)
4261 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4262 Lisp_Object value = XCAR(rest);
4263 unmap_subwindow(value);
4267 /*****************************************************************************
4268 * subwindow exposure ignorance *
4269 *****************************************************************************/
4270 /* when we unmap subwindows the associated window system will generate
4271 expose events. This we do not want as redisplay already copes with
4272 the repainting necessary. Worse, we can get in an endless cycle of
4273 redisplay if we are not careful. Thus we keep a per-frame list of
4274 expose events that are going to come and ignore them as
4277 struct expose_ignore_blocktype {
4278 Blocktype_declare(struct expose_ignore);
4279 } *the_expose_ignore_blocktype;
4282 check_for_ignored_expose(struct frame *f, int x, int y, int width, int height)
4284 struct expose_ignore *ei, *prev;
4285 /* the ignore list is FIFO so we should generally get a match with
4286 the first element in the list */
4287 for (ei = f->subwindow_exposures, prev = 0; ei; ei = ei->next) {
4288 /* Checking for exact matches just isn't good enough as we
4289 might get exposures for partially obscured subwindows, thus
4290 we have to check for overlaps. Being conservative, we will
4291 check for exposures wholly contained by the subwindow - this
4292 might give us what we want. */
4293 if (ei->x <= (unsigned)x && ei->y <= (unsigned)y
4294 && ei->x + ei->width >= (unsigned)(x + width)
4295 && ei->y + ei->height >= (unsigned)(y + height)) {
4296 #ifdef DEBUG_WIDGETS
4298 ("ignored %d+%d, %dx%d for exposure %d+%d, %dx%d\n",
4299 x, y, width, height, ei->x, ei->y, ei->width,
4303 f->subwindow_exposures = ei->next;
4305 prev->next = ei->next;
4307 if (ei == f->subwindow_exposures_tail)
4308 f->subwindow_exposures_tail = prev;
4310 Blocktype_free(the_expose_ignore_blocktype, ei);
4319 register_ignored_expose(struct frame *f, int x, int y, int width, int height)
4321 if (!hold_ignored_expose_registration) {
4322 struct expose_ignore *ei;
4324 ei = Blocktype_alloc(the_expose_ignore_blocktype);
4330 ei->height = height;
4332 /* we have to add the exposure to the end of the list, since we
4333 want to check the oldest events first. for speed we keep a record
4334 of the end so that we can add right to it. */
4335 if (f->subwindow_exposures_tail) {
4336 f->subwindow_exposures_tail->next = ei;
4338 if (!f->subwindow_exposures) {
4339 f->subwindow_exposures = ei;
4341 f->subwindow_exposures_tail = ei;
4345 /****************************************************************************
4346 find_matching_subwindow
4348 See if there is a subwindow that completely encloses the requested
4350 ****************************************************************************/
4351 int find_matching_subwindow(struct frame *f, int x, int y, int width,
4356 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4357 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(XCAR(rest));
4359 if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii)
4361 IMAGE_INSTANCE_DISPLAY_X(ii) <= (unsigned)x
4363 IMAGE_INSTANCE_DISPLAY_Y(ii) <= (unsigned)y
4364 && IMAGE_INSTANCE_DISPLAY_X(ii)
4365 + IMAGE_INSTANCE_DISPLAY_WIDTH(ii) >= (unsigned)(x + width)
4366 && IMAGE_INSTANCE_DISPLAY_Y(ii)
4367 + IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) >=
4368 (unsigned)(y + height)) {
4375 /*****************************************************************************
4376 * subwindow functions *
4377 *****************************************************************************/
4379 /* Update the displayed characteristics of a subwindow. This function
4380 should generally only get called if the subwindow is actually
4382 void redisplay_subwindow(Lisp_Object subwindow)
4384 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4385 int count = specpdl_depth();
4387 /* The update method is allowed to call eval. Since it is quite
4388 common for this function to get called from somewhere in
4389 redisplay we need to make sure that quits are ignored. Otherwise
4390 Fsignal will abort. */
4391 specbind(Qinhibit_quit, Qt);
4393 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4395 if (WIDGET_IMAGE_INSTANCEP(subwindow)) {
4396 if (image_instance_changed(subwindow))
4397 redisplay_widget(subwindow);
4398 /* Reset the changed flags. */
4399 IMAGE_INSTANCE_WIDGET_FACE_CHANGED(ii) = 0;
4400 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii) = 0;
4401 IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii) = 0;
4402 IMAGE_INSTANCE_TEXT_CHANGED(ii) = 0;
4403 } else if (IMAGE_INSTANCE_TYPE(ii) == IMAGE_SUBWINDOW
4404 && !NILP(IMAGE_INSTANCE_FRAME(ii))) {
4405 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4406 redisplay_subwindow, (ii));
4409 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 0;
4410 /* This function is typically called by redisplay just before
4411 outputting the information to the screen. Thus we record a hash
4412 of the output to determine whether on-screen is the same as
4413 recorded structure. This approach has limitations in there is a
4414 good chance that hash values will be different for the same
4415 visual appearance. However, we would rather that then the other
4416 way round - it simply means that we will get more displays than
4417 we might need. We can get better hashing by making the depth
4418 negative - currently it will recurse down 7 levels. */
4419 IMAGE_INSTANCE_DISPLAY_HASH(ii) = internal_hash(subwindow,
4420 IMAGE_INSTANCE_HASH_DEPTH);
4422 unbind_to(count, Qnil);
4425 /* Determine whether an image_instance has changed structurally and
4426 hence needs redisplaying in some way.
4428 #### This should just look at the instantiator differences when we
4429 get rid of the stored items altogether. In fact we should probably
4430 store the new instantiator as well as the old - as we do with
4431 gui_items currently - and then pick-up the new on the next
4432 redisplay. This would obviate the need for any of this trickery
4434 int image_instance_changed(Lisp_Object subwindow)
4436 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4438 if (internal_hash(subwindow, IMAGE_INSTANCE_HASH_DEPTH) !=
4439 IMAGE_INSTANCE_DISPLAY_HASH(ii))
4441 /* #### I think there is probably a bug here. This gets called for
4442 layouts - and yet the pending items are always nil for
4443 layouts. We are saved by layout optimization, but I'm undecided
4444 as to what the correct fix is. */
4445 else if (WIDGET_IMAGE_INSTANCEP(subwindow)
4446 && (!internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(ii),
4447 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii), 0)
4448 || !NILP(IMAGE_INSTANCE_LAYOUT_CHILDREN(ii))
4449 || IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii)))
4455 /* Update all the subwindows on a frame. */
4456 void update_widget_instances(Lisp_Object frame)
4461 /* Its possible for the preceding callback to have deleted the
4462 frame, so cope with this. */
4463 if (!FRAMEP(frame) || !FRAME_LIVE_P(XFRAME(frame)))
4469 /* If we get called we know something has changed. */
4470 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4471 Lisp_Object widget = XCAR(rest);
4473 if (XIMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(widget)
4474 && image_instance_changed(widget)) {
4475 set_image_instance_dirty_p(widget, 1);
4476 MARK_FRAME_GLYPHS_CHANGED(f);
4481 /* remove a subwindow from its frame */
4482 void unmap_subwindow(Lisp_Object subwindow)
4484 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4487 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4489 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4490 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK))
4491 || !IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii))
4494 #ifdef DEBUG_WIDGETS
4495 stderr_out("unmapping subwindow %p\n", IMAGE_INSTANCE_SUBWINDOW_ID(ii));
4497 f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
4499 /* make sure we don't get expose events */
4500 register_ignored_expose(f, IMAGE_INSTANCE_DISPLAY_X(ii),
4501 IMAGE_INSTANCE_DISPLAY_Y(ii),
4502 IMAGE_INSTANCE_DISPLAY_WIDTH(ii),
4503 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii));
4504 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4506 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(ii)),
4507 unmap_subwindow, (ii));
4510 /* show a subwindow in its frame */
4511 void map_subwindow(Lisp_Object subwindow, int x, int y,
4512 struct display_glyph_area *dga)
4514 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4516 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4518 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4519 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK)))
4522 #ifdef DEBUG_WIDGETS
4523 stderr_out("mapping subwindow %p, %dx%d@%d+%d\n",
4524 IMAGE_INSTANCE_SUBWINDOW_ID(ii),
4525 dga->width, dga->height, x, y);
4527 (void)XFRAME(IMAGE_INSTANCE_FRAME(ii));
4528 IMAGE_INSTANCE_DISPLAY_X(ii) = x;
4529 IMAGE_INSTANCE_DISPLAY_Y(ii) = y;
4530 IMAGE_INSTANCE_DISPLAY_WIDTH(ii) = dga->width;
4531 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) = dga->height;
4533 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4534 map_subwindow, (ii, x, y, dga));
4535 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 1;
4538 static int subwindow_possible_dest_types(void)
4540 return IMAGE_SUBWINDOW_MASK;
4543 int subwindow_governing_domain(void)
4545 return GOVERNING_DOMAIN_WINDOW;
4548 /* Partially instantiate a subwindow. */
4550 subwindow_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
4551 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
4552 int dest_mask, Lisp_Object domain)
4554 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
4555 Lisp_Object device = image_instance_device(image_instance);
4556 Lisp_Object frame = DOMAIN_FRAME(domain);
4557 Lisp_Object width = find_keyword_in_vector(instantiator, Q_pixel_width);
4558 Lisp_Object height =
4559 find_keyword_in_vector(instantiator, Q_pixel_height);
4562 signal_simple_error("No selected frame", device);
4564 if (!(dest_mask & IMAGE_SUBWINDOW_MASK))
4565 incompatible_image_types(instantiator, dest_mask,
4566 IMAGE_SUBWINDOW_MASK);
4569 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = 0;
4570 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4574 if (XINT(width) > 1)
4576 IMAGE_INSTANCE_WIDTH(ii) = w;
4577 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP(ii) = 0;
4582 if (XINT(height) > 1)
4584 IMAGE_INSTANCE_HEIGHT(ii) = h;
4585 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP(ii) = 0;
4589 #ifdef HAVE_X_WINDOWS
4590 extern void x_subwindow_query_geometry(Lisp_Object image_instance,
4591 int *width, int *height);
4594 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4595 int *height, enum image_instance_geometry disp,
4598 if (IMAGE_INSTANCE_INITIALIZED(XIMAGE_INSTANCE(image_instance)))
4600 /* Query real size of subwindow */
4601 x_subwindow_query_geometry(image_instance, width, height);
4603 /* Set them in case of initial layout instantiation */
4611 /* This is just a backup in case no-one has assigned a suitable geometry.
4612 #### It should really query the enclose window for geometry. */
4614 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4615 int *height, enum image_instance_geometry disp,
4623 #endif /* HAVE_X_WINDOWS */
4625 DEFUN("subwindowp", Fsubwindowp, 1, 1, 0, /*
4626 Return non-nil if OBJECT is a subwindow.
4630 CHECK_IMAGE_INSTANCE(object);
4631 return (XIMAGE_INSTANCE_TYPE(object) == IMAGE_SUBWINDOW) ? Qt : Qnil;
4634 DEFUN("image-instance-subwindow-id", Fimage_instance_subwindow_id, 1, 1, 0, /*
4635 Return the window id of SUBWINDOW as a number.
4639 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4640 return make_int((EMACS_INT) XIMAGE_INSTANCE_SUBWINDOW_ID(subwindow));
4643 DEFUN("resize-subwindow", Fresize_subwindow, 1, 3, 0, /*
4644 Resize SUBWINDOW to WIDTH x HEIGHT.
4645 If a value is nil that parameter is not changed.
4647 (subwindow, width, height))
4650 Lisp_Image_Instance *ii;
4652 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4653 ii = XIMAGE_INSTANCE(subwindow);
4656 neww = IMAGE_INSTANCE_WIDTH(ii);
4661 newh = IMAGE_INSTANCE_HEIGHT(ii);
4663 newh = XINT(height);
4665 /* The actual resizing gets done asynchronously by
4666 update_subwindow. */
4667 IMAGE_INSTANCE_HEIGHT(ii) = newh;
4668 IMAGE_INSTANCE_WIDTH(ii) = neww;
4669 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
4674 DEFUN("force-subwindow-map", Fforce_subwindow_map, 1, 1, 0, /*
4675 Generate a Map event for SUBWINDOW.
4679 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4681 map_subwindow(subwindow, 0, 0);
4686 /*****************************************************************************
4688 *****************************************************************************/
4690 /* Get the display tables for use currently on window W with face
4691 FACE. #### This will have to be redone. */
4694 get_display_tables(struct window *w, face_index findex,
4695 Lisp_Object * face_table, Lisp_Object * window_table)
4698 tem = WINDOW_FACE_CACHEL_DISPLAY_TABLE(w, findex);
4702 tem = noseeum_cons(tem, Qnil);
4704 tem = w->display_table;
4708 tem = noseeum_cons(tem, Qnil);
4709 *window_table = tem;
4713 display_table_entry(Emchar ch, Lisp_Object face_table, Lisp_Object window_table)
4717 /* Loop over FACE_TABLE, and then over WINDOW_TABLE. */
4718 for (tail = face_table; 1; tail = XCDR(tail)) {
4721 if (!NILP(window_table)) {
4722 tail = window_table;
4723 window_table = Qnil;
4729 if (VECTORP(table)) {
4730 if (ch < XVECTOR_LENGTH(table)
4731 && !NILP(XVECTOR_DATA(table)[ch]))
4732 return XVECTOR_DATA(table)[ch];
4735 } else if (CHAR_TABLEP(table)
4736 && XCHAR_TABLE_TYPE(table) == CHAR_TABLE_TYPE_CHAR) {
4737 return get_char_table(ch, XCHAR_TABLE(table));
4738 } else if (CHAR_TABLEP(table)
4739 && XCHAR_TABLE_TYPE(table) ==
4740 CHAR_TABLE_TYPE_GENERIC) {
4742 get_char_table(ch, XCHAR_TABLE(table));
4747 } else if (RANGE_TABLEP(table)) {
4749 Fget_range_table(make_char(ch), table, Qnil);
4759 /*****************************************************************************
4760 * timeouts for animated glyphs *
4761 *****************************************************************************/
4762 static Lisp_Object Qglyph_animated_timeout_handler;
4764 DEFUN("glyph-animated-timeout-handler", Fglyph_animated_timeout_handler, 1, 1, 0, /*
4765 Callback function for updating animated images.
4770 CHECK_WEAK_LIST(arg);
4772 if (!NILP(XWEAK_LIST_LIST(arg)) && !NILP(XCAR(XWEAK_LIST_LIST(arg)))) {
4773 Lisp_Object value = XCAR(XWEAK_LIST_LIST(arg));
4775 if (IMAGE_INSTANCEP(value)) {
4776 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(value);
4778 if (COLOR_PIXMAP_IMAGE_INSTANCEP(value)
4780 IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii) > 1
4781 && !disable_animated_pixmaps) {
4783 /* Increment the index of the image slice we are
4784 currently viewing. */
4785 IMAGE_INSTANCE_PIXMAP_SLICE(ii) =
4786 (IMAGE_INSTANCE_PIXMAP_SLICE(ii) + 1)
4787 % IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii);
4788 /* We might need to kick redisplay at this point
4789 - but we also might not. */
4790 tmp = image_instance_device(value);
4791 MARK_DEVICE_FRAMES_GLYPHS_CHANGED(XDEVICE(tmp));
4792 /* Cascade dirtiness so that we can have an
4793 animated glyph in a layout for instance. */
4794 set_image_instance_dirty_p(value, 1);
4801 Lisp_Object add_glyph_animated_timeout(EMACS_INT tickms, Lisp_Object image)
4803 Lisp_Object ret = Qnil;
4805 if (tickms > 0 && IMAGE_INSTANCEP(image)) {
4806 double ms = ((double)tickms) / 1000.0;
4807 struct gcpro gcpro1;
4808 Lisp_Object holder = make_weak_list(WEAK_LIST_SIMPLE);
4811 XWEAK_LIST_LIST(holder) = Fcons(image, Qnil);
4813 ret = Fadd_timeout(make_float(ms),
4814 Qglyph_animated_timeout_handler,
4815 holder, make_float(ms));
4822 void disable_glyph_animated_timeout(int i)
4827 Fdisable_timeout(id);
4830 /*****************************************************************************
4832 *****************************************************************************/
4834 void syms_of_glyphs(void)
4836 INIT_LRECORD_IMPLEMENTATION(glyph);
4837 INIT_LRECORD_IMPLEMENTATION(image_instance);
4839 /* image instantiators */
4841 DEFSUBR(Fimage_instantiator_format_list);
4842 DEFSUBR(Fvalid_image_instantiator_format_p);
4843 DEFSUBR(Fset_console_type_image_conversion_list);
4844 DEFSUBR(Fconsole_type_image_conversion_list);
4847 DEFKEYWORD(Q_pixel_height);
4848 DEFKEYWORD(Q_pixel_width);
4851 DEFKEYWORD(Q_color_symbols);
4854 DEFKEYWORD(Q_mask_file);
4855 DEFKEYWORD(Q_mask_data);
4856 DEFKEYWORD(Q_hotspot_x);
4857 DEFKEYWORD(Q_hotspot_y);
4858 DEFKEYWORD(Q_foreground);
4859 DEFKEYWORD(Q_background);
4861 /* image specifiers */
4863 DEFSUBR(Fimage_specifier_p);
4864 /* Qimage in general.c */
4866 /* image instances */
4868 defsymbol(&Qimage_instancep, "image-instance-p");
4870 DEFSYMBOL(Qnothing_image_instance_p);
4871 DEFSYMBOL(Qtext_image_instance_p);
4872 DEFSYMBOL(Qmono_pixmap_image_instance_p);
4873 DEFSYMBOL(Qcolor_pixmap_image_instance_p);
4874 DEFSYMBOL(Qpointer_image_instance_p);
4875 DEFSYMBOL(Qwidget_image_instance_p);
4876 DEFSYMBOL(Qsubwindow_image_instance_p);
4878 DEFSUBR(Fmake_image_instance);
4879 DEFSUBR(Fimage_instance_p);
4880 DEFSUBR(Fimage_instance_type);
4881 DEFSUBR(Fvalid_image_instance_type_p);
4882 DEFSUBR(Fimage_instance_type_list);
4883 DEFSUBR(Fimage_instance_name);
4884 DEFSUBR(Fimage_instance_domain);
4885 DEFSUBR(Fimage_instance_string);
4886 DEFSUBR(Fimage_instance_file_name);
4887 DEFSUBR(Fimage_instance_mask_file_name);
4888 DEFSUBR(Fimage_instance_depth);
4889 DEFSUBR(Fimage_instance_height);
4890 DEFSUBR(Fimage_instance_width);
4891 DEFSUBR(Fimage_instance_hotspot_x);
4892 DEFSUBR(Fimage_instance_hotspot_y);
4893 DEFSUBR(Fimage_instance_foreground);
4894 DEFSUBR(Fimage_instance_background);
4895 DEFSUBR(Fimage_instance_property);
4896 DEFSUBR(Fcolorize_image_instance);
4898 DEFSUBR(Fsubwindowp);
4899 DEFSUBR(Fimage_instance_subwindow_id);
4900 DEFSUBR(Fresize_subwindow);
4901 DEFSUBR(Fforce_subwindow_map);
4903 /* Qnothing defined as part of the "nothing" image-instantiator
4905 /* Qtext defined in general.c */
4906 DEFSYMBOL(Qmono_pixmap);
4907 DEFSYMBOL(Qcolor_pixmap);
4908 /* Qpointer defined in general.c */
4913 DEFSYMBOL(Qcontrib_p);
4914 DEFSYMBOL(Qbaseline);
4916 DEFSYMBOL(Qbuffer_glyph_p);
4917 DEFSYMBOL(Qpointer_glyph_p);
4918 DEFSYMBOL(Qicon_glyph_p);
4920 DEFSYMBOL(Qconst_glyph_variable);
4922 DEFSUBR(Fglyph_type);
4923 DEFSUBR(Fvalid_glyph_type_p);
4924 DEFSUBR(Fglyph_type_list);
4926 DEFSUBR(Fmake_glyph_internal);
4927 DEFSUBR(Fglyph_width);
4928 DEFSUBR(Fglyph_ascent);
4929 DEFSUBR(Fglyph_descent);
4930 DEFSUBR(Fglyph_height);
4931 DEFSUBR(Fset_instantiator_property);
4933 /* Qbuffer defined in general.c. */
4934 /* Qpointer defined above */
4936 /* Unfortunately, timeout handlers must be lisp functions. This is
4937 for animated glyphs. */
4938 DEFSYMBOL(Qglyph_animated_timeout_handler);
4939 DEFSUBR(Fglyph_animated_timeout_handler);
4942 DEFERROR_STANDARD(Qimage_conversion_error, Qio_error);
4945 static const struct lrecord_description image_specifier_description[] = {
4947 specifier_data_offset + offsetof(struct image_specifier, attachee)},
4949 specifier_data_offset + offsetof(struct image_specifier,
4950 attachee_property)},
4954 void specifier_type_create_image(void)
4956 /* image specifiers */
4958 INITIALIZE_SPECIFIER_TYPE_WITH_DATA(image, "image", "imagep");
4960 SPECIFIER_HAS_METHOD(image, create);
4961 SPECIFIER_HAS_METHOD(image, mark);
4962 SPECIFIER_HAS_METHOD(image, instantiate);
4963 SPECIFIER_HAS_METHOD(image, validate);
4964 SPECIFIER_HAS_METHOD(image, after_change);
4965 SPECIFIER_HAS_METHOD(image, going_to_add);
4966 SPECIFIER_HAS_METHOD(image, copy_instantiator);
4969 void reinit_specifier_type_create_image(void)
4971 REINITIALIZE_SPECIFIER_TYPE(image);
4974 static const struct lrecord_description iike_description_1[] = {
4975 {XD_LISP_OBJECT, offsetof(ii_keyword_entry, keyword)},
4979 static const struct struct_description iike_description = {
4980 sizeof(ii_keyword_entry),
4984 static const struct lrecord_description iiked_description_1[] = {
4985 XD_DYNARR_DESC(ii_keyword_entry_dynarr, &iike_description),
4989 static const struct struct_description iiked_description = {
4990 sizeof(ii_keyword_entry_dynarr),
4994 static const struct lrecord_description iife_description_1[] = {
4995 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, symbol)},
4996 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, device)},
4997 {XD_STRUCT_PTR, offsetof(image_instantiator_format_entry, meths), 1,
5002 static const struct struct_description iife_description = {
5003 sizeof(image_instantiator_format_entry),
5007 static const struct lrecord_description iifed_description_1[] = {
5008 XD_DYNARR_DESC(image_instantiator_format_entry_dynarr,
5013 static const struct struct_description iifed_description = {
5014 sizeof(image_instantiator_format_entry_dynarr),
5018 static const struct lrecord_description iim_description_1[] = {
5019 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, symbol)},
5020 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, device)},
5021 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, keywords),
5022 1, &iiked_description},
5023 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, consoles),
5024 1, &cted_description},
5028 const struct struct_description iim_description = {
5029 sizeof(struct image_instantiator_methods),
5033 void image_instantiator_format_create(void)
5035 /* image instantiators */
5037 the_image_instantiator_format_entry_dynarr =
5038 Dynarr_new(image_instantiator_format_entry);
5040 Vimage_instantiator_format_list = Qnil;
5041 staticpro(&Vimage_instantiator_format_list);
5043 dump_add_root_struct_ptr(&the_image_instantiator_format_entry_dynarr,
5044 &iifed_description);
5046 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(nothing, "nothing");
5048 IIFORMAT_HAS_METHOD(nothing, possible_dest_types);
5049 IIFORMAT_HAS_METHOD(nothing, instantiate);
5051 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(inherit, "inherit");
5053 IIFORMAT_HAS_METHOD(inherit, validate);
5054 IIFORMAT_HAS_METHOD(inherit, normalize);
5055 IIFORMAT_HAS_METHOD(inherit, possible_dest_types);
5056 IIFORMAT_HAS_METHOD(inherit, instantiate);
5058 IIFORMAT_VALID_KEYWORD(inherit, Q_face, check_valid_face);
5060 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(string, "string");
5062 IIFORMAT_HAS_METHOD(string, validate);
5063 IIFORMAT_HAS_SHARED_METHOD(string, governing_domain, subwindow);
5064 IIFORMAT_HAS_METHOD(string, possible_dest_types);
5065 IIFORMAT_HAS_METHOD(string, instantiate);
5067 IIFORMAT_VALID_KEYWORD(string, Q_data, check_valid_string);
5068 /* Do this so we can set strings. */
5069 /* #### Andy, what is this? This is a bogus format and should not be
5070 visible to the user. */
5071 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(text, "text");
5072 IIFORMAT_HAS_METHOD(text, update);
5073 IIFORMAT_HAS_METHOD(text, query_geometry);
5075 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(formatted_string,
5076 "formatted-string");
5078 IIFORMAT_HAS_METHOD(formatted_string, validate);
5079 IIFORMAT_HAS_METHOD(formatted_string, possible_dest_types);
5080 IIFORMAT_HAS_METHOD(formatted_string, instantiate);
5081 IIFORMAT_VALID_KEYWORD(formatted_string, Q_data, check_valid_string);
5083 /* Do this so pointers have geometry. */
5084 /* #### Andy, what is this? This is a bogus format and should not be
5085 visible to the user. */
5086 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(pointer, "pointer");
5087 IIFORMAT_HAS_SHARED_METHOD(pointer, query_geometry, subwindow);
5090 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(subwindow, "subwindow");
5091 IIFORMAT_HAS_METHOD(subwindow, possible_dest_types);
5092 IIFORMAT_HAS_METHOD(subwindow, governing_domain);
5093 IIFORMAT_HAS_METHOD(subwindow, instantiate);
5094 IIFORMAT_HAS_METHOD(subwindow, query_geometry);
5095 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_width, check_valid_int);
5096 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_height, check_valid_int);
5098 #ifdef HAVE_WINDOW_SYSTEM
5099 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xbm, "xbm");
5101 IIFORMAT_HAS_METHOD(xbm, validate);
5102 IIFORMAT_HAS_METHOD(xbm, normalize);
5103 IIFORMAT_HAS_METHOD(xbm, possible_dest_types);
5105 IIFORMAT_VALID_KEYWORD(xbm, Q_data, check_valid_xbm_inline);
5106 IIFORMAT_VALID_KEYWORD(xbm, Q_file, check_valid_string);
5107 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_data, check_valid_xbm_inline);
5108 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_file, check_valid_string);
5109 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_x, check_valid_int);
5110 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_y, check_valid_int);
5111 IIFORMAT_VALID_KEYWORD(xbm, Q_foreground, check_valid_string);
5112 IIFORMAT_VALID_KEYWORD(xbm, Q_background, check_valid_string);
5113 #endif /* HAVE_WINDOW_SYSTEM */
5116 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xface, "xface");
5118 IIFORMAT_HAS_METHOD(xface, validate);
5119 IIFORMAT_HAS_METHOD(xface, normalize);
5120 IIFORMAT_HAS_METHOD(xface, possible_dest_types);
5122 IIFORMAT_VALID_KEYWORD(xface, Q_data, check_valid_string);
5123 IIFORMAT_VALID_KEYWORD(xface, Q_file, check_valid_string);
5124 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_x, check_valid_int);
5125 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_y, check_valid_int);
5126 IIFORMAT_VALID_KEYWORD(xface, Q_foreground, check_valid_string);
5127 IIFORMAT_VALID_KEYWORD(xface, Q_background, check_valid_string);
5131 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xpm, "xpm");
5133 IIFORMAT_HAS_METHOD(xpm, validate);
5134 IIFORMAT_HAS_METHOD(xpm, normalize);
5135 IIFORMAT_HAS_METHOD(xpm, possible_dest_types);
5137 IIFORMAT_VALID_KEYWORD(xpm, Q_data, check_valid_string);
5138 IIFORMAT_VALID_KEYWORD(xpm, Q_file, check_valid_string);
5139 IIFORMAT_VALID_KEYWORD(xpm, Q_color_symbols,
5140 check_valid_xpm_color_symbols);
5141 #endif /* HAVE_XPM */
5144 void reinit_vars_of_glyphs(void)
5146 the_expose_ignore_blocktype =
5147 Blocktype_new(struct expose_ignore_blocktype);
5149 hold_ignored_expose_registration = 0;
5152 void vars_of_glyphs(void)
5154 reinit_vars_of_glyphs();
5156 Vthe_nothing_vector = vector1(Qnothing);
5157 staticpro(&Vthe_nothing_vector);
5159 /* image instances */
5161 Vimage_instance_type_list = Fcons(Qnothing,
5162 list6(Qtext, Qmono_pixmap,
5163 Qcolor_pixmap, Qpointer,
5164 Qsubwindow, Qwidget));
5165 staticpro(&Vimage_instance_type_list);
5169 Vglyph_type_list = list3(Qbuffer, Qpointer, Qicon);
5170 staticpro(&Vglyph_type_list);
5172 /* The octal-escape glyph, control-arrow-glyph and
5173 invisible-text-glyph are completely initialized in glyphs.el */
5175 DEFVAR_LISP("octal-escape-glyph", &Voctal_escape_glyph /*
5176 What to prefix character codes displayed in octal with.
5178 Voctal_escape_glyph =
5179 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5181 DEFVAR_LISP("control-arrow-glyph", &Vcontrol_arrow_glyph /*
5182 What to use as an arrow for control characters.
5184 Vcontrol_arrow_glyph = allocate_glyph(GLYPH_BUFFER,
5185 redisplay_glyph_changed);
5187 DEFVAR_LISP("invisible-text-glyph", &Vinvisible_text_glyph /*
5188 What to use to indicate the presence of invisible text.
5189 This is the glyph that is displayed when an ellipsis is called for
5190 \(see `selective-display-ellipses' and `buffer-invisibility-spec').
5191 Normally this is three dots ("...").
5193 Vinvisible_text_glyph = allocate_glyph(GLYPH_BUFFER,
5194 redisplay_glyph_changed);
5196 /* Partially initialized in glyphs.el */
5197 DEFVAR_LISP("hscroll-glyph", &Vhscroll_glyph /*
5198 What to display at the beginning of horizontally scrolled lines.
5200 Vhscroll_glyph = allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5201 #ifdef HAVE_WINDOW_SYSTEM
5207 DEFVAR_LISP("xpm-color-symbols", &Vxpm_color_symbols /*
5208 Definitions of logical color-names used when reading XPM files.
5209 Elements of this list should be of the form (COLOR-NAME FORM-TO-EVALUATE).
5210 The COLOR-NAME should be a string, which is the name of the color to define;
5211 the FORM should evaluate to a `color' specifier object, or a string to be
5212 passed to `make-color-instance'. If a loaded XPM file references a symbolic
5213 color called COLOR-NAME, it will display as the computed color instead.
5215 The default value of this variable defines the logical color names
5216 \"foreground\" and \"background\" to be the colors of the `default' face.
5218 Vxpm_color_symbols = Qnil; /* initialized in x-faces.el */
5219 #endif /* HAVE_XPM */
5224 DEFVAR_BOOL("disable-animated-pixmaps", &disable_animated_pixmaps /*
5225 Whether animated pixmaps should be animated.
5228 disable_animated_pixmaps = 0;
5231 void specifier_vars_of_glyphs(void)
5233 /* #### Can we GC here? The set_specifier_* calls definitely need */
5235 /* display tables */
5237 DEFVAR_SPECIFIER("current-display-table", &Vcurrent_display_table /*
5238 *The display table currently in use.
5239 This is a specifier; use `set-specifier' to change it.
5241 Display tables are used to control how characters are displayed. Each
5242 time that redisplay processes a character, it is looked up in all the
5243 display tables that apply (obtained by calling `specifier-instance' on
5244 `current-display-table' and any overriding display tables specified in
5245 currently active faces). The first entry found that matches the
5246 character determines how the character is displayed. If there is no
5247 matching entry, the default display method is used. (Non-control
5248 characters are displayed as themselves and control characters are
5249 displayed according to the buffer-local variable `ctl-arrow'. Control
5250 characters are further affected by `control-arrow-glyph' and
5251 `octal-escape-glyph'.)
5253 Each instantiator in this specifier and the display-table specifiers
5254 in faces is a display table or a list of such tables. If a list, each
5255 table will be searched in turn for an entry matching a particular
5256 character. Each display table is one of
5258 -- a vector, specifying values for characters starting at 0
5259 -- a char table, either of type `char' or `generic'
5262 Each entry in a display table should be one of
5264 -- nil (this entry is ignored and the search continues)
5265 -- a character (use this character; if it happens to be the same as
5266 the original character, default processing happens, otherwise
5267 redisplay attempts to display this character directly;
5268 #### At some point recursive display-table lookup will be
5270 -- a string (display each character in the string directly;
5271 #### At some point recursive display-table lookup will be
5273 -- a glyph (display the glyph;
5274 #### At some point recursive display-table lookup will be
5275 implemented when a string glyph is being processed.)
5276 -- a cons of the form (format "STRING") where STRING is a printf-like
5277 spec used to process the character. #### Unfortunately no
5278 formatting directives other than %% are implemented.
5279 -- a vector (each element of the vector is processed recursively;
5280 in such a case, nil elements in the vector are simply ignored)
5282 #### At some point in the near future, display tables are likely to
5283 be expanded to include other features, such as referencing characters
5284 in particular fonts and allowing the character search to continue
5285 all the way up the chain of specifier instantiators. These features
5286 are necessary to properly display Unicode characters.
5288 Vcurrent_display_table = Fmake_specifier(Qdisplay_table);
5289 set_specifier_fallback(Vcurrent_display_table,
5290 list1(Fcons(Qnil, Qnil)));
5291 set_specifier_caching(Vcurrent_display_table,
5292 offsetof(struct window, display_table),
5293 some_window_value_changed, 0, 0, 0);
5296 void complex_vars_of_glyphs(void)
5298 /* Partially initialized in glyphs-x.c, glyphs.el */
5299 DEFVAR_LISP("truncation-glyph", &Vtruncation_glyph /*
5300 What to display at the end of truncated lines.
5303 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5305 /* Partially initialized in glyphs-x.c, glyphs.el */
5306 DEFVAR_LISP("continuation-glyph", &Vcontinuation_glyph /*
5307 What to display at the end of wrapped lines.
5309 Vcontinuation_glyph =
5310 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5312 /* Partially initialized in glyphs-x.c, glyphs.el */
5313 DEFVAR_LISP("sxemacs-logo", &Vsxemacs_logo /*
5314 The glyph used to display the SXEmacs logo at startup.
5316 Vsxemacs_logo = allocate_glyph(GLYPH_BUFFER, 0);