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"
52 Lisp_Object Qimage_conversion_error;
54 Lisp_Object Qglyphp, Qcontrib_p, Qbaseline;
55 Lisp_Object Qbuffer_glyph_p, Qpointer_glyph_p, Qicon_glyph_p;
56 Lisp_Object Qnothing_image_instance_p, Qtext_image_instance_p;
57 Lisp_Object Qmono_pixmap_image_instance_p;
58 Lisp_Object Qcolor_pixmap_image_instance_p;
59 Lisp_Object Qpointer_image_instance_p;
60 Lisp_Object Qsubwindow_image_instance_p;
61 Lisp_Object Qwidget_image_instance_p;
62 Lisp_Object Qconst_glyph_variable;
63 Lisp_Object Qmono_pixmap, Qcolor_pixmap, Qsubwindow;
64 Lisp_Object Q_file, Q_data, Q_face, Q_pixel_width, Q_pixel_height;
65 Lisp_Object Qformatted_string;
66 Lisp_Object Vcurrent_display_table;
67 Lisp_Object Vtruncation_glyph, Vcontinuation_glyph, Voctal_escape_glyph;
68 Lisp_Object Vcontrol_arrow_glyph, Vinvisible_text_glyph, Vhscroll_glyph;
69 Lisp_Object Vsxemacs_logo;
70 Lisp_Object Vthe_nothing_vector;
71 Lisp_Object Vimage_instantiator_format_list;
72 Lisp_Object Vimage_instance_type_list;
73 Lisp_Object Vglyph_type_list;
75 int disable_animated_pixmaps;
77 DEFINE_IMAGE_INSTANTIATOR_FORMAT(nothing);
78 DEFINE_IMAGE_INSTANTIATOR_FORMAT(inherit);
79 DEFINE_IMAGE_INSTANTIATOR_FORMAT(string);
80 DEFINE_IMAGE_INSTANTIATOR_FORMAT(formatted_string);
81 DEFINE_IMAGE_INSTANTIATOR_FORMAT(subwindow);
82 DEFINE_IMAGE_INSTANTIATOR_FORMAT(text);
83 DEFINE_IMAGE_INSTANTIATOR_FORMAT(pointer);
85 Lisp_Object Q_mask_file, Q_mask_data, Q_hotspot_x, Q_hotspot_y;
86 Lisp_Object Q_foreground, Q_background;
88 #ifdef HAVE_WINDOW_SYSTEM
89 DEFINE_IMAGE_INSTANTIATOR_FORMAT(xbm);
93 #define BitmapSuccess 0
94 #define BitmapOpenFailed 1
95 #define BitmapFileInvalid 2
96 #define BitmapNoMemory 3
101 DEFINE_IMAGE_INSTANTIATOR_FORMAT(xface);
106 DEFINE_IMAGE_INSTANTIATOR_FORMAT(xpm);
108 Lisp_Object Q_color_symbols;
111 typedef struct image_instantiator_format_entry image_instantiator_format_entry;
112 struct image_instantiator_format_entry {
115 struct image_instantiator_methods *meths;
119 Dynarr_declare(struct image_instantiator_format_entry);
120 } image_instantiator_format_entry_dynarr;
122 /* This contains one entry per format, per device it's defined on. */
123 image_instantiator_format_entry_dynarr
124 *the_image_instantiator_format_entry_dynarr;
126 static Lisp_Object allocate_image_instance(Lisp_Object governing_domain,
128 Lisp_Object instantiator);
129 static void image_validate(Lisp_Object instantiator);
130 static void glyph_property_was_changed(Lisp_Object glyph,
131 Lisp_Object property,
133 static void set_image_instance_dirty_p(Lisp_Object instance, int dirty);
134 static void register_ignored_expose(struct frame *f, int x, int y, int width,
136 static void cache_subwindow_instance_in_frame_maybe(Lisp_Object instance);
137 static void update_image_instance(Lisp_Object image_instance,
138 Lisp_Object instantiator);
139 /* Unfortunately windows and X are different. In windows BeginPaint()
140 will prevent WM_PAINT messages being generated so it is unnecessary
141 to register exposures as they will not occur. Under X they will
143 int hold_ignored_expose_registration;
145 EXFUN(Fimage_instance_type, 1);
146 EXFUN(Fglyph_type, 1);
147 EXFUN(Fnext_window, 4);
149 /****************************************************************************
150 * Image Instantiators *
151 ****************************************************************************/
153 struct image_instantiator_methods *decode_device_ii_format(Lisp_Object device,
159 if (!SYMBOLP(format)) {
160 if (ERRB_EQ(errb, ERROR_ME))
161 CHECK_SYMBOL(format);
166 i < Dynarr_length(the_image_instantiator_format_entry_dynarr);
170 Dynarr_at(the_image_instantiator_format_entry_dynarr,
174 (the_image_instantiator_format_entry_dynarr,
176 if ((NILP(d) && NILP(device))
179 EQ(CONSOLE_TYPE(XCONSOLE
180 (DEVICE_CONSOLE(XDEVICE(device)))),
184 (the_image_instantiator_format_entry_dynarr,
189 maybe_signal_simple_error("Invalid image-instantiator format", format,
195 struct image_instantiator_methods *decode_image_instantiator_format(Lisp_Object
200 return decode_device_ii_format(Qnil, format, errb);
204 valid_image_instantiator_format_p(Lisp_Object format, Lisp_Object locale)
207 struct image_instantiator_methods *meths =
208 decode_image_instantiator_format(format, ERROR_ME_NOT);
209 Lisp_Object contype = Qnil;
210 /* mess with the locale */
211 if (!NILP(locale) && SYMBOLP(locale))
214 struct console *console = decode_console(locale);
215 contype = console ? CONSOLE_TYPE(console) : locale;
217 /* nothing is valid in all locales */
218 if (EQ(format, Qnothing))
220 /* reject unknown formats */
221 else if (NILP(contype) || !meths)
224 for (i = 0; i < Dynarr_length(meths->consoles); i++)
225 if (EQ(contype, Dynarr_at(meths->consoles, i).symbol))
230 DEFUN("valid-image-instantiator-format-p", Fvalid_image_instantiator_format_p, 1, 2, 0, /*
231 Given an IMAGE-INSTANTIATOR-FORMAT, return non-nil if it is valid.
232 If LOCALE is non-nil then the format is checked in that locale.
233 If LOCALE is nil the current console is used.
235 Valid formats are some subset of 'nothing, 'string, 'formatted-string,
236 'xpm, 'xbm, 'xface, 'gif, 'jpeg, 'png, 'tiff, 'cursor-font, 'font,
237 'autodetect, 'subwindow, 'inherit, 'mswindows-resource, 'bmp,
238 'native-layout, 'layout, 'label, 'tab-control, 'tree-view,
239 'progress-gauge, 'scrollbar, 'combo-box, 'edit-field, 'button,
240 'widget, 'pointer, and 'text, depending on how SXEmacs was compiled.
242 (image_instantiator_format, locale))
244 return valid_image_instantiator_format_p(image_instantiator_format,
248 DEFUN("image-instantiator-format-list", Fimage_instantiator_format_list, 0, 0, 0, /*
249 Return a list of valid image-instantiator formats.
253 return Fcopy_sequence(Vimage_instantiator_format_list);
257 add_entry_to_device_ii_format_list(Lisp_Object device, Lisp_Object symbol,
258 struct image_instantiator_methods *meths)
260 struct image_instantiator_format_entry entry;
262 entry.symbol = symbol;
263 entry.device = device;
265 Dynarr_add(the_image_instantiator_format_entry_dynarr, entry);
266 if (NILP(memq_no_quit(symbol, Vimage_instantiator_format_list)))
267 Vimage_instantiator_format_list =
268 Fcons(symbol, Vimage_instantiator_format_list);
271 void add_entry_to_image_instantiator_format_list(Lisp_Object symbol, struct
272 image_instantiator_methods
275 add_entry_to_device_ii_format_list(Qnil, symbol, meths);
278 static Lisp_Object *get_image_conversion_list(Lisp_Object console_type)
280 return &decode_console_type(console_type,
281 ERROR_ME)->image_conversion_list;
284 DEFUN("set-console-type-image-conversion-list", Fset_console_type_image_conversion_list, 2, 2, 0, /*
285 Set the image-conversion-list for consoles of the given CONSOLE-TYPE.
286 The image-conversion-list specifies how image instantiators that
287 are strings should be interpreted. Each element of the list should be
288 a list of two elements (a regular expression string and a vector) or
289 a list of three elements (the preceding two plus an integer index into
290 the vector). The string is converted to the vector associated with the
291 first matching regular expression. If a vector index is specified, the
292 string itself is substituted into that position in the vector.
294 Note: The conversion above is applied when the image instantiator is
295 added to an image specifier, not when the specifier is actually
296 instantiated. Therefore, changing the image-conversion-list only affects
297 newly-added instantiators. Existing instantiators in glyphs and image
298 specifiers will not be affected.
300 (console_type, list))
303 Lisp_Object *imlist = get_image_conversion_list(console_type);
305 /* Check the list to make sure that it only has valid entries. */
307 EXTERNAL_LIST_LOOP(tail, list) {
308 Lisp_Object mapping = XCAR(tail);
310 /* Mapping form should be (STRING VECTOR) or (STRING VECTOR INTEGER) */
311 if (!CONSP(mapping) ||
312 !CONSP(XCDR(mapping)) ||
313 (!NILP(XCDR(XCDR(mapping))) &&
314 (!CONSP(XCDR(XCDR(mapping))) ||
315 !NILP(XCDR(XCDR(XCDR(mapping)))))))
316 signal_simple_error("Invalid mapping form", mapping);
318 Lisp_Object mapexp = XCAR(mapping);
319 Lisp_Object typevec = XCAR(XCDR(mapping));
320 Lisp_Object pos = Qnil;
324 CHECK_STRING(mapexp);
325 CHECK_VECTOR(typevec);
326 if (!NILP(XCDR(XCDR(mapping)))) {
327 pos = XCAR(XCDR(XCDR(mapping)));
330 XINT(pos) >= XVECTOR_LENGTH(typevec))
333 make_int(XVECTOR_LENGTH(typevec) -
337 newvec = Fcopy_sequence(typevec);
339 XVECTOR_DATA(newvec)[XINT(pos)] = mapexp;
341 image_validate(newvec);
346 *imlist = Fcopy_tree(list, Qt);
350 DEFUN("console-type-image-conversion-list", Fconsole_type_image_conversion_list, 1, 1, 0, /*
351 Return the image-conversion-list for devices of the given CONSOLE-TYPE.
352 The image-conversion-list specifies how to interpret image string
353 instantiators for the specified console type. See
354 `set-console-type-image-conversion-list' for a description of its syntax.
358 return Fcopy_tree(*get_image_conversion_list(console_type), Qt);
361 /* Process a string instantiator according to the image-conversion-list for
362 CONSOLE_TYPE. Returns a vector. */
365 process_image_string_instantiator(Lisp_Object data,
366 Lisp_Object console_type, int dest_mask)
370 LIST_LOOP(tail, *get_image_conversion_list(console_type)) {
371 Lisp_Object mapping = XCAR(tail);
372 Lisp_Object mapexp = XCAR(mapping);
373 Lisp_Object typevec = XCAR(XCDR(mapping));
375 /* if the result is of a type that can't be instantiated
376 (e.g. a string when we're dealing with a pointer glyph),
379 IIFORMAT_METH(decode_image_instantiator_format
380 (INSTANTIATOR_TYPE(typevec), ERROR_ME),
381 possible_dest_types, ())))
383 if (fast_string_match(mapexp, 0, data, 0, -1, 0, ERROR_ME, 0) >=
385 if (!NILP(XCDR(XCDR(mapping)))) {
386 int pos = XINT(XCAR(XCDR(XCDR(mapping))));
387 Lisp_Object newvec = Fcopy_sequence(typevec);
388 XVECTOR_DATA(newvec)[pos] = data;
396 signal_simple_error("Unable to interpret glyph instantiator", data);
402 find_keyword_in_vector_or_given(Lisp_Object vector, Lisp_Object keyword,
403 Lisp_Object default_)
406 int instantiator_len;
408 elt = XVECTOR_DATA(vector);
409 instantiator_len = XVECTOR_LENGTH(vector);
414 while (instantiator_len > 0) {
415 if (EQ(elt[0], keyword))
418 instantiator_len -= 2;
424 Lisp_Object find_keyword_in_vector(Lisp_Object vector, Lisp_Object keyword)
426 return find_keyword_in_vector_or_given(vector, keyword, Qnil);
430 find_instantiator_differences(Lisp_Object new, Lisp_Object old)
432 Lisp_Object alist = Qnil;
433 Lisp_Object *elt = XVECTOR_DATA(new);
434 Lisp_Object *old_elt = XVECTOR_DATA(old);
435 int len = XVECTOR_LENGTH(new);
438 /* If the vector length has changed then consider everything
439 changed. We could try and figure out what properties have
440 disappeared or been added, but this code is only used as an
441 optimization anyway so lets not bother. */
442 if (len != XVECTOR_LENGTH(old))
447 for (len -= 2; len >= 1; len -= 2) {
448 /* Keyword comparisons can be done with eq, the value must be
450 #### Note that this does not optimize re-ordering. */
451 if (!EQ(elt[len], old_elt[len])
452 || !internal_equal(elt[len + 1], old_elt[len + 1], 0))
453 alist = Fcons(Fcons(elt[len], elt[len + 1]), alist);
457 Lisp_Object result = alist_to_tagged_vector(elt[0], alist);
459 RETURN_UNGCPRO(result);
463 DEFUN("set-instantiator-property", Fset_instantiator_property, 3, 3, 0, /*
464 Destructively set the property KEYWORD of INSTANTIATOR to VALUE.
465 If the property is not set then it is added to a copy of the
466 instantiator and the new instantiator returned.
467 Use `set-glyph-image' on glyphs to register instantiator changes.
469 (instantiator, keyword, value))
474 CHECK_VECTOR(instantiator);
475 if (!KEYWORDP(keyword))
476 signal_simple_error("instantiator property must be a keyword",
479 elt = XVECTOR_DATA(instantiator);
480 len = XVECTOR_LENGTH(instantiator);
482 for (len -= 2; len >= 1; len -= 2) {
483 if (EQ(elt[len], keyword)) {
484 elt[len + 1] = value;
489 /* Didn't find it so add it. */
491 Lisp_Object alist = Qnil, result;
495 alist = tagged_vector_to_alist(instantiator);
496 alist = Fcons(Fcons(keyword, value), alist);
497 result = alist_to_tagged_vector(elt[0], alist);
499 RETURN_UNGCPRO(result);
505 void check_valid_string(Lisp_Object data)
510 void check_valid_vector(Lisp_Object data)
515 void check_valid_face(Lisp_Object data)
520 void check_valid_int(Lisp_Object data)
525 void file_or_data_must_be_present(Lisp_Object instantiator)
527 if (NILP(find_keyword_in_vector(instantiator, Q_file)) &&
528 NILP(find_keyword_in_vector(instantiator, Q_data)))
529 signal_simple_error("Must supply either :file or :data",
533 void data_must_be_present(Lisp_Object instantiator)
535 if (NILP(find_keyword_in_vector(instantiator, Q_data)))
536 signal_simple_error("Must supply :data", instantiator);
539 static void face_must_be_present(Lisp_Object instantiator)
541 if (NILP(find_keyword_in_vector(instantiator, Q_face)))
542 signal_simple_error("Must supply :face", instantiator);
545 /* utility function useful in retrieving data from a file. */
547 Lisp_Object make_string_from_file(Lisp_Object file)
549 /* This function can call lisp */
550 int count = specpdl_depth();
551 Lisp_Object temp_buffer;
555 specbind(Qinhibit_quit, Qt);
556 record_unwind_protect(Fset_buffer, Fcurrent_buffer());
557 temp_buffer = Fget_buffer_create(build_string(" *pixmap conversion*"));
559 set_buffer_internal(XBUFFER(temp_buffer));
561 specbind(intern("format-alist"), Qnil);
562 Finsert_file_contents_internal(file, Qnil, Qnil, Qnil, Qnil, Qnil,
564 data = Fbuffer_substring(Qnil, Qnil, Qnil);
565 unbind_to(count, Qnil);
570 /* The following two functions are provided to make it easier for
571 the normalize methods to work with keyword-value vectors.
572 Hash tables are kind of heavyweight for this purpose.
573 (If vectors were resizable, we could avoid this problem;
574 but they're not.) An alternative approach that might be
575 more efficient but require more work is to use a type of
576 assoc-Dynarr and provide primitives for deleting elements out
577 of it. (However, you'd also have to add an unwind-protect
578 to make sure the Dynarr got freed in case of an error in
579 the normalization process.) */
581 Lisp_Object tagged_vector_to_alist(Lisp_Object vector)
583 Lisp_Object *elt = XVECTOR_DATA(vector);
584 int len = XVECTOR_LENGTH(vector);
585 Lisp_Object result = Qnil;
588 for (len -= 2; len >= 1; len -= 2)
589 result = Fcons(Fcons(elt[len], elt[len + 1]), result);
594 Lisp_Object alist_to_tagged_vector(Lisp_Object tag, Lisp_Object alist)
596 int len = 1 + 2 * XINT(Flength(alist));
597 Lisp_Object *elt = alloca_array(Lisp_Object, len);
603 LIST_LOOP(rest, alist) {
604 Lisp_Object pair = XCAR(rest);
606 elt[i + 1] = XCDR(pair);
610 return Fvector(len, elt);
613 #ifdef ERROR_CHECK_GLYPHS
615 check_instance_cache_mapper(Lisp_Object key, Lisp_Object value,
618 /* This function can GC */
619 /* value can be nil; we cache failures as well as successes */
622 VOID_TO_LISP(window, flag_closure);
623 assert(EQ(XIMAGE_INSTANCE_DOMAIN(value), window));
629 void check_window_subwindow_cache(struct window *w)
633 XSETWINDOW(window, w);
635 assert(!NILP(w->subwindow_instance_cache));
636 elisp_maphash(check_instance_cache_mapper,
637 w->subwindow_instance_cache, LISP_TO_VOID(window));
640 void check_image_instance_structure(Lisp_Object instance)
642 /* Weird nothing images exist at startup when the console is
644 if (!NOTHING_IMAGE_INSTANCEP(instance)) {
645 assert(DOMAIN_LIVE_P(instance));
646 assert(VECTORP(XIMAGE_INSTANCE_INSTANTIATOR(instance)));
648 if (WINDOWP(XIMAGE_INSTANCE_DOMAIN(instance)))
649 check_window_subwindow_cache
650 (XWINDOW(XIMAGE_INSTANCE_DOMAIN(instance)));
654 /* Determine what kind of domain governs the image instance.
655 Verify that the given domain is at least as specific, and extract
656 the governing domain from it. */
658 get_image_instantiator_governing_domain(Lisp_Object instantiator,
661 int governing_domain;
663 struct image_instantiator_methods *meths =
664 decode_image_instantiator_format(INSTANTIATOR_TYPE(instantiator),
666 governing_domain = IIFORMAT_METH_OR_GIVEN(meths, governing_domain, (),
667 GOVERNING_DOMAIN_DEVICE);
669 if (governing_domain == GOVERNING_DOMAIN_WINDOW
670 && NILP(DOMAIN_WINDOW(domain)))
671 signal_simple_error_2
672 ("Domain for this instantiator must be resolvable to a window",
673 instantiator, domain);
674 else if (governing_domain == GOVERNING_DOMAIN_FRAME
675 && NILP(DOMAIN_FRAME(domain)))
676 signal_simple_error_2
677 ("Domain for this instantiator must be resolvable to a frame",
678 instantiator, domain);
680 if (governing_domain == GOVERNING_DOMAIN_WINDOW)
681 domain = DOMAIN_WINDOW(domain);
682 else if (governing_domain == GOVERNING_DOMAIN_FRAME)
683 domain = DOMAIN_FRAME(domain);
684 else if (governing_domain == GOVERNING_DOMAIN_DEVICE)
685 domain = DOMAIN_DEVICE(domain);
693 normalize_image_instantiator(Lisp_Object instantiator,
694 Lisp_Object contype, Lisp_Object dest_mask)
696 if (IMAGE_INSTANCEP(instantiator))
699 if (STRINGP(instantiator))
701 process_image_string_instantiator(instantiator, contype,
703 /* Subsequent validation will pick this up. */
704 if (!VECTORP(instantiator))
706 /* We have to always store the actual pixmap data and not the
707 filename even though this is a potential memory pig. We have to
708 do this because it is quite possible that we will need to
709 instantiate a new instance of the pixmap and the file will no
710 longer exist (e.g. w3 pixmaps are almost always from temporary
714 struct image_instantiator_methods *meths;
716 GCPRO1(instantiator);
719 decode_image_instantiator_format(INSTANTIATOR_TYPE
720 (instantiator), ERROR_ME);
721 RETURN_UNGCPRO(IIFORMAT_METH_OR_GIVEN
723 (instantiator, contype, dest_mask),
729 instantiate_image_instantiator(Lisp_Object governing_domain,
731 Lisp_Object instantiator,
732 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
733 int dest_mask, Lisp_Object glyph)
735 Lisp_Object ii = allocate_image_instance(governing_domain,
736 IMAGE_INSTANCEP(domain) ?
737 domain : glyph, instantiator);
738 Lisp_Image_Instance *p = XIMAGE_INSTANCE(ii);
739 struct image_instantiator_methods *meths, *device_meths;
743 if (!valid_image_instantiator_format_p(INSTANTIATOR_TYPE(instantiator),
744 DOMAIN_DEVICE(governing_domain)))
746 ("Image instantiator format is invalid in this locale.",
750 decode_image_instantiator_format(INSTANTIATOR_TYPE(instantiator),
752 MAYBE_IIFORMAT_METH(meths, instantiate,
753 (ii, instantiator, pointer_fg, pointer_bg,
756 /* Now do device specific instantiation. */
757 device_meths = decode_device_ii_format(DOMAIN_DEVICE(governing_domain),
758 INSTANTIATOR_TYPE(instantiator),
761 if (!HAS_IIFORMAT_METH_P(meths, instantiate)
763 || !HAS_IIFORMAT_METH_P(device_meths, instantiate)))
765 ("Don't know how to instantiate this image instantiator?",
768 /* In general native window system methods will require sane
769 geometry values, thus the instance needs to have been laid-out
770 before they get called. */
771 image_instance_layout(ii, XIMAGE_INSTANCE_WIDTH(ii),
772 XIMAGE_INSTANCE_HEIGHT(ii),
773 IMAGE_UNCHANGED_GEOMETRY,
774 IMAGE_UNCHANGED_GEOMETRY, domain);
776 MAYBE_IIFORMAT_METH(device_meths, instantiate,
777 (ii, instantiator, pointer_fg, pointer_bg,
779 /* Do post instantiation. */
780 MAYBE_IIFORMAT_METH(meths, post_instantiate,
781 (ii, instantiator, domain));
782 MAYBE_IIFORMAT_METH(device_meths, post_instantiate,
783 (ii, instantiator, domain));
786 IMAGE_INSTANCE_INITIALIZED(p) = 1;
787 /* Now that we're done verify that we really are laid out. */
788 if (IMAGE_INSTANCE_LAYOUT_CHANGED(p))
789 image_instance_layout(ii, XIMAGE_INSTANCE_WIDTH(ii),
790 XIMAGE_INSTANCE_HEIGHT(ii),
791 IMAGE_UNCHANGED_GEOMETRY,
792 IMAGE_UNCHANGED_GEOMETRY, domain);
794 /* We *must* have a clean image at this point. */
795 IMAGE_INSTANCE_TEXT_CHANGED(p) = 0;
796 IMAGE_INSTANCE_SIZE_CHANGED(p) = 0;
797 IMAGE_INSTANCE_LAYOUT_CHANGED(p) = 0;
798 IMAGE_INSTANCE_DIRTYP(p) = 0;
800 assert(XIMAGE_INSTANCE_HEIGHT(ii) >= 0
801 && XIMAGE_INSTANCE_WIDTH(ii) >= 0);
803 ERROR_CHECK_IMAGE_INSTANCE(ii);
808 /****************************************************************************
809 * Image-Instance Object *
810 ****************************************************************************/
812 Lisp_Object Qimage_instancep;
814 static Lisp_Object mark_image_instance(Lisp_Object obj)
816 Lisp_Image_Instance *i = XIMAGE_INSTANCE(obj);
818 /* #### I want to check the instance here, but there are way too
819 many instances of the instance being marked while the domain is
820 dead. For instance you can get marked through an event when using
823 ERROR_CHECK_IMAGE_INSTANCE(obj);
826 mark_object(i->name);
827 mark_object(i->instantiator);
828 /* Is this legal in marking? We may get in the situation where the
829 domain has been deleted - making the instance unusable. It seems
830 better to remove the domain so that it can be finalized. */
831 if (!DOMAIN_LIVE_P(i->domain))
834 mark_object(i->domain);
836 /* We don't mark the glyph reference since that would create a
837 circularity preventing GC. Ditto the instantiator. */
838 switch (IMAGE_INSTANCE_TYPE(i)) {
840 mark_object(IMAGE_INSTANCE_TEXT_STRING(i));
842 case IMAGE_MONO_PIXMAP:
843 case IMAGE_COLOR_PIXMAP:
844 mark_object(IMAGE_INSTANCE_PIXMAP_FILENAME(i));
845 mark_object(IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i));
846 mark_object(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i));
847 mark_object(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i));
848 mark_object(IMAGE_INSTANCE_PIXMAP_FG(i));
849 mark_object(IMAGE_INSTANCE_PIXMAP_BG(i));
853 mark_object(IMAGE_INSTANCE_WIDGET_TYPE(i));
854 mark_object(IMAGE_INSTANCE_WIDGET_PROPS(i));
855 mark_object(IMAGE_INSTANCE_SUBWINDOW_FACE(i));
856 mark_object(IMAGE_INSTANCE_WIDGET_ITEMS(i));
857 mark_object(IMAGE_INSTANCE_LAYOUT_CHILDREN(i));
858 mark_object(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(i));
859 mark_object(IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i));
860 mark_object(IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i));
861 case IMAGE_SUBWINDOW:
871 /* The image may have been previously finalized (yes that's weird,
872 see Fdelete_frame() and mark_window_as_deleted()), in which case
873 the domain will be nil, so cope with this. */
874 if (!NILP(IMAGE_INSTANCE_DEVICE(i)))
875 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(i)),
876 mark_image_instance, (i));
882 print_image_instance(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
884 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(obj);
887 error("printing unreadable object #<image-instance 0x%x>",
889 write_c_string("#<image-instance (", printcharfun);
890 print_internal(Fimage_instance_type(obj), printcharfun, 0);
891 write_c_string(") ", printcharfun);
892 if (!NILP(ii->name)) {
893 print_internal(ii->name, printcharfun, 1);
894 write_c_string(" ", printcharfun);
896 write_c_string("on ", printcharfun);
897 print_internal(ii->domain, printcharfun, 0);
898 write_c_string(" ", printcharfun);
899 switch (IMAGE_INSTANCE_TYPE(ii)) {
904 print_internal(IMAGE_INSTANCE_TEXT_STRING(ii), printcharfun, 1);
907 case IMAGE_MONO_PIXMAP:
908 case IMAGE_COLOR_PIXMAP:
910 if (STRINGP(IMAGE_INSTANCE_PIXMAP_FILENAME(ii))) {
912 Lisp_Object filename =
913 IMAGE_INSTANCE_PIXMAP_FILENAME(ii);
914 s = strrchr((char *)XSTRING_DATA(filename), '/');
916 print_internal(build_string(s + 1),
919 print_internal(filename, printcharfun, 1);
921 if (IMAGE_INSTANCE_PIXMAP_DEPTH(ii) > 1)
922 write_fmt_str(printcharfun, " %dx%dx%d",
923 IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
924 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii),
925 IMAGE_INSTANCE_PIXMAP_DEPTH(ii));
927 write_fmt_str(printcharfun, " %dx%d", IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
928 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii));
929 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) ||
930 !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
931 write_c_string(" @", printcharfun);
932 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii))) {
933 write_fmt_str(printcharfun,"%ld",
934 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)));
936 write_c_string("??", printcharfun);
937 write_c_string(",", printcharfun);
938 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
939 write_fmt_str(printcharfun,"%ld",
940 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii)));
942 write_c_string("??", printcharfun);
944 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii)) ||
945 !NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
946 write_c_string(" (", printcharfun);
947 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii))) {
950 (IMAGE_INSTANCE_PIXMAP_FG(ii))->name,
953 write_c_string("/", printcharfun);
954 if (!NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
957 (IMAGE_INSTANCE_PIXMAP_BG(ii))->name,
960 write_c_string(")", printcharfun);
965 print_internal(IMAGE_INSTANCE_WIDGET_TYPE(ii), printcharfun, 0);
967 if (GUI_ITEMP(IMAGE_INSTANCE_WIDGET_ITEM(ii))) {
968 write_c_string(" ", printcharfun);
969 print_internal(IMAGE_INSTANCE_WIDGET_TEXT(ii),
973 if (!NILP(IMAGE_INSTANCE_WIDGET_FACE(ii))) {
974 write_c_string(" face=", printcharfun);
976 (IMAGE_INSTANCE_WIDGET_FACE(ii), printcharfun, 0);
980 case IMAGE_SUBWINDOW:
981 write_fmt_str(printcharfun, " %dx%d", IMAGE_INSTANCE_WIDTH(ii),
982 IMAGE_INSTANCE_HEIGHT(ii));
984 /* This is stolen from frame.c. Subwindows are strange in that they
985 are specific to a particular frame so we want to print in their
986 description what that frame is. */
988 write_c_string(" on #<", printcharfun);
990 struct frame *f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
992 if (!FRAME_LIVE_P(f))
993 write_c_string("dead", printcharfun);
995 write_c_string(DEVICE_TYPE_NAME
996 (XDEVICE(FRAME_DEVICE(f))),
999 write_c_string("-frame>", printcharfun);
1000 write_hex_ptr( IMAGE_INSTANCE_SUBWINDOW_ID(ii), printcharfun);
1009 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain), print_image_instance,
1010 (ii, printcharfun, escapeflag));
1011 write_fmt_str(printcharfun, " 0x%x>", ii->header.uid);
1014 static void finalize_image_instance(void *header, int for_disksave)
1016 Lisp_Image_Instance *i = (Lisp_Image_Instance *) header;
1018 /* objects like this exist at dump time, so don't bomb out. */
1019 if (IMAGE_INSTANCE_TYPE(i) == IMAGE_NOTHING
1020 || NILP(IMAGE_INSTANCE_DEVICE(i)))
1025 /* We can't use the domain here, because it might have
1027 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(i)),
1028 finalize_image_instance, (i));
1030 /* Make sure we don't try this twice. */
1031 IMAGE_INSTANCE_DEVICE(i) = Qnil;
1034 static int image_instance_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
1036 Lisp_Image_Instance *i1 = XIMAGE_INSTANCE(obj1);
1037 Lisp_Image_Instance *i2 = XIMAGE_INSTANCE(obj2);
1039 ERROR_CHECK_IMAGE_INSTANCE(obj1);
1040 ERROR_CHECK_IMAGE_INSTANCE(obj2);
1042 if (!EQ(IMAGE_INSTANCE_DOMAIN(i1), IMAGE_INSTANCE_DOMAIN(i2))
1043 || IMAGE_INSTANCE_TYPE(i1) != IMAGE_INSTANCE_TYPE(i2)
1044 || IMAGE_INSTANCE_WIDTH(i1) != IMAGE_INSTANCE_WIDTH(i2)
1045 || IMAGE_INSTANCE_MARGIN_WIDTH(i1) !=
1046 IMAGE_INSTANCE_MARGIN_WIDTH(i2)
1047 || IMAGE_INSTANCE_HEIGHT(i1) != IMAGE_INSTANCE_HEIGHT(i2)
1048 || IMAGE_INSTANCE_XOFFSET(i1) != IMAGE_INSTANCE_XOFFSET(i2)
1049 || IMAGE_INSTANCE_YOFFSET(i1) != IMAGE_INSTANCE_YOFFSET(i2))
1051 if (!internal_equal(IMAGE_INSTANCE_NAME(i1), IMAGE_INSTANCE_NAME(i2),
1054 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(i1),
1055 IMAGE_INSTANCE_INSTANTIATOR(i2), depth + 1))
1058 switch (IMAGE_INSTANCE_TYPE(i1)) {
1063 if (!internal_equal(IMAGE_INSTANCE_TEXT_STRING(i1),
1064 IMAGE_INSTANCE_TEXT_STRING(i2), depth + 1))
1068 case IMAGE_MONO_PIXMAP:
1069 case IMAGE_COLOR_PIXMAP:
1071 if (!(IMAGE_INSTANCE_PIXMAP_DEPTH(i1) ==
1072 IMAGE_INSTANCE_PIXMAP_DEPTH(i2) &&
1073 IMAGE_INSTANCE_PIXMAP_SLICE(i1) ==
1074 IMAGE_INSTANCE_PIXMAP_SLICE(i2) &&
1075 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i1),
1076 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i2)) &&
1077 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i1),
1078 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i2)) &&
1079 internal_equal(IMAGE_INSTANCE_PIXMAP_FILENAME(i1),
1080 IMAGE_INSTANCE_PIXMAP_FILENAME(i2),
1082 internal_equal(IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i1),
1083 IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i2),
1089 if (!(EQ(IMAGE_INSTANCE_WIDGET_TYPE(i1),
1090 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1091 && IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1092 IMAGE_INSTANCE_SUBWINDOW_ID(i2)
1094 EQ(IMAGE_INSTANCE_WIDGET_FACE(i1),
1095 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1096 && internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(i1),
1097 IMAGE_INSTANCE_WIDGET_ITEMS(i2),
1099 && internal_equal(IMAGE_INSTANCE_LAYOUT_CHILDREN(i1),
1100 IMAGE_INSTANCE_LAYOUT_CHILDREN(i2),
1102 && internal_equal(IMAGE_INSTANCE_WIDGET_PROPS(i1),
1103 IMAGE_INSTANCE_WIDGET_PROPS(i2),
1105 && internal_equal(IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i1),
1106 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i2),
1108 && internal_equal(IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i1),
1109 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i2),
1115 case IMAGE_SUBWINDOW:
1116 if (!(IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1117 IMAGE_INSTANCE_SUBWINDOW_ID(i2)))
1126 return DEVMETH_OR_GIVEN(DOMAIN_XDEVICE(i1->domain),
1127 image_instance_equal, (i1, i2, depth), 1);
1130 /* Image instance domain manipulators. We can't error check in these
1131 otherwise we get into infinite recursion. */
1132 Lisp_Object image_instance_device(Lisp_Object instance)
1134 return XIMAGE_INSTANCE_DEVICE(instance);
1137 Lisp_Object image_instance_frame(Lisp_Object instance)
1139 return XIMAGE_INSTANCE_FRAME(instance);
1142 Lisp_Object image_instance_window(Lisp_Object instance)
1144 return DOMAIN_WINDOW(XIMAGE_INSTANCE_DOMAIN(instance));
1147 int image_instance_live_p(Lisp_Object instance)
1149 return DOMAIN_LIVE_P(XIMAGE_INSTANCE_DOMAIN(instance));
1152 static unsigned long image_instance_hash(Lisp_Object obj, int depth)
1154 Lisp_Image_Instance *i = XIMAGE_INSTANCE(obj);
1155 unsigned long hash = HASH5(LISP_HASH(IMAGE_INSTANCE_DOMAIN(i)),
1156 IMAGE_INSTANCE_WIDTH(i),
1157 IMAGE_INSTANCE_MARGIN_WIDTH(i),
1158 IMAGE_INSTANCE_HEIGHT(i),
1159 internal_hash(IMAGE_INSTANCE_INSTANTIATOR(i),
1162 ERROR_CHECK_IMAGE_INSTANCE(obj);
1164 switch (IMAGE_INSTANCE_TYPE(i)) {
1169 hash = HASH2(hash, internal_hash(IMAGE_INSTANCE_TEXT_STRING(i),
1173 case IMAGE_MONO_PIXMAP:
1174 case IMAGE_COLOR_PIXMAP:
1176 hash = HASH4(hash, IMAGE_INSTANCE_PIXMAP_DEPTH(i),
1177 IMAGE_INSTANCE_PIXMAP_SLICE(i),
1178 internal_hash(IMAGE_INSTANCE_PIXMAP_FILENAME(i),
1183 /* We need the hash to be equivalent to what should be
1186 LISP_HASH(IMAGE_INSTANCE_WIDGET_TYPE(i)),
1187 internal_hash(IMAGE_INSTANCE_WIDGET_PROPS(i),
1189 internal_hash(IMAGE_INSTANCE_WIDGET_ITEMS(i),
1191 internal_hash(IMAGE_INSTANCE_LAYOUT_CHILDREN(i),
1193 case IMAGE_SUBWINDOW:
1194 hash = HASH2(hash, (EMACS_INT) IMAGE_INSTANCE_SUBWINDOW_ID(i));
1203 Lisp_Object tmp = image_instance_device(obj);
1204 return HASH2(hash, DEVMETH_OR_GIVEN(
1205 XDEVICE(tmp), image_instance_hash,
1210 DEFINE_LRECORD_IMPLEMENTATION("image-instance", image_instance,
1211 mark_image_instance, print_image_instance,
1212 finalize_image_instance, image_instance_equal,
1213 image_instance_hash, 0, Lisp_Image_Instance);
1216 allocate_image_instance(Lisp_Object governing_domain, Lisp_Object parent,
1217 Lisp_Object instantiator)
1219 Lisp_Image_Instance *lp =
1220 alloc_lcrecord_type(Lisp_Image_Instance, &lrecord_image_instance);
1224 /* It's not possible to simply keep a record of the domain in which
1225 the instance was instantiated. This is because caching may mean
1226 that the domain becomes invalid but the instance remains
1227 valid. However, the only truly relevant domain is the domain in
1228 which the instance is cached since this is the one that will be
1229 common to the instances. */
1230 lp->domain = governing_domain;
1231 /* The cache domain is not quite sufficient since the domain can get
1232 deleted before the image instance does. We need to know the
1233 domain device in order to finalize the image instance
1234 properly. We therefore record the device also. */
1235 lp->device = DOMAIN_DEVICE(governing_domain);
1236 lp->type = IMAGE_NOTHING;
1240 lp->width = IMAGE_UNSPECIFIED_GEOMETRY;
1241 lp->margin_width = 0;
1242 lp->height = IMAGE_UNSPECIFIED_GEOMETRY;
1243 lp->parent = parent;
1244 lp->instantiator = instantiator;
1245 /* So that layouts get done. */
1246 lp->layout_changed = 1;
1247 lp->initialized = 0;
1249 XSETIMAGE_INSTANCE(val, lp);
1250 MARK_GLYPHS_CHANGED;
1255 static enum image_instance_type
1256 decode_image_instance_type(Lisp_Object type, Error_behavior errb)
1258 if (ERRB_EQ(errb, ERROR_ME))
1261 if (EQ(type, Qnothing))
1262 return IMAGE_NOTHING;
1263 if (EQ(type, Qtext))
1265 if (EQ(type, Qmono_pixmap))
1266 return IMAGE_MONO_PIXMAP;
1267 if (EQ(type, Qcolor_pixmap))
1268 return IMAGE_COLOR_PIXMAP;
1269 if (EQ(type, Qpointer))
1270 return IMAGE_POINTER;
1271 if (EQ(type, Qsubwindow))
1272 return IMAGE_SUBWINDOW;
1273 if (EQ(type, Qwidget))
1274 return IMAGE_WIDGET;
1276 maybe_signal_simple_error("Invalid image-instance type", type,
1279 return IMAGE_UNKNOWN; /* not reached */
1282 static Lisp_Object encode_image_instance_type(enum image_instance_type type)
1289 case IMAGE_MONO_PIXMAP:
1290 return Qmono_pixmap;
1291 case IMAGE_COLOR_PIXMAP:
1292 return Qcolor_pixmap;
1295 case IMAGE_SUBWINDOW:
1305 return Qnil; /* not reached */
1308 static int decode_image_instance_type_list(Lisp_Object list)
1317 enum image_instance_type type =
1318 decode_image_instance_type(list, ERROR_ME);
1319 return image_instance_type_to_mask(type);
1322 EXTERNAL_LIST_LOOP(rest, list) {
1323 enum image_instance_type type =
1324 decode_image_instance_type(XCAR(rest), ERROR_ME);
1325 mask |= image_instance_type_to_mask(type);
1331 static Lisp_Object encode_image_instance_type_list(int mask)
1334 Lisp_Object result = Qnil;
1339 result = Fcons(encode_image_instance_type
1340 ((enum image_instance_type)count),
1345 return Fnreverse(result);
1349 incompatible_image_types(Lisp_Object instantiator, int given_dest_mask,
1350 int desired_dest_mask)
1352 signal_error(Qerror, list2(emacs_doprnt_string_lisp_2((const Bufbyte *)
1353 "No compatible image-instance types given: wanted one of %s, got %s",
1355 encode_image_instance_type_list
1356 (desired_dest_mask),
1357 encode_image_instance_type_list
1362 static int valid_image_instance_type_p(Lisp_Object type)
1364 return !NILP(memq_no_quit(type, Vimage_instance_type_list));
1367 DEFUN("valid-image-instance-type-p", Fvalid_image_instance_type_p, 1, 1, 0, /*
1368 Given an IMAGE-INSTANCE-TYPE, return non-nil if it is valid.
1369 Valid types are some subset of 'nothing, 'text, 'mono-pixmap, 'color-pixmap,
1370 'pointer, 'subwindow, and 'widget, depending on how SXEmacs was compiled.
1372 (image_instance_type))
1374 return valid_image_instance_type_p(image_instance_type) ? Qt : Qnil;
1377 DEFUN("image-instance-type-list", Fimage_instance_type_list, 0, 0, 0, /*
1378 Return a list of valid image-instance types.
1382 return Fcopy_sequence(Vimage_instance_type_list);
1385 Error_behavior decode_error_behavior_flag(Lisp_Object noerror)
1389 else if (EQ(noerror, Qt))
1390 return ERROR_ME_NOT;
1392 return ERROR_ME_WARN;
1395 Lisp_Object encode_error_behavior_flag(Error_behavior errb)
1397 if (ERRB_EQ(errb, ERROR_ME))
1399 else if (ERRB_EQ(errb, ERROR_ME_NOT))
1402 assert(ERRB_EQ(errb, ERROR_ME_WARN));
1407 /* Recurse up the hierarchy looking for the topmost glyph. This means
1408 that instances in layouts will inherit face properties from their
1410 Lisp_Object image_instance_parent_glyph(Lisp_Image_Instance * ii)
1412 if (IMAGE_INSTANCEP(IMAGE_INSTANCE_PARENT(ii))) {
1413 return image_instance_parent_glyph
1414 (XIMAGE_INSTANCE(IMAGE_INSTANCE_PARENT(ii)));
1416 return IMAGE_INSTANCE_PARENT(ii);
1420 make_image_instance_1(Lisp_Object data, Lisp_Object domain,
1421 Lisp_Object dest_types)
1424 struct gcpro gcpro1;
1426 Lisp_Object governing_domain;
1428 if (IMAGE_INSTANCEP(data))
1429 signal_simple_error("Image instances not allowed here", data);
1430 image_validate(data);
1431 domain = decode_domain(domain);
1432 /* instantiate_image_instantiator() will abort if given an
1433 image instance ... */
1434 dest_mask = decode_image_instance_type_list(dest_types);
1435 data = normalize_image_instantiator(data,
1436 DEVICE_TYPE(DOMAIN_XDEVICE(domain)),
1437 make_int(dest_mask));
1439 /* After normalizing the data, it's always either an image instance (which
1440 we filtered out above) or a vector. */
1441 if (EQ(INSTANTIATOR_TYPE(data), Qinherit))
1442 signal_simple_error("Inheritance not allowed here", data);
1444 get_image_instantiator_governing_domain(data, domain);
1445 ii = instantiate_image_instantiator(governing_domain, domain, data,
1446 Qnil, Qnil, dest_mask, Qnil);
1450 DEFUN("make-image-instance", Fmake_image_instance, 1, 4, 0, /*
1451 Return a new `image-instance' object.
1453 Image-instance objects encapsulate the way a particular image (pixmap,
1454 etc.) is displayed on a particular device. In most circumstances, you
1455 do not need to directly create image instances; use a glyph instead.
1456 However, it may occasionally be useful to explicitly create image
1457 instances, if you want more control over the instantiation process.
1459 DATA is an image instantiator, which describes the image; see
1460 `make-image-specifier' for a description of the allowed values.
1462 DEST-TYPES should be a list of allowed image instance types that can
1463 be generated. The recognized image instance types are
1466 Nothing is displayed.
1468 Displayed as text. The foreground and background colors and the
1469 font of the text are specified independent of the pixmap. Typically
1470 these attributes will come from the face of the surrounding text,
1471 unless a face is specified for the glyph in which the image appears.
1473 Displayed as a mono pixmap (a pixmap with only two colors where the
1474 foreground and background can be specified independent of the pixmap;
1475 typically the pixmap assumes the foreground and background colors of
1476 the text around it, unless a face is specified for the glyph in which
1479 Displayed as a color pixmap.
1481 Used as the mouse pointer for a window.
1483 A child window that is treated as an image. This allows (e.g.)
1484 another program to be responsible for drawing into the window.
1486 A child window that contains a window-system widget, e.g. a push
1487 button, text field, or slider.
1489 The DEST-TYPES list is unordered. If multiple destination types are
1490 possible for a given instantiator, the "most natural" type for the
1491 instantiator's format is chosen. (For XBM, the most natural types are
1492 `mono-pixmap', followed by `color-pixmap', followed by `pointer'. For
1493 the other normal image formats, the most natural types are
1494 `color-pixmap', followed by `mono-pixmap', followed by `pointer'. For
1495 the string and formatted-string formats, the most natural types are
1496 `text', followed by `mono-pixmap' (not currently implemented),
1497 followed by `color-pixmap' (not currently implemented). For MS
1498 Windows resources, the most natural type for pointer resources is
1499 `pointer', and for the others it's `color-pixmap'. The other formats
1500 can only be instantiated as one type. (If you want to control more
1501 specifically the order of the types into which an image is
1502 instantiated, just call `make-image-instance' repeatedly until it
1503 succeeds, passing less and less preferred destination types each
1506 See `make-image-specifier' for a description of the different image
1507 instantiator formats.
1509 If DEST-TYPES is omitted, all possible types are allowed.
1511 DOMAIN specifies the domain to which the image instance will be attached.
1512 This domain is termed the \"governing domain\". The type of the governing
1513 domain depends on the image instantiator format. (Although, more correctly,
1514 it should probably depend on the image instance type.) For example, pixmap
1515 image instances are specific to a device, but widget image instances are
1516 specific to a particular SXEmacs window because in order to display such a
1517 widget when two windows onto the same buffer want to display the widget,
1518 two separate underlying widgets must be created. (That's because a widget
1519 is actually a child window-system window, and all window-system windows have
1520 a unique existence on the screen.) This means that the governing domain for
1521 a pixmap image instance will be some device (most likely, the only existing
1522 device), whereas the governing domain for a widget image instance will be
1523 some SXEmacs window.
1525 If you specify an overly general DOMAIN (e.g. a frame when a window was
1526 wanted), an error is signaled. If you specify an overly specific DOMAIN
1527 \(e.g. a window when a device was wanted), the corresponding general domain
1528 is fetched and used instead. For `make-image-instance', it makes no
1529 difference whether you specify an overly specific domain or the properly
1530 general domain derived from it. However, it does matter when creating an
1531 image instance by instantiating a specifier or glyph (e.g. with
1532 `glyph-image-instance'), because the more specific domain causes spec lookup
1533 to start there and proceed to more general domains. (It would also matter
1534 when creating an image instance with an instantiator format of `inherit',
1535 but we currently disallow this. #### We should fix this.)
1537 If omitted, DOMAIN defaults to the selected window.
1539 NOERROR controls what happens when the image cannot be generated.
1540 If nil, an error message is generated. If t, no messages are
1541 generated and this function returns nil. If anything else, a warning
1542 message is generated and this function returns nil.
1544 (data, domain, dest_types, noerror))
1546 Error_behavior errb = decode_error_behavior_flag(noerror);
1548 return call_with_suspended_errors((lisp_fn_t) make_image_instance_1,
1550 3, data, domain, dest_types);
1553 DEFUN("image-instance-p", Fimage_instance_p, 1, 1, 0, /*
1554 Return non-nil if OBJECT is an image instance.
1558 return IMAGE_INSTANCEP(object) ? Qt : Qnil;
1561 DEFUN("image-instance-type", Fimage_instance_type, 1, 1, 0, /*
1562 Return the type of the given image instance.
1563 The return value will be one of 'nothing, 'text, 'mono-pixmap,
1564 'color-pixmap, 'pointer, or 'subwindow.
1568 CHECK_IMAGE_INSTANCE(image_instance);
1569 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1570 return encode_image_instance_type(XIMAGE_INSTANCE_TYPE(image_instance));
1573 DEFUN("image-instance-name", Fimage_instance_name, 1, 1, 0, /*
1574 Return the name of the given image instance.
1578 CHECK_IMAGE_INSTANCE(image_instance);
1579 return XIMAGE_INSTANCE_NAME(image_instance);
1582 DEFUN("image-instance-domain", Fimage_instance_domain, 1, 1, 0, /*
1583 Return the governing domain of the given image instance.
1584 The governing domain of an image instance is the domain that the image
1585 instance is specific to. It is NOT necessarily the domain that was
1586 given to the call to `specifier-instance' that resulted in the creation
1587 of this image instance. See `make-image-instance' for more information
1588 on governing domains.
1592 CHECK_IMAGE_INSTANCE(image_instance);
1593 return XIMAGE_INSTANCE_DOMAIN(image_instance);
1596 DEFUN("image-instance-string", Fimage_instance_string, 1, 1, 0, /*
1597 Return the string of the given image instance.
1598 This will only be non-nil for text image instances and widgets.
1602 CHECK_IMAGE_INSTANCE(image_instance);
1603 if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_TEXT)
1604 return XIMAGE_INSTANCE_TEXT_STRING(image_instance);
1605 else if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_WIDGET)
1606 return XIMAGE_INSTANCE_WIDGET_TEXT(image_instance);
1611 DEFUN("image-instance-property", Fimage_instance_property, 2, 2, 0, /*
1612 Return the given property of the given image instance.
1613 Returns nil if the property or the property method do not exist for
1614 the image instance in the domain.
1616 (image_instance, prop))
1618 Lisp_Image_Instance *ii;
1619 Lisp_Object type, ret;
1620 struct image_instantiator_methods *meths;
1622 CHECK_IMAGE_INSTANCE(image_instance);
1623 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1625 ii = XIMAGE_INSTANCE(image_instance);
1627 /* ... then try device specific methods ... */
1628 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1629 meths = decode_device_ii_format(image_instance_device(image_instance),
1630 type, ERROR_ME_NOT);
1631 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1634 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1637 /* ... then format specific methods ... */
1638 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1639 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1642 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1649 DEFUN("image-instance-file-name", Fimage_instance_file_name, 1, 1, 0, /*
1650 Return the file name from which IMAGE-INSTANCE was read, if known.
1654 CHECK_IMAGE_INSTANCE(image_instance);
1655 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1657 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1658 case IMAGE_MONO_PIXMAP:
1659 case IMAGE_COLOR_PIXMAP:
1661 return XIMAGE_INSTANCE_PIXMAP_FILENAME(image_instance);
1666 case IMAGE_SUBWINDOW:
1673 DEFUN("image-instance-mask-file-name", Fimage_instance_mask_file_name, 1, 1, 0, /*
1674 Return the file name from which IMAGE-INSTANCE's mask was read, if known.
1678 CHECK_IMAGE_INSTANCE(image_instance);
1679 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1681 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1682 case IMAGE_MONO_PIXMAP:
1683 case IMAGE_COLOR_PIXMAP:
1685 return XIMAGE_INSTANCE_PIXMAP_MASK_FILENAME(image_instance);
1690 case IMAGE_SUBWINDOW:
1697 DEFUN("image-instance-depth", Fimage_instance_depth, 1, 1, 0, /*
1698 Return the depth of the image instance.
1699 This is 0 for a bitmap, or a positive integer for a pixmap.
1703 CHECK_IMAGE_INSTANCE(image_instance);
1704 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1706 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1707 case IMAGE_MONO_PIXMAP:
1708 case IMAGE_COLOR_PIXMAP:
1710 return make_int(XIMAGE_INSTANCE_PIXMAP_DEPTH(image_instance));
1715 case IMAGE_SUBWINDOW:
1722 DEFUN("image-instance-height", Fimage_instance_height, 1, 1, 0, /*
1723 Return the height of the image instance, in pixels.
1727 CHECK_IMAGE_INSTANCE(image_instance);
1728 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1730 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1731 case IMAGE_MONO_PIXMAP:
1732 case IMAGE_COLOR_PIXMAP:
1734 case IMAGE_SUBWINDOW:
1736 return make_int(XIMAGE_INSTANCE_HEIGHT(image_instance));
1746 DEFUN("image-instance-width", Fimage_instance_width, 1, 1, 0, /*
1747 Return the width of the image instance, in pixels.
1751 CHECK_IMAGE_INSTANCE(image_instance);
1752 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1754 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1755 case IMAGE_MONO_PIXMAP:
1756 case IMAGE_COLOR_PIXMAP:
1758 case IMAGE_SUBWINDOW:
1760 return make_int(XIMAGE_INSTANCE_WIDTH(image_instance));
1770 DEFUN("image-instance-hotspot-x", Fimage_instance_hotspot_x, 1, 1, 0, /*
1771 Return the X coordinate of the image instance's hotspot, if known.
1772 This is a point relative to the origin of the pixmap. When an image is
1773 used as a mouse pointer, the hotspot is the point on the image that sits
1774 over the location that the pointer points to. This is, for example, the
1775 tip of the arrow or the center of the crosshairs.
1776 This will always be nil for a non-pointer image instance.
1780 CHECK_IMAGE_INSTANCE(image_instance);
1781 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1783 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1784 case IMAGE_MONO_PIXMAP:
1785 case IMAGE_COLOR_PIXMAP:
1787 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_X(image_instance);
1792 case IMAGE_SUBWINDOW:
1799 DEFUN("image-instance-hotspot-y", Fimage_instance_hotspot_y, 1, 1, 0, /*
1800 Return the Y coordinate of the image instance's hotspot, if known.
1801 This is a point relative to the origin of the pixmap. When an image is
1802 used as a mouse pointer, the hotspot is the point on the image that sits
1803 over the location that the pointer points to. This is, for example, the
1804 tip of the arrow or the center of the crosshairs.
1805 This will always be nil for a non-pointer image instance.
1809 CHECK_IMAGE_INSTANCE(image_instance);
1810 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1812 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1813 case IMAGE_MONO_PIXMAP:
1814 case IMAGE_COLOR_PIXMAP:
1816 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(image_instance);
1821 case IMAGE_SUBWINDOW:
1828 DEFUN("image-instance-foreground", Fimage_instance_foreground, 1, 1, 0, /*
1829 Return the foreground color of IMAGE-INSTANCE, if applicable.
1830 This will be a color instance or nil. (It will only be non-nil for
1831 colorized mono pixmaps and for pointers.)
1835 CHECK_IMAGE_INSTANCE(image_instance);
1836 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1838 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1839 case IMAGE_MONO_PIXMAP:
1840 case IMAGE_COLOR_PIXMAP:
1842 return XIMAGE_INSTANCE_PIXMAP_FG(image_instance);
1846 FACE_FOREGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1847 XIMAGE_INSTANCE_FRAME(image_instance));
1852 case IMAGE_SUBWINDOW:
1858 DEFUN("image-instance-background", Fimage_instance_background, 1, 1, 0, /*
1859 Return the background color of IMAGE-INSTANCE, if applicable.
1860 This will be a color instance or nil. (It will only be non-nil for
1861 colorized mono pixmaps and for pointers.)
1865 CHECK_IMAGE_INSTANCE(image_instance);
1866 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1868 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1869 case IMAGE_MONO_PIXMAP:
1870 case IMAGE_COLOR_PIXMAP:
1872 return XIMAGE_INSTANCE_PIXMAP_BG(image_instance);
1876 FACE_BACKGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1877 XIMAGE_INSTANCE_FRAME(image_instance));
1882 case IMAGE_SUBWINDOW:
1888 DEFUN("colorize-image-instance", Fcolorize_image_instance, 3, 3, 0, /*
1889 Make the image instance be displayed in the given colors.
1890 This function returns a new image instance that is exactly like the
1891 specified one except that (if possible) the foreground and background
1892 colors and as specified. Currently, this only does anything if the image
1893 instance is a mono pixmap; otherwise, the same image instance is returned.
1895 (image_instance, foreground, background))
1900 CHECK_IMAGE_INSTANCE(image_instance);
1901 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1902 CHECK_COLOR_INSTANCE(foreground);
1903 CHECK_COLOR_INSTANCE(background);
1905 device = image_instance_device(image_instance);
1906 if (!HAS_DEVMETH_P(XDEVICE(device), colorize_image_instance))
1907 return image_instance;
1909 /* #### There should be a copy_image_instance(), which calls a
1910 device-specific method to copy the window-system subobject. */
1911 new = allocate_image_instance(XIMAGE_INSTANCE_DOMAIN(image_instance),
1913 copy_lcrecord(XIMAGE_INSTANCE(new), XIMAGE_INSTANCE(image_instance));
1914 /* note that if this method returns non-zero, this method MUST
1915 copy any window-system resources, so that when one image instance is
1916 freed, the other one is not hosed. */
1917 if (!DEVMETH(XDEVICE(device), colorize_image_instance, (new, foreground,
1919 return image_instance;
1923 /************************************************************************/
1924 /* Geometry calculations */
1925 /************************************************************************/
1927 /* Find out desired geometry of the image instance. If there is no
1928 special function then just return the width and / or height. */
1930 image_instance_query_geometry(Lisp_Object image_instance,
1931 int *width, int *height,
1932 enum image_instance_geometry disp,
1935 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1937 struct image_instantiator_methods *meths;
1938 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1940 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1941 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1943 if (meths && HAS_IIFORMAT_METH_P(meths, query_geometry)) {
1944 IIFORMAT_METH(meths, query_geometry,
1945 (image_instance, width, height, disp, domain));
1948 *width = IMAGE_INSTANCE_WIDTH(ii);
1950 *height = IMAGE_INSTANCE_HEIGHT(ii);
1954 /* Layout the image instance using the provided dimensions. Layout
1955 widgets are going to do different kinds of calculations to
1956 determine what size to give things so we could make the layout
1957 function relatively simple to take account of that. An alternative
1958 approach is to consider separately the two cases, one where you
1959 don't mind what size you have (normal widgets) and one where you
1960 want to specify something (layout widgets). */
1962 image_instance_layout(Lisp_Object image_instance,
1963 int width, int height,
1964 int xoffset, int yoffset, Lisp_Object domain)
1966 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1968 struct image_instantiator_methods *meths;
1970 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1972 /* Nothing is as nothing does. */
1973 if (NOTHING_IMAGE_INSTANCEP(image_instance))
1976 /* We don't want carefully calculated offsets to be mucked up by
1978 if (xoffset != IMAGE_UNCHANGED_GEOMETRY)
1979 XIMAGE_INSTANCE_XOFFSET(image_instance) = xoffset;
1980 if (yoffset != IMAGE_UNCHANGED_GEOMETRY)
1981 XIMAGE_INSTANCE_YOFFSET(image_instance) = yoffset;
1983 /* If geometry is unspecified then get some reasonable values for it. */
1984 if (width == IMAGE_UNSPECIFIED_GEOMETRY
1985 || height == IMAGE_UNSPECIFIED_GEOMETRY) {
1986 int dwidth = IMAGE_UNSPECIFIED_GEOMETRY;
1987 int dheight = IMAGE_UNSPECIFIED_GEOMETRY;
1988 /* Get the desired geometry. */
1989 image_instance_query_geometry(image_instance,
1991 IMAGE_DESIRED_GEOMETRY, domain);
1992 /* Compare with allowed geometry. */
1993 if (width == IMAGE_UNSPECIFIED_GEOMETRY)
1995 if (height == IMAGE_UNSPECIFIED_GEOMETRY)
1999 /* If we don't have sane values then we cannot layout at this point and
2000 must just return. */
2001 if (width == IMAGE_UNSPECIFIED_GEOMETRY
2002 || height == IMAGE_UNSPECIFIED_GEOMETRY)
2005 /* At this point width and height should contain sane values. Thus
2006 we set the glyph geometry and lay it out. */
2007 if (IMAGE_INSTANCE_WIDTH(ii) != width
2008 || IMAGE_INSTANCE_HEIGHT(ii) != height) {
2009 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
2012 IMAGE_INSTANCE_WIDTH(ii) = width;
2013 IMAGE_INSTANCE_HEIGHT(ii) = height;
2015 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2016 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2018 MAYBE_IIFORMAT_METH(meths, layout,
2019 (image_instance, width, height, xoffset, yoffset,
2021 /* Do not clear the dirty flag here - redisplay will do this for
2023 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 0;
2026 /* Update an image instance from its changed instantiator. */
2028 update_image_instance(Lisp_Object image_instance, Lisp_Object instantiator)
2030 struct image_instantiator_methods *meths;
2031 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2033 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
2035 if (NOTHING_IMAGE_INSTANCEP(image_instance))
2038 assert(!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2040 (internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2041 && internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator,
2044 /* If the instantiator is identical then do nothing. We must use
2045 equal here because the specifier code copies the instantiator. */
2046 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)) {
2047 /* Extract the changed properties so that device / format
2048 methods only have to cope with these. We assume that
2049 normalization has already been done. */
2050 Lisp_Object diffs = find_instantiator_differences(instantiator,
2051 IMAGE_INSTANCE_INSTANTIATOR
2054 encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2055 struct gcpro gcpro1;
2058 /* try device specific methods first ... */
2060 decode_device_ii_format(image_instance_device
2061 (image_instance), type,
2063 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2064 /* ... then format specific methods ... */
2065 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2066 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2068 /* Instance and therefore glyph has changed so mark as dirty.
2069 If we don't do this output optimizations will assume the
2070 glyph is unchanged. */
2071 set_image_instance_dirty_p(image_instance, 1);
2072 /* Structure has changed. */
2073 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2077 /* We should now have a consistent instantiator so keep a record of
2078 it. It is important that we don't actually update the window
2079 system widgets here - we must do that when redisplay tells us
2082 #### should we delay doing this until the display is up-to-date
2084 IMAGE_INSTANCE_INSTANTIATOR(ii) = instantiator;
2088 * Mark image instance in W as dirty if (a) W's faces have changed and
2089 * (b) GLYPH_OR_II instance in W is a string.
2091 * Return non-zero if instance has been marked dirty.
2093 int invalidate_glyph_geometry_maybe(Lisp_Object glyph_or_ii, struct window *w)
2095 if (XFRAME(WINDOW_FRAME(w))->faces_changed) {
2096 Lisp_Object image = glyph_or_ii;
2098 if (GLYPHP(glyph_or_ii)) {
2100 XSETWINDOW(window, w);
2102 glyph_image_instance(glyph_or_ii, window,
2106 if (TEXT_IMAGE_INSTANCEP(image)) {
2107 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image);
2108 IMAGE_INSTANCE_DIRTYP(ii) = 1;
2109 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2110 if (GLYPHP(glyph_or_ii))
2111 XGLYPH_DIRTYP(glyph_or_ii) = 1;
2119 /************************************************************************/
2121 /************************************************************************/
2122 DOESNT_RETURN signal_image_error(const char *reason, Lisp_Object frob)
2124 signal_error(Qimage_conversion_error,
2125 list2(build_translated_string(reason), frob));
2129 signal_image_error_2(const char *reason, Lisp_Object frob0, Lisp_Object frob1)
2131 signal_error(Qimage_conversion_error,
2132 list3(build_translated_string(reason), frob0, frob1));
2135 /****************************************************************************
2137 ****************************************************************************/
2139 static int nothing_possible_dest_types(void)
2141 return IMAGE_NOTHING_MASK;
2145 nothing_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2146 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2147 int dest_mask, Lisp_Object domain)
2149 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2151 if (dest_mask & IMAGE_NOTHING_MASK) {
2152 IMAGE_INSTANCE_TYPE(ii) = IMAGE_NOTHING;
2153 IMAGE_INSTANCE_HEIGHT(ii) = 0;
2154 IMAGE_INSTANCE_WIDTH(ii) = 0;
2156 incompatible_image_types(instantiator, dest_mask,
2157 IMAGE_NOTHING_MASK);
2160 /****************************************************************************
2162 ****************************************************************************/
2164 static void inherit_validate(Lisp_Object instantiator)
2166 face_must_be_present(instantiator);
2170 inherit_normalize(Lisp_Object inst, Lisp_Object console_type,
2171 Lisp_Object dest_mask)
2175 assert(XVECTOR_LENGTH(inst) == 3);
2176 face = XVECTOR_DATA(inst)[2];
2178 inst = vector3(Qinherit, Q_face, Fget_face(face));
2182 static int inherit_possible_dest_types(void)
2184 return IMAGE_MONO_PIXMAP_MASK;
2188 inherit_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2189 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2190 int dest_mask, Lisp_Object domain)
2192 /* handled specially in image_instantiate */
2196 /****************************************************************************
2198 ****************************************************************************/
2200 static void string_validate(Lisp_Object instantiator)
2202 data_must_be_present(instantiator);
2205 static int string_possible_dest_types(void)
2207 return IMAGE_TEXT_MASK;
2210 /* Called from autodetect_instantiate() */
2212 string_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2213 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2214 int dest_mask, Lisp_Object domain)
2216 Lisp_Object string = find_keyword_in_vector(instantiator, Q_data);
2217 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2219 /* Should never get here with a domain other than a window. */
2220 assert(!NILP(string) && WINDOWP(DOMAIN_WINDOW(domain)));
2221 if (dest_mask & IMAGE_TEXT_MASK) {
2222 IMAGE_INSTANCE_TYPE(ii) = IMAGE_TEXT;
2223 IMAGE_INSTANCE_TEXT_STRING(ii) = string;
2225 incompatible_image_types(instantiator, dest_mask,
2229 /* Sort out the size of the text that is being displayed. Calculating
2230 it dynamically allows us to change the text and still see
2231 everything. Note that the following methods are for text not string
2232 since that is what the instantiated type is. The first method is a
2233 helper that is used elsewhere for calculating text geometry. */
2235 query_string_geometry(Lisp_Object string, Lisp_Object face,
2236 int *width, int *height, int *descent, Lisp_Object domain)
2238 struct font_metric_info fm;
2239 unsigned char charsets[NUM_LEADING_BYTES];
2240 struct face_cachel frame_cachel;
2241 struct face_cachel *cachel;
2242 Lisp_Object frame = DOMAIN_FRAME(domain);
2244 CHECK_STRING(string);
2246 /* Compute height */
2248 /* Compute string metric info */
2249 find_charsets_in_bufbyte_string(charsets,
2250 XSTRING_DATA(string),
2251 XSTRING_LENGTH(string));
2253 /* Fallback to the default face if none was provided. */
2255 reset_face_cachel(&frame_cachel);
2256 update_face_cachel_data(&frame_cachel, frame, face);
2257 cachel = &frame_cachel;
2259 cachel = WINDOW_FACE_CACHEL(DOMAIN_XWINDOW(domain),
2263 ensure_face_cachel_complete(cachel, domain, charsets);
2264 face_cachel_charset_font_metric_info(cachel, charsets, &fm);
2266 *height = fm.ascent + fm.descent;
2267 /* #### descent only gets set if we query the height as well. */
2269 *descent = fm.descent;
2276 redisplay_frame_text_width_string(XFRAME(frame),
2281 redisplay_frame_text_width_string(XFRAME(frame),
2288 query_string_font(Lisp_Object string, Lisp_Object face, Lisp_Object domain)
2290 unsigned char charsets[NUM_LEADING_BYTES];
2291 struct face_cachel frame_cachel;
2292 struct face_cachel *cachel;
2294 Lisp_Object frame = DOMAIN_FRAME(domain);
2296 /* Compute string font info */
2297 find_charsets_in_bufbyte_string(charsets,
2298 XSTRING_DATA(string),
2299 XSTRING_LENGTH(string));
2301 reset_face_cachel(&frame_cachel);
2302 update_face_cachel_data(&frame_cachel, frame, face);
2303 cachel = &frame_cachel;
2305 ensure_face_cachel_complete(cachel, domain, charsets);
2307 for (i = 0; i < NUM_LEADING_BYTES; i++) {
2310 CHARSET_BY_LEADING_BYTE(i + MIN_LEADING_BYTE);
2311 return FACE_CACHEL_FONT(cachel, tmp);
2315 return Qnil; /* NOT REACHED */
2319 text_query_geometry(Lisp_Object image_instance,
2320 int *width, int *height,
2321 enum image_instance_geometry disp, Lisp_Object domain)
2323 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2326 query_string_geometry(IMAGE_INSTANCE_TEXT_STRING(ii),
2327 IMAGE_INSTANCE_FACE(ii),
2328 width, height, &descent, domain);
2330 /* The descent gets set as a side effect of querying the
2332 IMAGE_INSTANCE_TEXT_DESCENT(ii) = descent;
2335 /* set the properties of a string */
2336 static void text_update(Lisp_Object image_instance, Lisp_Object instantiator)
2338 Lisp_Object val = find_keyword_in_vector(instantiator, Q_data);
2342 XIMAGE_INSTANCE_TEXT_STRING(image_instance) = val;
2346 /****************************************************************************
2347 * formatted-string *
2348 ****************************************************************************/
2350 static void formatted_string_validate(Lisp_Object instantiator)
2352 data_must_be_present(instantiator);
2355 static int formatted_string_possible_dest_types(void)
2357 return IMAGE_TEXT_MASK;
2361 formatted_string_instantiate(Lisp_Object image_instance,
2362 Lisp_Object instantiator,
2363 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2364 int dest_mask, Lisp_Object domain)
2366 /* #### implement this */
2367 warn_when_safe(Qunimplemented, Qnotice,
2368 "`formatted-string' not yet implemented; assuming `string'");
2370 string_instantiate(image_instance, instantiator,
2371 pointer_fg, pointer_bg, dest_mask, domain);
2374 /************************************************************************/
2375 /* pixmap file functions */
2376 /************************************************************************/
2378 /* If INSTANTIATOR refers to inline data, return Qnil.
2379 If INSTANTIATOR refers to data in a file, return the full filename
2380 if it exists; otherwise, return a cons of (filename).
2382 FILE_KEYWORD and DATA_KEYWORD are symbols specifying the
2383 keywords used to look up the file and inline data,
2384 respectively, in the instantiator. Normally these would
2385 be Q_file and Q_data, but might be different for mask data. */
2388 potential_pixmap_file_instantiator(Lisp_Object instantiator,
2389 Lisp_Object file_keyword,
2390 Lisp_Object data_keyword,
2391 Lisp_Object console_type)
2396 assert(VECTORP(instantiator));
2398 data = find_keyword_in_vector(instantiator, data_keyword);
2399 file = find_keyword_in_vector(instantiator, file_keyword);
2401 if (!NILP(file) && NILP(data)) {
2402 Lisp_Object retval = MAYBE_LISP_CONTYPE_METH
2403 (decode_console_type(console_type, ERROR_ME),
2404 locate_pixmap_file, (file));
2409 return Fcons(file, Qnil); /* should have been file */
2416 simple_image_type_normalize(Lisp_Object inst, Lisp_Object console_type,
2417 Lisp_Object image_type_tag)
2419 /* This function can call lisp */
2420 Lisp_Object file = Qnil;
2421 struct gcpro gcpro1, gcpro2;
2422 Lisp_Object alist = Qnil;
2424 GCPRO2(file, alist);
2426 /* Now, convert any file data into inline data. At the end of this,
2427 `data' will contain the inline data (if any) or Qnil, and `file'
2428 will contain the name this data was derived from (if known) or
2431 Note that if we cannot generate any regular inline data, we
2434 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2437 if (CONSP(file)) /* failure locating filename */
2438 signal_double_file_error("Opening pixmap file",
2439 "no such file or directory",
2442 if (NILP(file)) /* no conversion necessary */
2443 RETURN_UNGCPRO(inst);
2445 alist = tagged_vector_to_alist(inst);
2448 Lisp_Object data = make_string_from_file(file);
2449 alist = remassq_no_quit(Q_file, alist);
2450 /* there can't be a :data at this point. */
2451 alist = Fcons(Fcons(Q_file, file),
2452 Fcons(Fcons(Q_data, data), alist));
2456 Lisp_Object result =
2457 alist_to_tagged_vector(image_type_tag, alist);
2459 RETURN_UNGCPRO(result);
2463 #ifdef HAVE_WINDOW_SYSTEM
2464 /**********************************************************************
2466 **********************************************************************/
2468 /* Check if DATA represents a valid inline XBM spec (i.e. a list
2469 of (width height bits), with checking done on the dimensions).
2470 If not, signal an error. */
2472 static void check_valid_xbm_inline(Lisp_Object data)
2474 Lisp_Object width, height, bits;
2477 !CONSP(XCDR(data)) ||
2478 !CONSP(XCDR(XCDR(data))) || !NILP(XCDR(XCDR(XCDR(data)))))
2479 signal_simple_error("Must be list of 3 elements", data);
2482 height = XCAR(XCDR(data));
2483 bits = XCAR(XCDR(XCDR(data)));
2487 if (!NATNUMP(width))
2488 signal_simple_error("Width must be a natural number", width);
2490 if (!NATNUMP(height))
2491 signal_simple_error("Height must be a natural number", height);
2493 if (((XINT(width) * XINT(height)) / 8) > XSTRING_CHAR_LENGTH(bits))
2494 signal_simple_error("data is too short for width and height",
2495 vector3(width, height, bits));
2498 /* Validate method for XBM's. */
2500 static void xbm_validate(Lisp_Object instantiator)
2502 file_or_data_must_be_present(instantiator);
2505 /* Given a filename that is supposed to contain XBM data, return
2506 the inline representation of it as (width height bits). Return
2507 the hotspot through XHOT and YHOT, if those pointers are not 0.
2508 If there is no hotspot, XHOT and YHOT will contain -1.
2510 If the function fails:
2512 -- if OK_IF_DATA_INVALID is set and the data was invalid,
2514 -- maybe return an error, or return Qnil.
2517 #ifdef HAVE_X_WINDOWS
2518 #include <X11/Xlib.h>
2520 #define XFree(data) free(data)
2524 bitmap_to_lisp_data(Lisp_Object name, int *xhot, int *yhot,
2525 int ok_if_data_invalid)
2530 const char *filename_ext;
2532 LISP_STRING_TO_EXTERNAL(name, filename_ext, Qfile_name);
2533 result = read_bitmap_data_from_file(filename_ext, &w, &h,
2534 (unsigned char **)((void*)&data),
2537 if (result == BitmapSuccess) {
2539 int len = (w + 7) / 8 * h;
2541 retval = list3(make_int(w), make_int(h),
2542 make_ext_string(data, len, Qbinary));
2548 case BitmapOpenFailed:
2550 /* should never happen */
2551 signal_double_file_error("Opening bitmap file",
2552 "no such file or directory",
2555 case BitmapFileInvalid:
2557 if (ok_if_data_invalid)
2559 signal_double_file_error("Reading bitmap file",
2560 "invalid data in file", name);
2562 case BitmapNoMemory:
2564 signal_double_file_error("Reading bitmap file",
2565 "out of memory", name);
2569 signal_double_file_error_2("Reading bitmap file",
2570 "unknown error code",
2571 make_int(result), name);
2575 return Qnil; /* not reached */
2579 xbm_mask_file_munging(Lisp_Object alist, Lisp_Object file,
2580 Lisp_Object mask_file, Lisp_Object console_type)
2582 /* This is unclean but it's fairly standard -- a number of the
2583 bitmaps in /usr/include/X11/bitmaps use it -- so we support
2586 /* don't override explicitly specified mask data. */
2587 && NILP(assq_no_quit(Q_mask_data, alist))
2589 mask_file = MAYBE_LISP_CONTYPE_METH
2590 (decode_console_type(console_type, ERROR_ME),
2591 locate_pixmap_file, (concat2(file, build_string("Mask"))));
2592 if (NILP(mask_file))
2593 mask_file = MAYBE_LISP_CONTYPE_METH
2594 (decode_console_type(console_type, ERROR_ME),
2596 (concat2(file, build_string("msk"))));
2599 if (!NILP(mask_file)) {
2600 Lisp_Object mask_data = bitmap_to_lisp_data(mask_file, 0, 0, 0);
2601 alist = remassq_no_quit(Q_mask_file, alist);
2602 /* there can't be a :mask-data at this point. */
2603 alist = Fcons(Fcons(Q_mask_file, mask_file),
2604 Fcons(Fcons(Q_mask_data, mask_data), alist));
2610 /* Normalize method for XBM's. */
2613 xbm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2615 Lisp_Object file = Qnil, mask_file = Qnil;
2616 struct gcpro gcpro1, gcpro2, gcpro3;
2617 Lisp_Object alist = Qnil;
2619 GCPRO3(file, mask_file, alist);
2621 /* Now, convert any file data into inline data for both the regular
2622 data and the mask data. At the end of this, `data' will contain
2623 the inline data (if any) or Qnil, and `file' will contain
2624 the name this data was derived from (if known) or Qnil.
2625 Likewise for `mask_file' and `mask_data'.
2627 Note that if we cannot generate any regular inline data, we
2630 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2632 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2636 if (CONSP(file)) /* failure locating filename */
2637 signal_double_file_error("Opening bitmap file",
2638 "no such file or directory",
2641 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2642 RETURN_UNGCPRO(inst);
2644 alist = tagged_vector_to_alist(inst);
2648 Lisp_Object data = bitmap_to_lisp_data(file, &xhot, &yhot, 0);
2649 alist = remassq_no_quit(Q_file, alist);
2650 /* there can't be a :data at this point. */
2651 alist = Fcons(Fcons(Q_file, file),
2652 Fcons(Fcons(Q_data, data), alist));
2654 if (xhot != -1 && NILP(assq_no_quit(Q_hotspot_x, alist)))
2655 alist = Fcons(Fcons(Q_hotspot_x, make_int(xhot)),
2657 if (yhot != -1 && NILP(assq_no_quit(Q_hotspot_y, alist)))
2658 alist = Fcons(Fcons(Q_hotspot_y, make_int(yhot)),
2662 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2665 Lisp_Object result = alist_to_tagged_vector(Qxbm, alist);
2667 RETURN_UNGCPRO(result);
2671 static int xbm_possible_dest_types(void)
2674 IMAGE_MONO_PIXMAP_MASK |
2675 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2681 /**********************************************************************
2683 **********************************************************************/
2685 static void xface_validate(Lisp_Object instantiator)
2687 file_or_data_must_be_present(instantiator);
2691 xface_normalize(Lisp_Object inst, Lisp_Object console_type,
2692 Lisp_Object dest_mask)
2694 /* This function can call lisp */
2695 Lisp_Object file = Qnil, mask_file = Qnil;
2696 struct gcpro gcpro1, gcpro2, gcpro3;
2697 Lisp_Object alist = Qnil;
2699 GCPRO3(file, mask_file, alist);
2701 /* Now, convert any file data into inline data for both the regular
2702 data and the mask data. At the end of this, `data' will contain
2703 the inline data (if any) or Qnil, and `file' will contain
2704 the name this data was derived from (if known) or Qnil.
2705 Likewise for `mask_file' and `mask_data'.
2707 Note that if we cannot generate any regular inline data, we
2710 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2712 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2716 if (CONSP(file)) /* failure locating filename */
2717 signal_double_file_error("Opening bitmap file",
2718 "no such file or directory",
2721 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2722 RETURN_UNGCPRO(inst);
2724 #ifdef HAVE_WINDOW_SYSTEM
2725 alist = tagged_vector_to_alist(inst);
2728 Lisp_Object data = make_string_from_file(file);
2729 alist = remassq_no_quit(Q_file, alist);
2730 /* there can't be a :data at this point. */
2731 alist = Fcons(Fcons(Q_file, file),
2732 Fcons(Fcons(Q_data, data), alist));
2735 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2738 Lisp_Object result = alist_to_tagged_vector(Qxface, alist);
2740 RETURN_UNGCPRO(result);
2743 RETURN_UNGCPRO(Qnil);
2747 static int xface_possible_dest_types(void)
2750 IMAGE_MONO_PIXMAP_MASK |
2751 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2754 #endif /* HAVE_XFACE */
2758 /**********************************************************************
2760 **********************************************************************/
2762 Lisp_Object pixmap_to_lisp_data(Lisp_Object name, int ok_if_data_invalid)
2768 LISP_STRING_TO_EXTERNAL(name, fname, Qfile_name);
2769 result = XpmReadFileToData(fname, &data);
2771 if (result == XpmSuccess) {
2772 Lisp_Object retval = Qnil;
2773 struct buffer *old_buffer = current_buffer;
2774 Lisp_Object temp_buffer =
2775 Fget_buffer_create(build_string(" *pixmap conversion*"));
2777 int height, width, ncolors;
2778 struct gcpro gcpro1, gcpro2, gcpro3;
2779 int speccount = specpdl_depth();
2781 GCPRO3(name, retval, temp_buffer);
2783 specbind(Qinhibit_quit, Qt);
2784 set_buffer_internal(XBUFFER(temp_buffer));
2785 Ferase_buffer(Qnil);
2787 buffer_insert_c_string(current_buffer, "/* XPM */\r");
2788 buffer_insert_c_string(current_buffer,
2789 "static char *pixmap[] = {\r");
2791 sscanf(data[0], "%d %d %d", &height, &width, &ncolors);
2792 for (elt = 0; elt <= width + ncolors; elt++) {
2793 buffer_insert_c_string(current_buffer, "\"");
2794 buffer_insert_c_string(current_buffer, data[elt]);
2796 if (elt < width + ncolors)
2797 buffer_insert_c_string(current_buffer, "\",\r");
2799 buffer_insert_c_string(current_buffer,
2803 retval = Fbuffer_substring(Qnil, Qnil, Qnil);
2806 set_buffer_internal(old_buffer);
2807 unbind_to(speccount, Qnil);
2809 RETURN_UNGCPRO(retval);
2813 case XpmFileInvalid:
2815 if (ok_if_data_invalid)
2817 signal_image_error("invalid XPM data in file", name);
2821 signal_double_file_error("Reading pixmap file",
2822 "out of memory", name);
2826 /* should never happen? */
2827 signal_double_file_error("Opening pixmap file",
2828 "no such file or directory",
2833 signal_double_file_error_2("Parsing pixmap file",
2834 "unknown error code",
2835 make_int(result), name);
2840 return Qnil; /* not reached */
2843 static void check_valid_xpm_color_symbols(Lisp_Object data)
2847 for (rest = data; !NILP(rest); rest = XCDR(rest)) {
2849 !CONSP(XCAR(rest)) ||
2850 !STRINGP(XCAR(XCAR(rest))) ||
2851 (!STRINGP(XCDR(XCAR(rest))) &&
2852 !COLOR_SPECIFIERP(XCDR(XCAR(rest)))))
2853 signal_simple_error("Invalid color symbol alist", data);
2857 static void xpm_validate(Lisp_Object instantiator)
2859 file_or_data_must_be_present(instantiator);
2862 Lisp_Object Vxpm_color_symbols;
2864 Lisp_Object evaluate_xpm_color_symbols(void)
2866 Lisp_Object rest, results = Qnil;
2867 struct gcpro gcpro1, gcpro2;
2869 GCPRO2(rest, results);
2870 for (rest = Vxpm_color_symbols; !NILP(rest); rest = XCDR(rest)) {
2871 Lisp_Object name, value, cons;
2880 value = XCAR(value);
2881 value = Feval(value);
2884 if (!STRINGP(value) && !COLOR_SPECIFIERP(value))
2886 ("Result from xpm-color-symbols eval must be nil, string, or color",
2888 results = Fcons(Fcons(name, value), results);
2890 UNGCPRO; /* no more evaluation */
2895 xpm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2897 Lisp_Object file = Qnil;
2898 Lisp_Object color_symbols;
2899 struct gcpro gcpro1, gcpro2;
2900 Lisp_Object alist = Qnil;
2902 GCPRO2(file, alist);
2904 /* Now, convert any file data into inline data. At the end of this,
2905 `data' will contain the inline data (if any) or Qnil, and
2906 `file' will contain the name this data was derived from (if
2909 Note that if we cannot generate any regular inline data, we
2912 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2915 if (CONSP(file)) /* failure locating filename */
2916 signal_double_file_error("Opening pixmap file",
2917 "no such file or directory",
2920 color_symbols = find_keyword_in_vector_or_given(inst, Q_color_symbols,
2923 if (NILP(file) && !UNBOUNDP(color_symbols))
2924 /* no conversion necessary */
2925 RETURN_UNGCPRO(inst);
2927 alist = tagged_vector_to_alist(inst);
2930 Lisp_Object data = pixmap_to_lisp_data(file, 0);
2931 alist = remassq_no_quit(Q_file, alist);
2932 /* there can't be a :data at this point. */
2933 alist = Fcons(Fcons(Q_file, file),
2934 Fcons(Fcons(Q_data, data), alist));
2937 if (UNBOUNDP(color_symbols)) {
2938 color_symbols = evaluate_xpm_color_symbols();
2939 alist = Fcons(Fcons(Q_color_symbols, color_symbols), alist);
2943 Lisp_Object result = alist_to_tagged_vector(Qxpm, alist);
2945 RETURN_UNGCPRO(result);
2949 static int xpm_possible_dest_types(void)
2952 IMAGE_MONO_PIXMAP_MASK |
2953 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2956 #endif /* HAVE_XPM */
2958 /****************************************************************************
2959 * Image Specifier Object *
2960 ****************************************************************************/
2962 DEFINE_SPECIFIER_TYPE(image);
2964 static void image_create(Lisp_Object obj)
2966 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2968 IMAGE_SPECIFIER_ALLOWED(image) = ~0; /* all are allowed */
2969 IMAGE_SPECIFIER_ATTACHEE(image) = Qnil;
2970 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = Qnil;
2973 static void image_mark(Lisp_Object obj)
2975 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2977 mark_object(IMAGE_SPECIFIER_ATTACHEE(image));
2978 mark_object(IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image));
2981 static int instantiator_eq_equal(Lisp_Object obj1, Lisp_Object obj2)
2986 else if (CONSP(obj1) && CONSP(obj2)) {
2987 return instantiator_eq_equal(XCAR(obj1), XCAR(obj2))
2988 && instantiator_eq_equal(XCDR(obj1), XCDR(obj2));
2993 static hcode_t instantiator_eq_hash(Lisp_Object obj)
2996 /* no point in worrying about tail recursion, since we're not
2998 return HASH2(instantiator_eq_hash(XCAR(obj)),
2999 instantiator_eq_hash(XCDR(obj)));
3001 return LISP_HASH(obj);
3004 /* We need a special hash table for storing image instances. */
3005 Lisp_Object make_image_instance_cache_hash_table(void)
3007 return make_general_lisp_hash_table
3008 (instantiator_eq_hash, instantiator_eq_equal,
3009 30, -1.0, -1.0, HASH_TABLE_KEY_CAR_VALUE_WEAK);
3012 static Lisp_Object image_instantiate_cache_result(Lisp_Object locative)
3014 /* locative = (instance instantiator . subtable)
3016 So we are using the instantiator as the key and the instance as
3017 the value. Since the hashtable is key-weak this means that the
3018 image instance will stay around as long as the instantiator stays
3019 around. The instantiator is stored in the `image' slot of the
3020 glyph, so as long as the glyph is marked the instantiator will be
3021 as well and hence the cached image instance also. */
3022 Fputhash(XCAR(XCDR(locative)), XCAR(locative), XCDR(XCDR(locative)));
3023 free_cons(XCONS(XCDR(locative)));
3024 free_cons(XCONS(locative));
3028 /* Given a specification for an image, return an instance of
3029 the image which matches the given instantiator and which can be
3030 displayed in the given domain. */
3033 image_instantiate(Lisp_Object specifier, Lisp_Object matchspec,
3034 Lisp_Object domain, Lisp_Object instantiator,
3038 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3039 int dest_mask = XIMAGE_SPECIFIER_ALLOWED(specifier);
3040 int pointerp = dest_mask & image_instance_type_to_mask(IMAGE_POINTER);
3042 if (IMAGE_INSTANCEP(instantiator)) {
3043 /* make sure that the image instance's governing domain and type are
3045 Lisp_Object governing_domain =
3046 XIMAGE_INSTANCE_DOMAIN(instantiator);
3048 if ((DEVICEP(governing_domain)
3049 && EQ(governing_domain, DOMAIN_DEVICE(domain)))
3050 || (FRAMEP(governing_domain)
3051 && EQ(governing_domain, DOMAIN_FRAME(domain)))
3052 || (WINDOWP(governing_domain)
3053 && EQ(governing_domain, DOMAIN_WINDOW(domain)))) {
3055 image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE
3057 if (mask & dest_mask)
3058 return instantiator;
3061 ("Type of image instance not allowed here",
3064 signal_simple_error_2("Wrong domain for image instance",
3065 instantiator, domain);
3067 /* How ugly !! An image instanciator that uses a kludgy syntax to snarf in
3068 face properties. There's a design flaw here. -- didier */
3069 else if (VECTORP(instantiator)
3070 && EQ(INSTANTIATOR_TYPE(instantiator), Qinherit)) {
3071 assert(XVECTOR_LENGTH(instantiator) == 3);
3072 return (FACE_PROPERTY_INSTANCE
3073 (Fget_face(XVECTOR_DATA(instantiator)[2]),
3074 Qbackground_pixmap, domain, 1, depth));
3076 Lisp_Object instance = Qnil;
3077 Lisp_Object subtable = Qnil;
3078 /* #### Should this be GCPRO'd? */
3079 Lisp_Object hash_key = Qnil;
3080 Lisp_Object pointer_fg = Qnil;
3081 Lisp_Object pointer_bg = Qnil;
3082 Lisp_Object governing_domain =
3083 get_image_instantiator_governing_domain(instantiator,
3085 struct gcpro gcpro1;
3089 /* We have to put subwindow, widget and text image instances in
3090 a per-window cache so that we can see the same glyph in
3091 different windows. We use governing_domain to determine the type
3092 of image_instance that will be created. */
3095 pointer_fg = FACE_FOREGROUND(Vpointer_face, domain);
3096 pointer_bg = FACE_BACKGROUND(Vpointer_face, domain);
3097 hash_key = list4(glyph, INSTANTIATOR_TYPE(instantiator),
3098 pointer_fg, pointer_bg);
3100 /* We cannot simply key on the glyph since fallbacks could use
3101 the same glyph but have a totally different instantiator
3102 type. Thus we key on the glyph and the type (but not any
3103 other parts of the instantiator. */
3105 list2(glyph, INSTANTIATOR_TYPE(instantiator));
3107 /* First look in the device cache. */
3108 if (DEVICEP(governing_domain)) {
3109 subtable = Fgethash(make_int(dest_mask),
3110 XDEVICE(governing_domain)->
3111 image_instance_cache, Qunbound);
3112 if (UNBOUNDP(subtable)) {
3113 /* For the image instance cache, we do comparisons with
3114 EQ rather than with EQUAL, as we do for color and
3115 font names. The reasons are:
3117 1) pixmap data can be very long, and thus the hashing
3118 and comparing will take awhile.
3120 2) It's not so likely that we'll run into things that
3121 are EQUAL but not EQ (that can happen a lot with
3122 faces, because their specifiers are copied around);
3123 but pixmaps tend not to be in faces.
3125 However, if the image-instance could be a pointer, we
3126 have to use EQUAL because we massaged the
3127 instantiator into a cons3 also containing the
3128 foreground and background of the pointer face. */
3130 make_image_instance_cache_hash_table();
3132 Fputhash(make_int(dest_mask), subtable,
3133 XDEVICE(governing_domain)->
3134 image_instance_cache);
3135 instance = Qunbound;
3138 Fgethash(hash_key, subtable, Qunbound);
3140 } else if (WINDOWP(governing_domain)) {
3141 /* Subwindows have a per-window cache and have to be treated
3145 XWINDOW(governing_domain)->
3146 subwindow_instance_cache, Qunbound);
3148 abort(); /* We're not allowed anything else currently. */
3150 /* If we don't have an instance at this point then create
3152 if (UNBOUNDP(instance)) {
3153 Lisp_Object locative = noseeum_cons(Qnil,
3162 subwindow_instance_cache));
3163 int speccount = specpdl_depth();
3165 /* Make sure we cache the failures, too. Use an
3166 unwind-protect to catch such errors. If we fail, the
3167 unwind-protect records nil in the hash table. If we
3168 succeed, we change the car of the locative to the
3169 resulting instance, which gets recorded instead. */
3170 record_unwind_protect(image_instantiate_cache_result,
3173 instantiate_image_instantiator(governing_domain,
3174 domain, instantiator,
3179 /* We need a per-frame cache for redisplay. */
3180 cache_subwindow_instance_in_frame_maybe(instance);
3182 Fsetcar(locative, instance);
3183 #ifdef ERROR_CHECK_GLYPHS
3184 if (image_instance_type_to_mask
3185 (XIMAGE_INSTANCE_TYPE(instance))
3186 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3187 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3188 DOMAIN_FRAME(domain)));
3190 unbind_to(speccount, Qnil);
3191 #ifdef ERROR_CHECK_GLYPHS
3192 if (image_instance_type_to_mask
3193 (XIMAGE_INSTANCE_TYPE(instance))
3194 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3195 assert(EQ(Fgethash(hash_key,
3196 XWINDOW(governing_domain)
3197 ->subwindow_instance_cache,
3198 Qunbound), instance));
3200 } else if (NILP(instance))
3202 ("Can't instantiate image (probably cached)",
3204 /* We found an instance. However, because we are using the glyph
3205 as the hash key instead of the instantiator, the current
3206 instantiator may not be the same as the original. Thus we
3207 must update the instance based on the new
3208 instantiator. Preserving instance identity like this is
3209 important to stop excessive window system widget creation and
3210 deletion - and hence flashing. */
3212 /* #### This function should be able to cope with *all*
3213 changes to the instantiator, but currently only copes
3214 with the most used properties. This means that it is
3215 possible to make changes that don't get reflected in the
3217 update_image_instance(instance, instantiator);
3218 free_list(hash_key);
3221 #ifdef ERROR_CHECK_GLYPHS
3222 if (image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE(instance))
3223 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3224 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3225 DOMAIN_FRAME(domain)));
3227 ERROR_CHECK_IMAGE_INSTANCE(instance);
3228 RETURN_UNGCPRO(instance);
3232 return Qnil; /* not reached */
3235 /* Validate an image instantiator. */
3237 static void image_validate(Lisp_Object instantiator)
3239 if (IMAGE_INSTANCEP(instantiator) || STRINGP(instantiator))
3241 else if (VECTORP(instantiator)) {
3242 Lisp_Object *elt = XVECTOR_DATA(instantiator);
3243 int instantiator_len = XVECTOR_LENGTH(instantiator);
3244 struct image_instantiator_methods *meths;
3245 Lisp_Object already_seen = Qnil;
3246 struct gcpro gcpro1;
3249 if (instantiator_len < 1)
3250 signal_simple_error("Vector length must be at least 1",
3253 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3254 if (!(instantiator_len & 1))
3256 ("Must have alternating keyword/value pairs",
3259 GCPRO1(already_seen);
3261 for (i = 1; i < instantiator_len; i += 2) {
3262 Lisp_Object keyword = elt[i];
3263 Lisp_Object value = elt[i + 1];
3266 CHECK_SYMBOL(keyword);
3267 if (!SYMBOL_IS_KEYWORD(keyword))
3269 ("Symbol must begin with a colon", keyword);
3271 for (j = 0; j < Dynarr_length(meths->keywords); j++)
3274 Dynarr_at(meths->keywords, j).keyword))
3277 if (j == Dynarr_length(meths->keywords))
3278 signal_simple_error("Unrecognized keyword",
3281 if (!Dynarr_at(meths->keywords, j).multiple_p) {
3282 if (!NILP(memq_no_quit(keyword, already_seen)))
3284 ("Keyword may not appear more than once",
3286 already_seen = Fcons(keyword, already_seen);
3289 (Dynarr_at(meths->keywords, j).validate) (value);
3294 MAYBE_IIFORMAT_METH(meths, validate, (instantiator));
3296 signal_simple_error("Must be string or vector", instantiator);
3299 static void image_after_change(Lisp_Object specifier, Lisp_Object locale)
3301 Lisp_Object attachee =
3302 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3303 Lisp_Object property =
3304 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(XIMAGE_SPECIFIER(specifier));
3305 if (FACEP(attachee)) {
3306 face_property_was_changed(attachee, property, locale);
3307 if (BUFFERP(locale))
3308 XBUFFER(locale)->buffer_local_face_property = 1;
3309 } else if (GLYPHP(attachee))
3310 glyph_property_was_changed(attachee, property, locale);
3314 set_image_attached_to(Lisp_Object obj, Lisp_Object face_or_glyph,
3315 Lisp_Object property)
3317 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
3319 IMAGE_SPECIFIER_ATTACHEE(image) = face_or_glyph;
3320 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = property;
3324 image_going_to_add(Lisp_Object specifier, Lisp_Object locale,
3325 Lisp_Object tag_set, Lisp_Object instantiator)
3327 Lisp_Object possible_console_types = Qnil;
3329 Lisp_Object retlist = Qnil;
3330 struct gcpro gcpro1, gcpro2;
3332 LIST_LOOP(rest, Vconsole_type_list) {
3333 Lisp_Object contype = XCAR(rest);
3334 if (!NILP(memq_no_quit(contype, tag_set)))
3335 possible_console_types =
3336 Fcons(contype, possible_console_types);
3339 if (XINT(Flength(possible_console_types)) > 1)
3340 /* two conflicting console types specified */
3343 if (NILP(possible_console_types))
3344 possible_console_types = Vconsole_type_list;
3346 GCPRO2(retlist, possible_console_types);
3348 LIST_LOOP(rest, possible_console_types) {
3349 Lisp_Object contype = XCAR(rest);
3350 Lisp_Object newinst = call_with_suspended_errors
3351 ((lisp_fn_t) normalize_image_instantiator,
3352 Qnil, Qimage, ERROR_ME_NOT, 3, instantiator, contype,
3353 make_int(XIMAGE_SPECIFIER_ALLOWED(specifier)));
3355 if (!NILP(newinst)) {
3357 if (NILP(memq_no_quit(contype, tag_set)))
3358 newtag = Fcons(contype, tag_set);
3361 retlist = Fcons(Fcons(newtag, newinst), retlist);
3370 /* Copy an image instantiator. We can't use Fcopy_tree since widgets
3371 may contain circular references which would send Fcopy_tree into
3373 static Lisp_Object image_copy_vector_instantiator(Lisp_Object instantiator)
3376 struct image_instantiator_methods *meths;
3378 int instantiator_len;
3380 CHECK_VECTOR(instantiator);
3382 instantiator = Fcopy_sequence(instantiator);
3383 elt = XVECTOR_DATA(instantiator);
3384 instantiator_len = XVECTOR_LENGTH(instantiator);
3386 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3388 for (i = 1; i < instantiator_len; i += 2) {
3390 Lisp_Object keyword = elt[i];
3391 Lisp_Object value = elt[i + 1];
3393 /* Find the keyword entry. */
3394 for (j = 0; j < Dynarr_length(meths->keywords); j++) {
3395 if (EQ(keyword, Dynarr_at(meths->keywords, j).keyword))
3399 /* Only copy keyword values that should be copied. */
3400 if (Dynarr_at(meths->keywords, j).copy_p
3401 && (CONSP(value) || VECTORP(value))) {
3402 elt[i + 1] = Fcopy_tree(value, Qt);
3406 return instantiator;
3409 static Lisp_Object image_copy_instantiator(Lisp_Object arg)
3413 rest = arg = Fcopy_sequence(arg);
3414 while (CONSP(rest)) {
3415 Lisp_Object elt = XCAR(rest);
3417 XCAR(rest) = Fcopy_tree(elt, Qt);
3418 else if (VECTORP(elt))
3420 image_copy_vector_instantiator(elt);
3421 if (VECTORP(XCDR(rest))) /* hack for (a b . [c d]) */
3422 XCDR(rest) = Fcopy_tree(XCDR(rest), Qt);
3425 } else if (VECTORP(arg)) {
3426 arg = image_copy_vector_instantiator(arg);
3431 DEFUN("image-specifier-p", Fimage_specifier_p, 1, 1, 0, /*
3432 Return non-nil if OBJECT is an image specifier.
3433 See `make-image-specifier' for a description of image instantiators.
3437 return IMAGE_SPECIFIERP(object) ? Qt : Qnil;
3440 /****************************************************************************
3442 ****************************************************************************/
3444 static Lisp_Object mark_glyph(Lisp_Object obj)
3446 Lisp_Glyph *glyph = XGLYPH(obj);
3448 mark_object(glyph->image);
3449 mark_object(glyph->contrib_p);
3450 mark_object(glyph->baseline);
3451 mark_object(glyph->face);
3453 return glyph->plist;
3457 print_glyph(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
3459 Lisp_Glyph *glyph = XGLYPH(obj);
3461 error("printing unreadable object #<glyph 0x%x>",
3464 write_c_string("#<glyph (", printcharfun);
3465 print_internal(Fglyph_type(obj), printcharfun, 0);
3466 write_c_string(") ", printcharfun);
3467 print_internal(glyph->image, printcharfun, 1);
3468 write_fmt_str(printcharfun, "0x%x>", glyph->header.uid);
3471 /* Glyphs are equal if all of their display attributes are equal. We
3472 don't compare names or doc-strings, because that would make equal
3475 This isn't concerned with "unspecified" attributes, that's what
3476 #'glyph-differs-from-default-p is for. */
3477 static int glyph_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
3479 Lisp_Glyph *g1 = XGLYPH(obj1);
3480 Lisp_Glyph *g2 = XGLYPH(obj2);
3484 return (internal_equal(g1->image, g2->image, depth) &&
3485 internal_equal(g1->contrib_p, g2->contrib_p, depth) &&
3486 internal_equal(g1->baseline, g2->baseline, depth) &&
3487 internal_equal(g1->face, g2->face, depth) &&
3488 !plists_differ(g1->plist, g2->plist, 0, 0, depth + 1));
3491 static unsigned long glyph_hash(Lisp_Object obj, int depth)
3495 /* No need to hash all of the elements; that would take too long.
3496 Just hash the most common ones. */
3497 return HASH2(internal_hash(XGLYPH(obj)->image, depth),
3498 internal_hash(XGLYPH(obj)->face, depth));
3501 static Lisp_Object glyph_getprop(Lisp_Object obj, Lisp_Object prop)
3503 Lisp_Glyph *g = XGLYPH(obj);
3505 if (EQ(prop, Qimage))
3507 if (EQ(prop, Qcontrib_p))
3508 return g->contrib_p;
3509 if (EQ(prop, Qbaseline))
3511 if (EQ(prop, Qface))
3514 return external_plist_get(&g->plist, prop, 0, ERROR_ME);
3517 static int glyph_putprop(Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
3519 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3522 if (EQ(prop, Qface)) {
3523 XGLYPH(obj)->face = Fget_face(value);
3527 external_plist_put(&XGLYPH(obj)->plist, prop, value, 0, ERROR_ME);
3531 static int glyph_remprop(Lisp_Object obj, Lisp_Object prop)
3533 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3536 if (EQ(prop, Qface)) {
3537 XGLYPH(obj)->face = Qnil;
3541 return external_remprop(&XGLYPH(obj)->plist, prop, 0, ERROR_ME);
3544 static Lisp_Object glyph_plist(Lisp_Object obj)
3546 Lisp_Glyph *glyph = XGLYPH(obj);
3547 Lisp_Object result = glyph->plist;
3549 result = cons3(Qface, glyph->face, result);
3550 result = cons3(Qbaseline, glyph->baseline, result);
3551 result = cons3(Qcontrib_p, glyph->contrib_p, result);
3552 result = cons3(Qimage, glyph->image, result);
3557 static const struct lrecord_description glyph_description[] = {
3558 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, image)},
3559 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, contrib_p)},
3560 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, baseline)},
3561 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, face)},
3562 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, plist)},
3566 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS("glyph", glyph,
3567 mark_glyph, print_glyph, 0,
3568 glyph_equal, glyph_hash,
3569 glyph_description, glyph_getprop,
3570 glyph_putprop, glyph_remprop,
3571 glyph_plist, Lisp_Glyph);
3574 allocate_glyph(enum glyph_type type,
3575 void (*after_change) (Lisp_Object glyph, Lisp_Object property,
3576 Lisp_Object locale))
3578 /* This function can GC */
3579 Lisp_Object obj = Qnil;
3580 Lisp_Glyph *g = alloc_lcrecord_type(Lisp_Glyph, &lrecord_glyph);
3583 g->image = Fmake_specifier(Qimage); /* This function can GC */
3587 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3588 IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK
3589 | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
3590 | IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK;
3593 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3594 IMAGE_NOTHING_MASK | IMAGE_POINTER_MASK;
3597 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3598 IMAGE_NOTHING_MASK | IMAGE_MONO_PIXMAP_MASK
3599 | IMAGE_COLOR_PIXMAP_MASK;
3606 /* I think Fmake_specifier can GC. I think set_specifier_fallback can GC. */
3607 /* We're getting enough reports of odd behavior in this area it seems */
3608 /* best to GCPRO everything. */
3610 Lisp_Object tem1 = list1(Fcons(Qnil, Vthe_nothing_vector));
3611 Lisp_Object tem2 = list1(Fcons(Qnil, Qt));
3612 Lisp_Object tem3 = list1(Fcons(Qnil, Qnil));
3613 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3615 GCPRO4(obj, tem1, tem2, tem3);
3617 set_specifier_fallback(g->image, tem1);
3618 g->contrib_p = Fmake_specifier(Qboolean);
3619 set_specifier_fallback(g->contrib_p, tem2);
3620 /* #### should have a specifier for the following */
3621 g->baseline = Fmake_specifier(Qgeneric);
3622 set_specifier_fallback(g->baseline, tem3);
3625 g->after_change = after_change;
3628 set_image_attached_to(g->image, obj, Qimage);
3635 static enum glyph_type decode_glyph_type(Lisp_Object type, Error_behavior errb)
3638 return GLYPH_BUFFER;
3640 if (ERRB_EQ(errb, ERROR_ME))
3643 if (EQ(type, Qbuffer))
3644 return GLYPH_BUFFER;
3645 if (EQ(type, Qpointer))
3646 return GLYPH_POINTER;
3647 if (EQ(type, Qicon))
3650 maybe_signal_simple_error("Invalid glyph type", type, Qimage, errb);
3652 return GLYPH_UNKNOWN;
3655 static int valid_glyph_type_p(Lisp_Object type)
3657 return !NILP(memq_no_quit(type, Vglyph_type_list));
3660 DEFUN("valid-glyph-type-p", Fvalid_glyph_type_p, 1, 1, 0, /*
3661 Given a GLYPH-TYPE, return non-nil if it is valid.
3662 Valid types are `buffer', `pointer', and `icon'.
3666 return valid_glyph_type_p(glyph_type) ? Qt : Qnil;
3669 DEFUN("glyph-type-list", Fglyph_type_list, 0, 0, 0, /*
3670 Return a list of valid glyph types.
3674 return Fcopy_sequence(Vglyph_type_list);
3677 DEFUN("make-glyph-internal", Fmake_glyph_internal, 0, 1, 0, /*
3678 Create and return a new uninitialized glyph of type TYPE.
3680 TYPE specifies the type of the glyph; this should be one of `buffer',
3681 `pointer', or `icon', and defaults to `buffer'. The type of the glyph
3682 specifies in which contexts the glyph can be used, and controls the
3683 allowable image types into which the glyph's image can be
3686 `buffer' glyphs can be used as the begin-glyph or end-glyph of an
3687 extent, in the modeline, and in the toolbar. Their image can be
3688 instantiated as `nothing', `mono-pixmap', `color-pixmap', `text',
3691 `pointer' glyphs can be used to specify the mouse pointer. Their
3692 image can be instantiated as `pointer'.
3694 `icon' glyphs can be used to specify the icon used when a frame is
3695 iconified. Their image can be instantiated as `mono-pixmap' and
3700 enum glyph_type typeval = decode_glyph_type(type, ERROR_ME);
3701 return allocate_glyph(typeval, 0);
3704 DEFUN("glyphp", Fglyphp, 1, 1, 0, /*
3705 Return non-nil if OBJECT is a glyph.
3707 A glyph is an object used for pixmaps, widgets and the like. It is used
3708 in begin-glyphs and end-glyphs attached to extents, in marginal and textual
3709 annotations, in overlay arrows (overlay-arrow-* variables), in toolbar
3710 buttons, and the like. Much more detailed information can be found at
3711 `make-glyph'. Its image is described using an image specifier --
3712 see `make-image-specifier'. See also `make-image-instance' for further
3717 return GLYPHP(object) ? Qt : Qnil;
3720 DEFUN("glyph-type", Fglyph_type, 1, 1, 0, /*
3721 Return the type of the given glyph.
3722 The return value will be one of 'buffer, 'pointer, or 'icon.
3727 switch (XGLYPH_TYPE(glyph)) {
3743 glyph_image_instance(Lisp_Object glyph, Lisp_Object domain,
3744 Error_behavior errb, int no_quit)
3746 Lisp_Object specifier = GLYPH_IMAGE(XGLYPH(glyph));
3748 /* This can never return Qunbound. All glyphs have 'nothing as
3750 Lisp_Object image_instance = specifier_instance(specifier, Qunbound,
3751 domain, errb, no_quit,
3754 assert(!UNBOUNDP(image_instance));
3755 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
3757 return image_instance;
3761 glyph_image_instance_maybe(Lisp_Object glyph_or_image, Lisp_Object window)
3763 Lisp_Object instance = glyph_or_image;
3765 if (GLYPHP(glyph_or_image))
3767 glyph_image_instance(glyph_or_image, window, ERROR_ME_NOT,
3773 /*****************************************************************************
3776 Return the width of the given GLYPH on the given WINDOW.
3777 Calculations are done based on recursively querying the geometry of
3778 the associated image instances.
3779 ****************************************************************************/
3780 unsigned short glyph_width(Lisp_Object glyph_or_image, Lisp_Object domain)
3782 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3784 if (!IMAGE_INSTANCEP(instance))
3787 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3788 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3789 IMAGE_UNSPECIFIED_GEOMETRY,
3790 IMAGE_UNCHANGED_GEOMETRY,
3791 IMAGE_UNCHANGED_GEOMETRY, domain);
3793 return XIMAGE_INSTANCE_WIDTH(instance);
3796 DEFUN("glyph-width", Fglyph_width, 1, 2, 0, /*
3797 Return the width of GLYPH on WINDOW.
3798 This may not be exact as it does not take into account all of the context
3799 that redisplay will.
3803 XSETWINDOW(window, decode_window(window));
3806 return make_int(glyph_width(glyph, window));
3809 unsigned short glyph_ascent(Lisp_Object glyph_or_image, Lisp_Object domain)
3811 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3813 if (!IMAGE_INSTANCEP(instance))
3816 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3817 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3818 IMAGE_UNSPECIFIED_GEOMETRY,
3819 IMAGE_UNCHANGED_GEOMETRY,
3820 IMAGE_UNCHANGED_GEOMETRY, domain);
3822 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3823 return XIMAGE_INSTANCE_TEXT_ASCENT(instance);
3825 return XIMAGE_INSTANCE_HEIGHT(instance);
3828 unsigned short glyph_descent(Lisp_Object glyph_or_image, Lisp_Object domain)
3830 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3832 if (!IMAGE_INSTANCEP(instance))
3835 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3836 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3837 IMAGE_UNSPECIFIED_GEOMETRY,
3838 IMAGE_UNCHANGED_GEOMETRY,
3839 IMAGE_UNCHANGED_GEOMETRY, domain);
3841 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3842 return XIMAGE_INSTANCE_TEXT_DESCENT(instance);
3847 /* strictly a convenience function. */
3848 unsigned short glyph_height(Lisp_Object glyph_or_image, Lisp_Object domain)
3850 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3853 if (!IMAGE_INSTANCEP(instance))
3856 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3857 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3858 IMAGE_UNSPECIFIED_GEOMETRY,
3859 IMAGE_UNCHANGED_GEOMETRY,
3860 IMAGE_UNCHANGED_GEOMETRY, domain);
3862 return XIMAGE_INSTANCE_HEIGHT(instance);
3865 DEFUN("glyph-ascent", Fglyph_ascent, 1, 2, 0, /*
3866 Return the ascent value of GLYPH on WINDOW.
3867 This may not be exact as it does not take into account all of the context
3868 that redisplay will.
3872 XSETWINDOW(window, decode_window(window));
3875 return make_int(glyph_ascent(glyph, window));
3878 DEFUN("glyph-descent", Fglyph_descent, 1, 2, 0, /*
3879 Return the descent value of GLYPH on WINDOW.
3880 This may not be exact as it does not take into account all of the context
3881 that redisplay will.
3885 XSETWINDOW(window, decode_window(window));
3888 return make_int(glyph_descent(glyph, window));
3891 /* This is redundant but I bet a lot of people expect it to exist. */
3892 DEFUN("glyph-height", Fglyph_height, 1, 2, 0, /*
3893 Return the height of GLYPH on WINDOW.
3894 This may not be exact as it does not take into account all of the context
3895 that redisplay will.
3899 XSETWINDOW(window, decode_window(window));
3902 return make_int(glyph_height(glyph, window));
3906 set_glyph_dirty_p(Lisp_Object glyph_or_image, Lisp_Object window, int dirty)
3908 Lisp_Object instance = glyph_or_image;
3910 if (!NILP(glyph_or_image)) {
3911 if (GLYPHP(glyph_or_image)) {
3912 instance = glyph_image_instance(glyph_or_image, window,
3914 XGLYPH_DIRTYP(glyph_or_image) = dirty;
3917 if (!IMAGE_INSTANCEP(instance))
3920 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3924 static void set_image_instance_dirty_p(Lisp_Object instance, int dirty)
3926 if (IMAGE_INSTANCEP(instance)) {
3927 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3928 /* Now cascade up the hierarchy. */
3929 set_image_instance_dirty_p(XIMAGE_INSTANCE_PARENT(instance),
3931 } else if (GLYPHP(instance)) {
3932 XGLYPH_DIRTYP(instance) = dirty;
3936 /* #### do we need to cache this info to speed things up? */
3938 Lisp_Object glyph_baseline(Lisp_Object glyph, Lisp_Object domain)
3943 Lisp_Object retval =
3944 specifier_instance_no_quit(GLYPH_BASELINE(XGLYPH(glyph)),
3945 /* #### look into ERROR_ME_NOT */
3946 Qunbound, domain, ERROR_ME_NOT,
3948 if (!NILP(retval) && !INTP(retval))
3950 else if (INTP(retval)) {
3951 if (XINT(retval) < 0)
3953 if (XINT(retval) > 100)
3954 retval = make_int(100);
3960 Lisp_Object glyph_face(Lisp_Object glyph, Lisp_Object domain)
3962 /* #### Domain parameter not currently used but it will be */
3963 return GLYPHP(glyph) ? GLYPH_FACE(XGLYPH(glyph)) : Qnil;
3966 int glyph_contrib_p(Lisp_Object glyph, Lisp_Object domain)
3971 return !NILP(specifier_instance_no_quit
3972 (GLYPH_CONTRIB_P(XGLYPH(glyph)), Qunbound, domain,
3973 /* #### look into ERROR_ME_NOT */
3974 ERROR_ME_NOT, 0, Qzero));
3978 glyph_property_was_changed(Lisp_Object glyph, Lisp_Object property,
3981 if (XGLYPH(glyph)->after_change)
3982 (XGLYPH(glyph)->after_change) (glyph, property, locale);
3986 glyph_query_geometry(Lisp_Object glyph_or_image, int *width, int *height,
3987 enum image_instance_geometry disp, Lisp_Object domain)
3989 Lisp_Object instance = glyph_or_image;
3991 if (GLYPHP(glyph_or_image))
3993 glyph_image_instance(glyph_or_image, domain, ERROR_ME_NOT,
3996 image_instance_query_geometry(instance, width, height, disp, domain);
4000 glyph_do_layout(Lisp_Object glyph_or_image, int width, int height,
4001 int xoffset, int yoffset, Lisp_Object domain)
4003 Lisp_Object instance = glyph_or_image;
4005 if (GLYPHP(glyph_or_image))
4007 glyph_image_instance(glyph_or_image, domain, ERROR_ME_NOT,
4010 image_instance_layout(instance, width, height, xoffset, yoffset,
4014 /*****************************************************************************
4015 * glyph cachel functions *
4016 *****************************************************************************/
4018 /* #### All of this is 95% copied from face cachels. Consider
4021 Why do we need glyph_cachels? Simply because a glyph_cachel captures
4022 per-window information about a particular glyph. A glyph itself is
4023 not created in any particular context, so if we were to rely on a
4024 glyph to tell us about its dirtiness we would not be able to reset
4025 the dirty flag after redisplaying it as it may exist in other
4026 contexts. When we have redisplayed we need to know which glyphs to
4027 reset the dirty flags on - the glyph_cachels give us a nice list we
4028 can iterate through doing this. */
4029 void mark_glyph_cachels(glyph_cachel_dynarr * elements)
4036 for (elt = 0; elt < Dynarr_length(elements); elt++) {
4037 struct glyph_cachel *cachel = Dynarr_atp(elements, elt);
4038 mark_object(cachel->glyph);
4043 update_glyph_cachel_data(struct window *w, Lisp_Object glyph,
4044 struct glyph_cachel *cachel)
4046 if (!cachel->updated || NILP(cachel->glyph) || !EQ(cachel->glyph, glyph)
4047 || XGLYPH_DIRTYP(cachel->glyph)
4048 || XFRAME(WINDOW_FRAME(w))->faces_changed) {
4049 Lisp_Object window, instance;
4051 XSETWINDOW(window, w);
4053 cachel->glyph = glyph;
4054 /* Speed things up slightly by grabbing the glyph instantiation
4055 and passing it to the size functions. */
4056 instance = glyph_image_instance(glyph, window, ERROR_ME_NOT, 1);
4058 if (!IMAGE_INSTANCEP(instance))
4061 /* Mark text instance of the glyph dirty if faces have changed,
4062 because its geometry might have changed. */
4063 invalidate_glyph_geometry_maybe(instance, w);
4065 /* #### Do the following 2 lines buy us anything? --kkm */
4066 XGLYPH_DIRTYP(glyph) = XIMAGE_INSTANCE_DIRTYP(instance);
4067 cachel->dirty = XGLYPH_DIRTYP(glyph);
4068 cachel->width = glyph_width(instance, window);
4069 cachel->ascent = glyph_ascent(instance, window);
4070 cachel->descent = glyph_descent(instance, window);
4073 cachel->updated = 1;
4076 static void add_glyph_cachel(struct window *w, Lisp_Object glyph)
4078 struct glyph_cachel new_cachel;
4081 new_cachel.glyph = Qnil;
4083 update_glyph_cachel_data(w, glyph, &new_cachel);
4084 Dynarr_add(w->glyph_cachels, new_cachel);
4087 glyph_index get_glyph_cachel_index(struct window *w, Lisp_Object glyph)
4094 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4095 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4097 if (EQ(cachel->glyph, glyph) && !NILP(glyph)) {
4098 update_glyph_cachel_data(w, glyph, cachel);
4103 /* If we didn't find the glyph, add it and then return its index. */
4104 add_glyph_cachel(w, glyph);
4108 void reset_glyph_cachels(struct window *w)
4110 Dynarr_reset(w->glyph_cachels);
4111 get_glyph_cachel_index(w, Vcontinuation_glyph);
4112 get_glyph_cachel_index(w, Vtruncation_glyph);
4113 get_glyph_cachel_index(w, Vhscroll_glyph);
4114 get_glyph_cachel_index(w, Vcontrol_arrow_glyph);
4115 get_glyph_cachel_index(w, Voctal_escape_glyph);
4116 get_glyph_cachel_index(w, Vinvisible_text_glyph);
4119 void mark_glyph_cachels_as_not_updated(struct window *w)
4123 /* We need to have a dirty flag to tell if the glyph has changed.
4124 We can check to see if each glyph variable is actually a
4125 completely different glyph, though. */
4126 #define FROB(glyph_obj, gindex) \
4127 update_glyph_cachel_data (w, glyph_obj, \
4128 Dynarr_atp (w->glyph_cachels, gindex))
4130 FROB(Vcontinuation_glyph, CONT_GLYPH_INDEX);
4131 FROB(Vtruncation_glyph, TRUN_GLYPH_INDEX);
4132 FROB(Vhscroll_glyph, HSCROLL_GLYPH_INDEX);
4133 FROB(Vcontrol_arrow_glyph, CONTROL_GLYPH_INDEX);
4134 FROB(Voctal_escape_glyph, OCT_ESC_GLYPH_INDEX);
4135 FROB(Vinvisible_text_glyph, INVIS_GLYPH_INDEX);
4138 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4139 Dynarr_atp(w->glyph_cachels, elt)->updated = 0;
4143 /* Unset the dirty bit on all the glyph cachels that have it. */
4144 void mark_glyph_cachels_as_clean(struct window *w)
4148 XSETWINDOW(window, w);
4149 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4150 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4152 set_glyph_dirty_p(cachel->glyph, window, 0);
4156 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
4159 compute_glyph_cachel_usage(glyph_cachel_dynarr * glyph_cachels,
4160 struct overhead_stats *ovstats)
4165 total += Dynarr_memory_usage(glyph_cachels, ovstats);
4170 #endif /* MEMORY_USAGE_STATS */
4172 /*****************************************************************************
4173 * subwindow cachel functions *
4174 *****************************************************************************/
4175 /* Subwindows are curious in that you have to physically unmap them to
4176 not display them. It is problematic deciding what to do in
4177 redisplay. We have two caches - a per-window instance cache that
4178 keeps track of subwindows on a window, these are linked to their
4179 instantiator in the hashtable and when the instantiator goes away
4180 we want the instance to go away also. However we also have a
4181 per-frame instance cache that we use to determine if a subwindow is
4182 obscuring an area that we want to clear. We need to be able to flip
4183 through this quickly so a hashtable is not suitable hence the
4184 subwindow_cachels. This is a weak list so unreference instances
4185 will get deleted properly. */
4187 /* redisplay in general assumes that drawing something will erase
4188 what was there before. unfortunately this does not apply to
4189 subwindows that need to be specifically unmapped in order to
4190 disappear. we take a brute force approach - on the basis that its
4191 cheap - and unmap all subwindows in a display line */
4193 /* Put new instances in the frame subwindow cache. This is less costly than
4194 doing it every time something gets mapped, and deleted instances will be
4195 removed automatically. */
4196 static void cache_subwindow_instance_in_frame_maybe(Lisp_Object instance)
4198 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(instance);
4199 if (!NILP(DOMAIN_FRAME(IMAGE_INSTANCE_DOMAIN(ii)))) {
4200 struct frame *f = DOMAIN_XFRAME(IMAGE_INSTANCE_DOMAIN(ii));
4201 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4203 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f)));
4207 /* Unmap and finalize all subwindow instances in the frame cache. This
4208 is necessary because GC will not guarantee the order things get
4209 deleted in and moreover, frame finalization deletes the window
4210 system windows before deleting SXEmacs windows, and hence
4213 unmap_subwindow_instance_cache_mapper(Lisp_Object key, Lisp_Object value,
4216 /* value can be nil; we cache failures as well as successes */
4218 struct frame *f = XFRAME(XIMAGE_INSTANCE_FRAME(value));
4219 unmap_subwindow(value);
4221 /* In case GC doesn't catch up fast enough, remove from the frame
4222 cache also. Otherwise code that checks the sanity of the instance
4224 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4225 = delq_no_quit(value,
4226 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE
4228 finalize_image_instance(XIMAGE_INSTANCE(value), 0);
4234 static void finalize_all_subwindow_instances(struct window *w)
4237 finalize_all_subwindow_instances(XWINDOW(w->next));
4238 if (!NILP(w->vchild))
4239 finalize_all_subwindow_instances(XWINDOW(w->vchild));
4240 if (!NILP(w->hchild))
4241 finalize_all_subwindow_instances(XWINDOW(w->hchild));
4243 elisp_maphash(unmap_subwindow_instance_cache_mapper,
4244 w->subwindow_instance_cache, (void *)1);
4247 void free_frame_subwindow_instances(struct frame *f)
4249 /* Make sure all instances are finalized. We have to do this via the
4250 instance cache since some instances may be extant but not
4251 displayed (and hence not in the frame cache). */
4252 finalize_all_subwindow_instances(XWINDOW(f->root_window));
4255 /* Unmap all instances in the frame cache. */
4256 void reset_frame_subwindow_instance_cache(struct frame *f)
4260 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4261 Lisp_Object value = XCAR(rest);
4262 unmap_subwindow(value);
4266 /*****************************************************************************
4267 * subwindow exposure ignorance *
4268 *****************************************************************************/
4269 /* when we unmap subwindows the associated window system will generate
4270 expose events. This we do not want as redisplay already copes with
4271 the repainting necessary. Worse, we can get in an endless cycle of
4272 redisplay if we are not careful. Thus we keep a per-frame list of
4273 expose events that are going to come and ignore them as
4276 struct expose_ignore_blocktype {
4277 Blocktype_declare(struct expose_ignore);
4278 } *the_expose_ignore_blocktype;
4281 check_for_ignored_expose(struct frame *f, int x, int y, int width, int height)
4283 struct expose_ignore *ei, *prev;
4284 /* the ignore list is FIFO so we should generally get a match with
4285 the first element in the list */
4286 for (ei = f->subwindow_exposures, prev = 0; ei; ei = ei->next) {
4287 /* Checking for exact matches just isn't good enough as we
4288 might get exposures for partially obscured subwindows, thus
4289 we have to check for overlaps. Being conservative, we will
4290 check for exposures wholly contained by the subwindow - this
4291 might give us what we want. */
4292 if (ei->x <= (unsigned)x && ei->y <= (unsigned)y
4293 && ei->x + ei->width >= (unsigned)(x + width)
4294 && ei->y + ei->height >= (unsigned)(y + height)) {
4295 #ifdef DEBUG_WIDGETS
4297 ("ignored %d+%d, %dx%d for exposure %d+%d, %dx%d\n",
4298 x, y, width, height, ei->x, ei->y, ei->width,
4302 f->subwindow_exposures = ei->next;
4304 prev->next = ei->next;
4306 if (ei == f->subwindow_exposures_tail)
4307 f->subwindow_exposures_tail = prev;
4309 Blocktype_free(the_expose_ignore_blocktype, ei);
4318 register_ignored_expose(struct frame *f, int x, int y, int width, int height)
4320 if (!hold_ignored_expose_registration) {
4321 struct expose_ignore *ei;
4323 ei = Blocktype_alloc(the_expose_ignore_blocktype);
4329 ei->height = height;
4331 /* we have to add the exposure to the end of the list, since we
4332 want to check the oldest events first. for speed we keep a record
4333 of the end so that we can add right to it. */
4334 if (f->subwindow_exposures_tail) {
4335 f->subwindow_exposures_tail->next = ei;
4337 if (!f->subwindow_exposures) {
4338 f->subwindow_exposures = ei;
4340 f->subwindow_exposures_tail = ei;
4344 /****************************************************************************
4345 find_matching_subwindow
4347 See if there is a subwindow that completely encloses the requested
4349 ****************************************************************************/
4350 int find_matching_subwindow(struct frame *f, int x, int y, int width,
4355 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4356 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(XCAR(rest));
4358 if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii)
4360 IMAGE_INSTANCE_DISPLAY_X(ii) <= (unsigned)x
4362 IMAGE_INSTANCE_DISPLAY_Y(ii) <= (unsigned)y
4363 && IMAGE_INSTANCE_DISPLAY_X(ii)
4364 + IMAGE_INSTANCE_DISPLAY_WIDTH(ii) >= (unsigned)(x + width)
4365 && IMAGE_INSTANCE_DISPLAY_Y(ii)
4366 + IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) >=
4367 (unsigned)(y + height)) {
4374 /*****************************************************************************
4375 * subwindow functions *
4376 *****************************************************************************/
4378 /* Update the displayed characteristics of a subwindow. This function
4379 should generally only get called if the subwindow is actually
4381 void redisplay_subwindow(Lisp_Object subwindow)
4383 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4384 int count = specpdl_depth();
4386 /* The update method is allowed to call eval. Since it is quite
4387 common for this function to get called from somewhere in
4388 redisplay we need to make sure that quits are ignored. Otherwise
4389 Fsignal will abort. */
4390 specbind(Qinhibit_quit, Qt);
4392 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4394 if (WIDGET_IMAGE_INSTANCEP(subwindow)) {
4395 if (image_instance_changed(subwindow))
4396 redisplay_widget(subwindow);
4397 /* Reset the changed flags. */
4398 IMAGE_INSTANCE_WIDGET_FACE_CHANGED(ii) = 0;
4399 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii) = 0;
4400 IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii) = 0;
4401 IMAGE_INSTANCE_TEXT_CHANGED(ii) = 0;
4402 } else if (IMAGE_INSTANCE_TYPE(ii) == IMAGE_SUBWINDOW
4403 && !NILP(IMAGE_INSTANCE_FRAME(ii))) {
4404 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4405 redisplay_subwindow, (ii));
4408 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 0;
4409 /* This function is typically called by redisplay just before
4410 outputting the information to the screen. Thus we record a hash
4411 of the output to determine whether on-screen is the same as
4412 recorded structure. This approach has limitations in there is a
4413 good chance that hash values will be different for the same
4414 visual appearance. However, we would rather that then the other
4415 way round - it simply means that we will get more displays than
4416 we might need. We can get better hashing by making the depth
4417 negative - currently it will recurse down 7 levels. */
4418 IMAGE_INSTANCE_DISPLAY_HASH(ii) = internal_hash(subwindow,
4419 IMAGE_INSTANCE_HASH_DEPTH);
4421 unbind_to(count, Qnil);
4424 /* Determine whether an image_instance has changed structurally and
4425 hence needs redisplaying in some way.
4427 #### This should just look at the instantiator differences when we
4428 get rid of the stored items altogether. In fact we should probably
4429 store the new instantiator as well as the old - as we do with
4430 gui_items currently - and then pick-up the new on the next
4431 redisplay. This would obviate the need for any of this trickery
4433 int image_instance_changed(Lisp_Object subwindow)
4435 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4437 if (internal_hash(subwindow, IMAGE_INSTANCE_HASH_DEPTH) !=
4438 IMAGE_INSTANCE_DISPLAY_HASH(ii))
4440 /* #### I think there is probably a bug here. This gets called for
4441 layouts - and yet the pending items are always nil for
4442 layouts. We are saved by layout optimization, but I'm undecided
4443 as to what the correct fix is. */
4444 else if (WIDGET_IMAGE_INSTANCEP(subwindow)
4445 && (!internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(ii),
4446 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii), 0)
4447 || !NILP(IMAGE_INSTANCE_LAYOUT_CHILDREN(ii))
4448 || IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii)))
4454 /* Update all the subwindows on a frame. */
4455 void update_widget_instances(Lisp_Object frame)
4460 /* Its possible for the preceding callback to have deleted the
4461 frame, so cope with this. */
4462 if (!FRAMEP(frame) || !FRAME_LIVE_P(XFRAME(frame)))
4468 /* If we get called we know something has changed. */
4469 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4470 Lisp_Object widget = XCAR(rest);
4472 if (XIMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(widget)
4473 && image_instance_changed(widget)) {
4474 set_image_instance_dirty_p(widget, 1);
4475 MARK_FRAME_GLYPHS_CHANGED(f);
4480 /* remove a subwindow from its frame */
4481 void unmap_subwindow(Lisp_Object subwindow)
4483 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4486 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4488 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4489 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK))
4490 || !IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii))
4493 #ifdef DEBUG_WIDGETS
4494 stderr_out("unmapping subwindow %p\n", IMAGE_INSTANCE_SUBWINDOW_ID(ii));
4496 f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
4498 /* make sure we don't get expose events */
4499 register_ignored_expose(f, IMAGE_INSTANCE_DISPLAY_X(ii),
4500 IMAGE_INSTANCE_DISPLAY_Y(ii),
4501 IMAGE_INSTANCE_DISPLAY_WIDTH(ii),
4502 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii));
4503 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4505 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(ii)),
4506 unmap_subwindow, (ii));
4509 /* show a subwindow in its frame */
4510 void map_subwindow(Lisp_Object subwindow, int x, int y,
4511 struct display_glyph_area *dga)
4513 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4515 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4517 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4518 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK)))
4521 #ifdef DEBUG_WIDGETS
4522 stderr_out("mapping subwindow %p, %dx%d@%d+%d\n",
4523 IMAGE_INSTANCE_SUBWINDOW_ID(ii),
4524 dga->width, dga->height, x, y);
4526 (void)XFRAME(IMAGE_INSTANCE_FRAME(ii));
4527 IMAGE_INSTANCE_DISPLAY_X(ii) = x;
4528 IMAGE_INSTANCE_DISPLAY_Y(ii) = y;
4529 IMAGE_INSTANCE_DISPLAY_WIDTH(ii) = dga->width;
4530 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) = dga->height;
4532 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4533 map_subwindow, (ii, x, y, dga));
4534 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 1;
4537 static int subwindow_possible_dest_types(void)
4539 return IMAGE_SUBWINDOW_MASK;
4542 int subwindow_governing_domain(void)
4544 return GOVERNING_DOMAIN_WINDOW;
4547 /* Partially instantiate a subwindow. */
4549 subwindow_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
4550 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
4551 int dest_mask, Lisp_Object domain)
4553 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
4554 Lisp_Object device = image_instance_device(image_instance);
4555 Lisp_Object frame = DOMAIN_FRAME(domain);
4556 Lisp_Object width = find_keyword_in_vector(instantiator, Q_pixel_width);
4557 Lisp_Object height =
4558 find_keyword_in_vector(instantiator, Q_pixel_height);
4561 signal_simple_error("No selected frame", device);
4563 if (!(dest_mask & IMAGE_SUBWINDOW_MASK))
4564 incompatible_image_types(instantiator, dest_mask,
4565 IMAGE_SUBWINDOW_MASK);
4568 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = 0;
4569 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4573 if (XINT(width) > 1)
4575 IMAGE_INSTANCE_WIDTH(ii) = w;
4576 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP(ii) = 0;
4581 if (XINT(height) > 1)
4583 IMAGE_INSTANCE_HEIGHT(ii) = h;
4584 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP(ii) = 0;
4588 #ifdef HAVE_X_WINDOWS
4589 extern void x_subwindow_query_geometry(Lisp_Object image_instance,
4590 int *width, int *height);
4593 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4594 int *height, enum image_instance_geometry disp,
4597 if (IMAGE_INSTANCE_INITIALIZED(XIMAGE_INSTANCE(image_instance)))
4599 /* Query real size of subwindow */
4600 x_subwindow_query_geometry(image_instance, width, height);
4602 /* Set them in case of initial layout instantiation */
4610 /* This is just a backup in case no-one has assigned a suitable geometry.
4611 #### It should really query the enclose window for geometry. */
4613 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4614 int *height, enum image_instance_geometry disp,
4622 #endif /* HAVE_X_WINDOWS */
4624 DEFUN("subwindowp", Fsubwindowp, 1, 1, 0, /*
4625 Return non-nil if OBJECT is a subwindow.
4629 CHECK_IMAGE_INSTANCE(object);
4630 return (XIMAGE_INSTANCE_TYPE(object) == IMAGE_SUBWINDOW) ? Qt : Qnil;
4633 DEFUN("image-instance-subwindow-id", Fimage_instance_subwindow_id, 1, 1, 0, /*
4634 Return the window id of SUBWINDOW as a number.
4638 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4639 return make_int((EMACS_INT) XIMAGE_INSTANCE_SUBWINDOW_ID(subwindow));
4642 DEFUN("resize-subwindow", Fresize_subwindow, 1, 3, 0, /*
4643 Resize SUBWINDOW to WIDTH x HEIGHT.
4644 If a value is nil that parameter is not changed.
4646 (subwindow, width, height))
4649 Lisp_Image_Instance *ii;
4651 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4652 ii = XIMAGE_INSTANCE(subwindow);
4655 neww = IMAGE_INSTANCE_WIDTH(ii);
4660 newh = IMAGE_INSTANCE_HEIGHT(ii);
4662 newh = XINT(height);
4664 /* The actual resizing gets done asynchronously by
4665 update_subwindow. */
4666 IMAGE_INSTANCE_HEIGHT(ii) = newh;
4667 IMAGE_INSTANCE_WIDTH(ii) = neww;
4668 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
4673 DEFUN("force-subwindow-map", Fforce_subwindow_map, 1, 1, 0, /*
4674 Generate a Map event for SUBWINDOW.
4678 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4680 map_subwindow(subwindow, 0, 0);
4685 /*****************************************************************************
4687 *****************************************************************************/
4689 /* Get the display tables for use currently on window W with face
4690 FACE. #### This will have to be redone. */
4693 get_display_tables(struct window *w, face_index findex,
4694 Lisp_Object * face_table, Lisp_Object * window_table)
4697 tem = WINDOW_FACE_CACHEL_DISPLAY_TABLE(w, findex);
4701 tem = noseeum_cons(tem, Qnil);
4703 tem = w->display_table;
4707 tem = noseeum_cons(tem, Qnil);
4708 *window_table = tem;
4712 display_table_entry(Emchar ch, Lisp_Object face_table, Lisp_Object window_table)
4716 /* Loop over FACE_TABLE, and then over WINDOW_TABLE. */
4717 for (tail = face_table; 1; tail = XCDR(tail)) {
4720 if (!NILP(window_table)) {
4721 tail = window_table;
4722 window_table = Qnil;
4728 if (VECTORP(table)) {
4729 if (ch < XVECTOR_LENGTH(table)
4730 && !NILP(XVECTOR_DATA(table)[ch]))
4731 return XVECTOR_DATA(table)[ch];
4734 } else if (CHAR_TABLEP(table)
4735 && XCHAR_TABLE_TYPE(table) == CHAR_TABLE_TYPE_CHAR) {
4736 return get_char_table(ch, XCHAR_TABLE(table));
4737 } else if (CHAR_TABLEP(table)
4738 && XCHAR_TABLE_TYPE(table) ==
4739 CHAR_TABLE_TYPE_GENERIC) {
4741 get_char_table(ch, XCHAR_TABLE(table));
4746 } else if (RANGE_TABLEP(table)) {
4748 Fget_range_table(make_char(ch), table, Qnil);
4758 /*****************************************************************************
4759 * timeouts for animated glyphs *
4760 *****************************************************************************/
4761 static Lisp_Object Qglyph_animated_timeout_handler;
4763 DEFUN("glyph-animated-timeout-handler", Fglyph_animated_timeout_handler, 1, 1, 0, /*
4764 Callback function for updating animated images.
4769 CHECK_WEAK_LIST(arg);
4771 if (!NILP(XWEAK_LIST_LIST(arg)) && !NILP(XCAR(XWEAK_LIST_LIST(arg)))) {
4772 Lisp_Object value = XCAR(XWEAK_LIST_LIST(arg));
4774 if (IMAGE_INSTANCEP(value)) {
4775 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(value);
4777 if (COLOR_PIXMAP_IMAGE_INSTANCEP(value)
4779 IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii) > 1
4780 && !disable_animated_pixmaps) {
4782 /* Increment the index of the image slice we are
4783 currently viewing. */
4784 IMAGE_INSTANCE_PIXMAP_SLICE(ii) =
4785 (IMAGE_INSTANCE_PIXMAP_SLICE(ii) + 1)
4786 % IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii);
4787 /* We might need to kick redisplay at this point
4788 - but we also might not. */
4789 tmp = image_instance_device(value);
4790 MARK_DEVICE_FRAMES_GLYPHS_CHANGED(XDEVICE(tmp));
4791 /* Cascade dirtiness so that we can have an
4792 animated glyph in a layout for instance. */
4793 set_image_instance_dirty_p(value, 1);
4800 Lisp_Object add_glyph_animated_timeout(EMACS_INT tickms, Lisp_Object image)
4802 Lisp_Object ret = Qnil;
4804 if (tickms > 0 && IMAGE_INSTANCEP(image)) {
4805 double ms = ((double)tickms) / 1000.0;
4806 struct gcpro gcpro1;
4807 Lisp_Object holder = make_weak_list(WEAK_LIST_SIMPLE);
4810 XWEAK_LIST_LIST(holder) = Fcons(image, Qnil);
4812 ret = Fadd_timeout(make_float(ms),
4813 Qglyph_animated_timeout_handler,
4814 holder, make_float(ms));
4821 void disable_glyph_animated_timeout(int i)
4826 Fdisable_timeout(id);
4829 /*****************************************************************************
4831 *****************************************************************************/
4833 void syms_of_glyphs(void)
4835 INIT_LRECORD_IMPLEMENTATION(glyph);
4836 INIT_LRECORD_IMPLEMENTATION(image_instance);
4838 /* image instantiators */
4840 DEFSUBR(Fimage_instantiator_format_list);
4841 DEFSUBR(Fvalid_image_instantiator_format_p);
4842 DEFSUBR(Fset_console_type_image_conversion_list);
4843 DEFSUBR(Fconsole_type_image_conversion_list);
4846 DEFKEYWORD(Q_pixel_height);
4847 DEFKEYWORD(Q_pixel_width);
4850 DEFKEYWORD(Q_color_symbols);
4853 DEFKEYWORD(Q_mask_file);
4854 DEFKEYWORD(Q_mask_data);
4855 DEFKEYWORD(Q_hotspot_x);
4856 DEFKEYWORD(Q_hotspot_y);
4857 DEFKEYWORD(Q_foreground);
4858 DEFKEYWORD(Q_background);
4860 /* image specifiers */
4862 DEFSUBR(Fimage_specifier_p);
4863 /* Qimage in general.c */
4865 /* image instances */
4867 defsymbol(&Qimage_instancep, "image-instance-p");
4869 DEFSYMBOL(Qnothing_image_instance_p);
4870 DEFSYMBOL(Qtext_image_instance_p);
4871 DEFSYMBOL(Qmono_pixmap_image_instance_p);
4872 DEFSYMBOL(Qcolor_pixmap_image_instance_p);
4873 DEFSYMBOL(Qpointer_image_instance_p);
4874 DEFSYMBOL(Qwidget_image_instance_p);
4875 DEFSYMBOL(Qsubwindow_image_instance_p);
4877 DEFSUBR(Fmake_image_instance);
4878 DEFSUBR(Fimage_instance_p);
4879 DEFSUBR(Fimage_instance_type);
4880 DEFSUBR(Fvalid_image_instance_type_p);
4881 DEFSUBR(Fimage_instance_type_list);
4882 DEFSUBR(Fimage_instance_name);
4883 DEFSUBR(Fimage_instance_domain);
4884 DEFSUBR(Fimage_instance_string);
4885 DEFSUBR(Fimage_instance_file_name);
4886 DEFSUBR(Fimage_instance_mask_file_name);
4887 DEFSUBR(Fimage_instance_depth);
4888 DEFSUBR(Fimage_instance_height);
4889 DEFSUBR(Fimage_instance_width);
4890 DEFSUBR(Fimage_instance_hotspot_x);
4891 DEFSUBR(Fimage_instance_hotspot_y);
4892 DEFSUBR(Fimage_instance_foreground);
4893 DEFSUBR(Fimage_instance_background);
4894 DEFSUBR(Fimage_instance_property);
4895 DEFSUBR(Fcolorize_image_instance);
4897 DEFSUBR(Fsubwindowp);
4898 DEFSUBR(Fimage_instance_subwindow_id);
4899 DEFSUBR(Fresize_subwindow);
4900 DEFSUBR(Fforce_subwindow_map);
4902 /* Qnothing defined as part of the "nothing" image-instantiator
4904 /* Qtext defined in general.c */
4905 DEFSYMBOL(Qmono_pixmap);
4906 DEFSYMBOL(Qcolor_pixmap);
4907 /* Qpointer defined in general.c */
4912 DEFSYMBOL(Qcontrib_p);
4913 DEFSYMBOL(Qbaseline);
4915 DEFSYMBOL(Qbuffer_glyph_p);
4916 DEFSYMBOL(Qpointer_glyph_p);
4917 DEFSYMBOL(Qicon_glyph_p);
4919 DEFSYMBOL(Qconst_glyph_variable);
4921 DEFSUBR(Fglyph_type);
4922 DEFSUBR(Fvalid_glyph_type_p);
4923 DEFSUBR(Fglyph_type_list);
4925 DEFSUBR(Fmake_glyph_internal);
4926 DEFSUBR(Fglyph_width);
4927 DEFSUBR(Fglyph_ascent);
4928 DEFSUBR(Fglyph_descent);
4929 DEFSUBR(Fglyph_height);
4930 DEFSUBR(Fset_instantiator_property);
4932 /* Qbuffer defined in general.c. */
4933 /* Qpointer defined above */
4935 /* Unfortunately, timeout handlers must be lisp functions. This is
4936 for animated glyphs. */
4937 DEFSYMBOL(Qglyph_animated_timeout_handler);
4938 DEFSUBR(Fglyph_animated_timeout_handler);
4941 DEFERROR_STANDARD(Qimage_conversion_error, Qio_error);
4944 static const struct lrecord_description image_specifier_description[] = {
4946 specifier_data_offset + offsetof(struct image_specifier, attachee)},
4948 specifier_data_offset + offsetof(struct image_specifier,
4949 attachee_property)},
4953 void specifier_type_create_image(void)
4955 /* image specifiers */
4957 INITIALIZE_SPECIFIER_TYPE_WITH_DATA(image, "image", "imagep");
4959 SPECIFIER_HAS_METHOD(image, create);
4960 SPECIFIER_HAS_METHOD(image, mark);
4961 SPECIFIER_HAS_METHOD(image, instantiate);
4962 SPECIFIER_HAS_METHOD(image, validate);
4963 SPECIFIER_HAS_METHOD(image, after_change);
4964 SPECIFIER_HAS_METHOD(image, going_to_add);
4965 SPECIFIER_HAS_METHOD(image, copy_instantiator);
4968 void reinit_specifier_type_create_image(void)
4970 REINITIALIZE_SPECIFIER_TYPE(image);
4973 static const struct lrecord_description iike_description_1[] = {
4974 {XD_LISP_OBJECT, offsetof(ii_keyword_entry, keyword)},
4978 static const struct struct_description iike_description = {
4979 sizeof(ii_keyword_entry),
4983 static const struct lrecord_description iiked_description_1[] = {
4984 XD_DYNARR_DESC(ii_keyword_entry_dynarr, &iike_description),
4988 static const struct struct_description iiked_description = {
4989 sizeof(ii_keyword_entry_dynarr),
4993 static const struct lrecord_description iife_description_1[] = {
4994 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, symbol)},
4995 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, device)},
4996 {XD_STRUCT_PTR, offsetof(image_instantiator_format_entry, meths), 1,
5001 static const struct struct_description iife_description = {
5002 sizeof(image_instantiator_format_entry),
5006 static const struct lrecord_description iifed_description_1[] = {
5007 XD_DYNARR_DESC(image_instantiator_format_entry_dynarr,
5012 static const struct struct_description iifed_description = {
5013 sizeof(image_instantiator_format_entry_dynarr),
5017 static const struct lrecord_description iim_description_1[] = {
5018 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, symbol)},
5019 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, device)},
5020 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, keywords),
5021 1, &iiked_description},
5022 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, consoles),
5023 1, &cted_description},
5027 const struct struct_description iim_description = {
5028 sizeof(struct image_instantiator_methods),
5032 void image_instantiator_format_create(void)
5034 /* image instantiators */
5036 the_image_instantiator_format_entry_dynarr =
5037 Dynarr_new(image_instantiator_format_entry);
5039 Vimage_instantiator_format_list = Qnil;
5040 staticpro(&Vimage_instantiator_format_list);
5042 dump_add_root_struct_ptr(&the_image_instantiator_format_entry_dynarr,
5043 &iifed_description);
5045 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(nothing, "nothing");
5047 IIFORMAT_HAS_METHOD(nothing, possible_dest_types);
5048 IIFORMAT_HAS_METHOD(nothing, instantiate);
5050 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(inherit, "inherit");
5052 IIFORMAT_HAS_METHOD(inherit, validate);
5053 IIFORMAT_HAS_METHOD(inherit, normalize);
5054 IIFORMAT_HAS_METHOD(inherit, possible_dest_types);
5055 IIFORMAT_HAS_METHOD(inherit, instantiate);
5057 IIFORMAT_VALID_KEYWORD(inherit, Q_face, check_valid_face);
5059 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(string, "string");
5061 IIFORMAT_HAS_METHOD(string, validate);
5062 IIFORMAT_HAS_SHARED_METHOD(string, governing_domain, subwindow);
5063 IIFORMAT_HAS_METHOD(string, possible_dest_types);
5064 IIFORMAT_HAS_METHOD(string, instantiate);
5066 IIFORMAT_VALID_KEYWORD(string, Q_data, check_valid_string);
5067 /* Do this so we can set strings. */
5068 /* #### Andy, what is this? This is a bogus format and should not be
5069 visible to the user. */
5070 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(text, "text");
5071 IIFORMAT_HAS_METHOD(text, update);
5072 IIFORMAT_HAS_METHOD(text, query_geometry);
5074 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(formatted_string,
5075 "formatted-string");
5077 IIFORMAT_HAS_METHOD(formatted_string, validate);
5078 IIFORMAT_HAS_METHOD(formatted_string, possible_dest_types);
5079 IIFORMAT_HAS_METHOD(formatted_string, instantiate);
5080 IIFORMAT_VALID_KEYWORD(formatted_string, Q_data, check_valid_string);
5082 /* Do this so pointers have geometry. */
5083 /* #### Andy, what is this? This is a bogus format and should not be
5084 visible to the user. */
5085 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(pointer, "pointer");
5086 IIFORMAT_HAS_SHARED_METHOD(pointer, query_geometry, subwindow);
5089 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(subwindow, "subwindow");
5090 IIFORMAT_HAS_METHOD(subwindow, possible_dest_types);
5091 IIFORMAT_HAS_METHOD(subwindow, governing_domain);
5092 IIFORMAT_HAS_METHOD(subwindow, instantiate);
5093 IIFORMAT_HAS_METHOD(subwindow, query_geometry);
5094 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_width, check_valid_int);
5095 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_height, check_valid_int);
5097 #ifdef HAVE_WINDOW_SYSTEM
5098 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xbm, "xbm");
5100 IIFORMAT_HAS_METHOD(xbm, validate);
5101 IIFORMAT_HAS_METHOD(xbm, normalize);
5102 IIFORMAT_HAS_METHOD(xbm, possible_dest_types);
5104 IIFORMAT_VALID_KEYWORD(xbm, Q_data, check_valid_xbm_inline);
5105 IIFORMAT_VALID_KEYWORD(xbm, Q_file, check_valid_string);
5106 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_data, check_valid_xbm_inline);
5107 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_file, check_valid_string);
5108 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_x, check_valid_int);
5109 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_y, check_valid_int);
5110 IIFORMAT_VALID_KEYWORD(xbm, Q_foreground, check_valid_string);
5111 IIFORMAT_VALID_KEYWORD(xbm, Q_background, check_valid_string);
5112 #endif /* HAVE_WINDOW_SYSTEM */
5115 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xface, "xface");
5117 IIFORMAT_HAS_METHOD(xface, validate);
5118 IIFORMAT_HAS_METHOD(xface, normalize);
5119 IIFORMAT_HAS_METHOD(xface, possible_dest_types);
5121 IIFORMAT_VALID_KEYWORD(xface, Q_data, check_valid_string);
5122 IIFORMAT_VALID_KEYWORD(xface, Q_file, check_valid_string);
5123 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_x, check_valid_int);
5124 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_y, check_valid_int);
5125 IIFORMAT_VALID_KEYWORD(xface, Q_foreground, check_valid_string);
5126 IIFORMAT_VALID_KEYWORD(xface, Q_background, check_valid_string);
5130 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xpm, "xpm");
5132 IIFORMAT_HAS_METHOD(xpm, validate);
5133 IIFORMAT_HAS_METHOD(xpm, normalize);
5134 IIFORMAT_HAS_METHOD(xpm, possible_dest_types);
5136 IIFORMAT_VALID_KEYWORD(xpm, Q_data, check_valid_string);
5137 IIFORMAT_VALID_KEYWORD(xpm, Q_file, check_valid_string);
5138 IIFORMAT_VALID_KEYWORD(xpm, Q_color_symbols,
5139 check_valid_xpm_color_symbols);
5140 #endif /* HAVE_XPM */
5143 void reinit_vars_of_glyphs(void)
5145 the_expose_ignore_blocktype =
5146 Blocktype_new(struct expose_ignore_blocktype);
5148 hold_ignored_expose_registration = 0;
5151 void vars_of_glyphs(void)
5153 reinit_vars_of_glyphs();
5155 Vthe_nothing_vector = vector1(Qnothing);
5156 staticpro(&Vthe_nothing_vector);
5158 /* image instances */
5160 Vimage_instance_type_list = Fcons(Qnothing,
5161 list6(Qtext, Qmono_pixmap,
5162 Qcolor_pixmap, Qpointer,
5163 Qsubwindow, Qwidget));
5164 staticpro(&Vimage_instance_type_list);
5168 Vglyph_type_list = list3(Qbuffer, Qpointer, Qicon);
5169 staticpro(&Vglyph_type_list);
5171 /* The octal-escape glyph, control-arrow-glyph and
5172 invisible-text-glyph are completely initialized in glyphs.el */
5174 DEFVAR_LISP("octal-escape-glyph", &Voctal_escape_glyph /*
5175 What to prefix character codes displayed in octal with.
5177 Voctal_escape_glyph =
5178 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5180 DEFVAR_LISP("control-arrow-glyph", &Vcontrol_arrow_glyph /*
5181 What to use as an arrow for control characters.
5183 Vcontrol_arrow_glyph = allocate_glyph(GLYPH_BUFFER,
5184 redisplay_glyph_changed);
5186 DEFVAR_LISP("invisible-text-glyph", &Vinvisible_text_glyph /*
5187 What to use to indicate the presence of invisible text.
5188 This is the glyph that is displayed when an ellipsis is called for
5189 \(see `selective-display-ellipses' and `buffer-invisibility-spec').
5190 Normally this is three dots ("...").
5192 Vinvisible_text_glyph = allocate_glyph(GLYPH_BUFFER,
5193 redisplay_glyph_changed);
5195 /* Partially initialized in glyphs.el */
5196 DEFVAR_LISP("hscroll-glyph", &Vhscroll_glyph /*
5197 What to display at the beginning of horizontally scrolled lines.
5199 Vhscroll_glyph = allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5200 #ifdef HAVE_WINDOW_SYSTEM
5206 DEFVAR_LISP("xpm-color-symbols", &Vxpm_color_symbols /*
5207 Definitions of logical color-names used when reading XPM files.
5208 Elements of this list should be of the form (COLOR-NAME FORM-TO-EVALUATE).
5209 The COLOR-NAME should be a string, which is the name of the color to define;
5210 the FORM should evaluate to a `color' specifier object, or a string to be
5211 passed to `make-color-instance'. If a loaded XPM file references a symbolic
5212 color called COLOR-NAME, it will display as the computed color instead.
5214 The default value of this variable defines the logical color names
5215 \"foreground\" and \"background\" to be the colors of the `default' face.
5217 Vxpm_color_symbols = Qnil; /* initialized in x-faces.el */
5218 #endif /* HAVE_XPM */
5223 DEFVAR_BOOL("disable-animated-pixmaps", &disable_animated_pixmaps /*
5224 Whether animated pixmaps should be animated.
5227 disable_animated_pixmaps = 0;
5230 void specifier_vars_of_glyphs(void)
5232 /* #### Can we GC here? The set_specifier_* calls definitely need */
5234 /* display tables */
5236 DEFVAR_SPECIFIER("current-display-table", &Vcurrent_display_table /*
5237 *The display table currently in use.
5238 This is a specifier; use `set-specifier' to change it.
5240 Display tables are used to control how characters are displayed. Each
5241 time that redisplay processes a character, it is looked up in all the
5242 display tables that apply (obtained by calling `specifier-instance' on
5243 `current-display-table' and any overriding display tables specified in
5244 currently active faces). The first entry found that matches the
5245 character determines how the character is displayed. If there is no
5246 matching entry, the default display method is used. (Non-control
5247 characters are displayed as themselves and control characters are
5248 displayed according to the buffer-local variable `ctl-arrow'. Control
5249 characters are further affected by `control-arrow-glyph' and
5250 `octal-escape-glyph'.)
5252 Each instantiator in this specifier and the display-table specifiers
5253 in faces is a display table or a list of such tables. If a list, each
5254 table will be searched in turn for an entry matching a particular
5255 character. Each display table is one of
5257 -- a vector, specifying values for characters starting at 0
5258 -- a char table, either of type `char' or `generic'
5261 Each entry in a display table should be one of
5263 -- nil (this entry is ignored and the search continues)
5264 -- a character (use this character; if it happens to be the same as
5265 the original character, default processing happens, otherwise
5266 redisplay attempts to display this character directly;
5267 #### At some point recursive display-table lookup will be
5269 -- a string (display each character in the string directly;
5270 #### At some point recursive display-table lookup will be
5272 -- a glyph (display the glyph;
5273 #### At some point recursive display-table lookup will be
5274 implemented when a string glyph is being processed.)
5275 -- a cons of the form (format "STRING") where STRING is a printf-like
5276 spec used to process the character. #### Unfortunately no
5277 formatting directives other than %% are implemented.
5278 -- a vector (each element of the vector is processed recursively;
5279 in such a case, nil elements in the vector are simply ignored)
5281 #### At some point in the near future, display tables are likely to
5282 be expanded to include other features, such as referencing characters
5283 in particular fonts and allowing the character search to continue
5284 all the way up the chain of specifier instantiators. These features
5285 are necessary to properly display Unicode characters.
5287 Vcurrent_display_table = Fmake_specifier(Qdisplay_table);
5288 set_specifier_fallback(Vcurrent_display_table,
5289 list1(Fcons(Qnil, Qnil)));
5290 set_specifier_caching(Vcurrent_display_table,
5291 offsetof(struct window, display_table),
5292 some_window_value_changed, 0, 0, 0);
5295 void complex_vars_of_glyphs(void)
5297 /* Partially initialized in glyphs-x.c, glyphs.el */
5298 DEFVAR_LISP("truncation-glyph", &Vtruncation_glyph /*
5299 What to display at the end of truncated lines.
5302 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5304 /* Partially initialized in glyphs-x.c, glyphs.el */
5305 DEFVAR_LISP("continuation-glyph", &Vcontinuation_glyph /*
5306 What to display at the end of wrapped lines.
5308 Vcontinuation_glyph =
5309 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5311 /* Partially initialized in glyphs-x.c, glyphs.el */
5312 DEFVAR_LISP("sxemacs-logo", &Vsxemacs_logo /*
5313 The glyph used to display the SXEmacs logo at startup.
5315 Vsxemacs_logo = allocate_glyph(GLYPH_BUFFER, 0);