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"
48 #if defined (HAVE_XPM) && !defined (HAVE_GTK)
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)
885 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(obj);
888 error("printing unreadable object #<image-instance 0x%x>",
890 write_c_string("#<image-instance (", printcharfun);
891 print_internal(Fimage_instance_type(obj), printcharfun, 0);
892 write_c_string(") ", printcharfun);
893 if (!NILP(ii->name)) {
894 print_internal(ii->name, printcharfun, 1);
895 write_c_string(" ", printcharfun);
897 write_c_string("on ", printcharfun);
898 print_internal(ii->domain, printcharfun, 0);
899 write_c_string(" ", printcharfun);
900 switch (IMAGE_INSTANCE_TYPE(ii)) {
905 print_internal(IMAGE_INSTANCE_TEXT_STRING(ii), printcharfun, 1);
908 case IMAGE_MONO_PIXMAP:
909 case IMAGE_COLOR_PIXMAP:
911 if (STRINGP(IMAGE_INSTANCE_PIXMAP_FILENAME(ii))) {
913 Lisp_Object filename =
914 IMAGE_INSTANCE_PIXMAP_FILENAME(ii);
915 s = strrchr((char *)XSTRING_DATA(filename), '/');
917 print_internal(build_string(s + 1),
920 print_internal(filename, printcharfun, 1);
922 if (IMAGE_INSTANCE_PIXMAP_DEPTH(ii) > 1)
923 sprintf(buf, " %dx%dx%d",
924 IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
925 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii),
926 IMAGE_INSTANCE_PIXMAP_DEPTH(ii));
928 sprintf(buf, " %dx%d", IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
929 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii));
930 write_c_string(buf, printcharfun);
931 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) ||
932 !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
933 write_c_string(" @", printcharfun);
934 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii))) {
937 (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X
939 write_c_string(buf, printcharfun);
941 write_c_string("??", printcharfun);
942 write_c_string(",", printcharfun);
943 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
946 (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y
948 write_c_string(buf, printcharfun);
950 write_c_string("??", printcharfun);
952 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii)) ||
953 !NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
954 write_c_string(" (", printcharfun);
955 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii))) {
958 (IMAGE_INSTANCE_PIXMAP_FG(ii))->name,
961 write_c_string("/", printcharfun);
962 if (!NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
965 (IMAGE_INSTANCE_PIXMAP_BG(ii))->name,
968 write_c_string(")", printcharfun);
973 print_internal(IMAGE_INSTANCE_WIDGET_TYPE(ii), printcharfun, 0);
975 if (GUI_ITEMP(IMAGE_INSTANCE_WIDGET_ITEM(ii))) {
976 write_c_string(" ", printcharfun);
977 print_internal(IMAGE_INSTANCE_WIDGET_TEXT(ii),
981 if (!NILP(IMAGE_INSTANCE_WIDGET_FACE(ii))) {
982 write_c_string(" face=", printcharfun);
984 (IMAGE_INSTANCE_WIDGET_FACE(ii), printcharfun, 0);
988 case IMAGE_SUBWINDOW:
989 sprintf(buf, " %dx%d", IMAGE_INSTANCE_WIDTH(ii),
990 IMAGE_INSTANCE_HEIGHT(ii));
991 write_c_string(buf, printcharfun);
993 /* This is stolen from frame.c. Subwindows are strange in that they
994 are specific to a particular frame so we want to print in their
995 description what that frame is. */
997 write_c_string(" on #<", printcharfun);
999 struct frame *f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
1001 if (!FRAME_LIVE_P(f))
1002 write_c_string("dead", printcharfun);
1004 write_c_string(DEVICE_TYPE_NAME
1005 (XDEVICE(FRAME_DEVICE(f))),
1008 write_c_string("-frame>", printcharfun);
1009 sprintf(buf, " 0x%p", IMAGE_INSTANCE_SUBWINDOW_ID(ii));
1010 write_c_string(buf, printcharfun);
1019 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain), print_image_instance,
1020 (ii, printcharfun, escapeflag));
1021 sprintf(buf, " 0x%x>", ii->header.uid);
1022 write_c_string(buf, printcharfun);
1025 static void finalize_image_instance(void *header, int for_disksave)
1027 Lisp_Image_Instance *i = (Lisp_Image_Instance *) header;
1029 /* objects like this exist at dump time, so don't bomb out. */
1030 if (IMAGE_INSTANCE_TYPE(i) == IMAGE_NOTHING
1031 || NILP(IMAGE_INSTANCE_DEVICE(i)))
1036 /* We can't use the domain here, because it might have
1038 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(i)),
1039 finalize_image_instance, (i));
1041 /* Make sure we don't try this twice. */
1042 IMAGE_INSTANCE_DEVICE(i) = Qnil;
1045 static int image_instance_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
1047 Lisp_Image_Instance *i1 = XIMAGE_INSTANCE(obj1);
1048 Lisp_Image_Instance *i2 = XIMAGE_INSTANCE(obj2);
1050 ERROR_CHECK_IMAGE_INSTANCE(obj1);
1051 ERROR_CHECK_IMAGE_INSTANCE(obj2);
1053 if (!EQ(IMAGE_INSTANCE_DOMAIN(i1), IMAGE_INSTANCE_DOMAIN(i2))
1054 || IMAGE_INSTANCE_TYPE(i1) != IMAGE_INSTANCE_TYPE(i2)
1055 || IMAGE_INSTANCE_WIDTH(i1) != IMAGE_INSTANCE_WIDTH(i2)
1056 || IMAGE_INSTANCE_MARGIN_WIDTH(i1) !=
1057 IMAGE_INSTANCE_MARGIN_WIDTH(i2)
1058 || IMAGE_INSTANCE_HEIGHT(i1) != IMAGE_INSTANCE_HEIGHT(i2)
1059 || IMAGE_INSTANCE_XOFFSET(i1) != IMAGE_INSTANCE_XOFFSET(i2)
1060 || IMAGE_INSTANCE_YOFFSET(i1) != IMAGE_INSTANCE_YOFFSET(i2))
1062 if (!internal_equal(IMAGE_INSTANCE_NAME(i1), IMAGE_INSTANCE_NAME(i2),
1065 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(i1),
1066 IMAGE_INSTANCE_INSTANTIATOR(i2), depth + 1))
1069 switch (IMAGE_INSTANCE_TYPE(i1)) {
1074 if (!internal_equal(IMAGE_INSTANCE_TEXT_STRING(i1),
1075 IMAGE_INSTANCE_TEXT_STRING(i2), depth + 1))
1079 case IMAGE_MONO_PIXMAP:
1080 case IMAGE_COLOR_PIXMAP:
1082 if (!(IMAGE_INSTANCE_PIXMAP_DEPTH(i1) ==
1083 IMAGE_INSTANCE_PIXMAP_DEPTH(i2) &&
1084 IMAGE_INSTANCE_PIXMAP_SLICE(i1) ==
1085 IMAGE_INSTANCE_PIXMAP_SLICE(i2) &&
1086 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i1),
1087 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i2)) &&
1088 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i1),
1089 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i2)) &&
1090 internal_equal(IMAGE_INSTANCE_PIXMAP_FILENAME(i1),
1091 IMAGE_INSTANCE_PIXMAP_FILENAME(i2),
1093 internal_equal(IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i1),
1094 IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i2),
1100 if (!(EQ(IMAGE_INSTANCE_WIDGET_TYPE(i1),
1101 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1102 && IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1103 IMAGE_INSTANCE_SUBWINDOW_ID(i2)
1105 EQ(IMAGE_INSTANCE_WIDGET_FACE(i1),
1106 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1107 && internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(i1),
1108 IMAGE_INSTANCE_WIDGET_ITEMS(i2),
1110 && internal_equal(IMAGE_INSTANCE_LAYOUT_CHILDREN(i1),
1111 IMAGE_INSTANCE_LAYOUT_CHILDREN(i2),
1113 && internal_equal(IMAGE_INSTANCE_WIDGET_PROPS(i1),
1114 IMAGE_INSTANCE_WIDGET_PROPS(i2),
1116 && internal_equal(IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i1),
1117 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i2),
1119 && internal_equal(IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i1),
1120 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i2),
1126 case IMAGE_SUBWINDOW:
1127 if (!(IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1128 IMAGE_INSTANCE_SUBWINDOW_ID(i2)))
1137 return DEVMETH_OR_GIVEN(DOMAIN_XDEVICE(i1->domain),
1138 image_instance_equal, (i1, i2, depth), 1);
1141 /* Image instance domain manipulators. We can't error check in these
1142 otherwise we get into infinite recursion. */
1143 Lisp_Object image_instance_device(Lisp_Object instance)
1145 return XIMAGE_INSTANCE_DEVICE(instance);
1148 Lisp_Object image_instance_frame(Lisp_Object instance)
1150 return XIMAGE_INSTANCE_FRAME(instance);
1153 Lisp_Object image_instance_window(Lisp_Object instance)
1155 return DOMAIN_WINDOW(XIMAGE_INSTANCE_DOMAIN(instance));
1158 int image_instance_live_p(Lisp_Object instance)
1160 return DOMAIN_LIVE_P(XIMAGE_INSTANCE_DOMAIN(instance));
1163 static unsigned long image_instance_hash(Lisp_Object obj, int depth)
1165 Lisp_Image_Instance *i = XIMAGE_INSTANCE(obj);
1166 unsigned long hash = HASH5(LISP_HASH(IMAGE_INSTANCE_DOMAIN(i)),
1167 IMAGE_INSTANCE_WIDTH(i),
1168 IMAGE_INSTANCE_MARGIN_WIDTH(i),
1169 IMAGE_INSTANCE_HEIGHT(i),
1170 internal_hash(IMAGE_INSTANCE_INSTANTIATOR(i),
1173 ERROR_CHECK_IMAGE_INSTANCE(obj);
1175 switch (IMAGE_INSTANCE_TYPE(i)) {
1180 hash = HASH2(hash, internal_hash(IMAGE_INSTANCE_TEXT_STRING(i),
1184 case IMAGE_MONO_PIXMAP:
1185 case IMAGE_COLOR_PIXMAP:
1187 hash = HASH4(hash, IMAGE_INSTANCE_PIXMAP_DEPTH(i),
1188 IMAGE_INSTANCE_PIXMAP_SLICE(i),
1189 internal_hash(IMAGE_INSTANCE_PIXMAP_FILENAME(i),
1194 /* We need the hash to be equivalent to what should be
1197 LISP_HASH(IMAGE_INSTANCE_WIDGET_TYPE(i)),
1198 internal_hash(IMAGE_INSTANCE_WIDGET_PROPS(i),
1200 internal_hash(IMAGE_INSTANCE_WIDGET_ITEMS(i),
1202 internal_hash(IMAGE_INSTANCE_LAYOUT_CHILDREN(i),
1204 case IMAGE_SUBWINDOW:
1205 hash = HASH2(hash, (EMACS_INT) IMAGE_INSTANCE_SUBWINDOW_ID(i));
1214 Lisp_Object tmp = image_instance_device(obj);
1215 return HASH2(hash, DEVMETH_OR_GIVEN(
1216 XDEVICE(tmp), image_instance_hash,
1221 DEFINE_LRECORD_IMPLEMENTATION("image-instance", image_instance,
1222 mark_image_instance, print_image_instance,
1223 finalize_image_instance, image_instance_equal,
1224 image_instance_hash, 0, Lisp_Image_Instance);
1227 allocate_image_instance(Lisp_Object governing_domain, Lisp_Object parent,
1228 Lisp_Object instantiator)
1230 Lisp_Image_Instance *lp =
1231 alloc_lcrecord_type(Lisp_Image_Instance, &lrecord_image_instance);
1235 /* It's not possible to simply keep a record of the domain in which
1236 the instance was instantiated. This is because caching may mean
1237 that the domain becomes invalid but the instance remains
1238 valid. However, the only truly relevant domain is the domain in
1239 which the instance is cached since this is the one that will be
1240 common to the instances. */
1241 lp->domain = governing_domain;
1242 /* The cache domain is not quite sufficient since the domain can get
1243 deleted before the image instance does. We need to know the
1244 domain device in order to finalize the image instance
1245 properly. We therefore record the device also. */
1246 lp->device = DOMAIN_DEVICE(governing_domain);
1247 lp->type = IMAGE_NOTHING;
1251 lp->width = IMAGE_UNSPECIFIED_GEOMETRY;
1252 lp->margin_width = 0;
1253 lp->height = IMAGE_UNSPECIFIED_GEOMETRY;
1254 lp->parent = parent;
1255 lp->instantiator = instantiator;
1256 /* So that layouts get done. */
1257 lp->layout_changed = 1;
1258 lp->initialized = 0;
1260 XSETIMAGE_INSTANCE(val, lp);
1261 MARK_GLYPHS_CHANGED;
1266 static enum image_instance_type
1267 decode_image_instance_type(Lisp_Object type, Error_behavior errb)
1269 if (ERRB_EQ(errb, ERROR_ME))
1272 if (EQ(type, Qnothing))
1273 return IMAGE_NOTHING;
1274 if (EQ(type, Qtext))
1276 if (EQ(type, Qmono_pixmap))
1277 return IMAGE_MONO_PIXMAP;
1278 if (EQ(type, Qcolor_pixmap))
1279 return IMAGE_COLOR_PIXMAP;
1280 if (EQ(type, Qpointer))
1281 return IMAGE_POINTER;
1282 if (EQ(type, Qsubwindow))
1283 return IMAGE_SUBWINDOW;
1284 if (EQ(type, Qwidget))
1285 return IMAGE_WIDGET;
1287 maybe_signal_simple_error("Invalid image-instance type", type,
1290 return IMAGE_UNKNOWN; /* not reached */
1293 static Lisp_Object encode_image_instance_type(enum image_instance_type type)
1300 case IMAGE_MONO_PIXMAP:
1301 return Qmono_pixmap;
1302 case IMAGE_COLOR_PIXMAP:
1303 return Qcolor_pixmap;
1306 case IMAGE_SUBWINDOW:
1316 return Qnil; /* not reached */
1319 static int decode_image_instance_type_list(Lisp_Object list)
1328 enum image_instance_type type =
1329 decode_image_instance_type(list, ERROR_ME);
1330 return image_instance_type_to_mask(type);
1333 EXTERNAL_LIST_LOOP(rest, list) {
1334 enum image_instance_type type =
1335 decode_image_instance_type(XCAR(rest), ERROR_ME);
1336 mask |= image_instance_type_to_mask(type);
1342 static Lisp_Object encode_image_instance_type_list(int mask)
1345 Lisp_Object result = Qnil;
1350 result = Fcons(encode_image_instance_type
1351 ((enum image_instance_type)count),
1356 return Fnreverse(result);
1360 incompatible_image_types(Lisp_Object instantiator, int given_dest_mask,
1361 int desired_dest_mask)
1363 signal_error(Qerror, list2(emacs_doprnt_string_lisp_2((const Bufbyte *)
1364 "No compatible image-instance types given: wanted one of %s, got %s",
1366 encode_image_instance_type_list
1367 (desired_dest_mask),
1368 encode_image_instance_type_list
1373 static int valid_image_instance_type_p(Lisp_Object type)
1375 return !NILP(memq_no_quit(type, Vimage_instance_type_list));
1378 DEFUN("valid-image-instance-type-p", Fvalid_image_instance_type_p, 1, 1, 0, /*
1379 Given an IMAGE-INSTANCE-TYPE, return non-nil if it is valid.
1380 Valid types are some subset of 'nothing, 'text, 'mono-pixmap, 'color-pixmap,
1381 'pointer, 'subwindow, and 'widget, depending on how SXEmacs was compiled.
1383 (image_instance_type))
1385 return valid_image_instance_type_p(image_instance_type) ? Qt : Qnil;
1388 DEFUN("image-instance-type-list", Fimage_instance_type_list, 0, 0, 0, /*
1389 Return a list of valid image-instance types.
1393 return Fcopy_sequence(Vimage_instance_type_list);
1396 Error_behavior decode_error_behavior_flag(Lisp_Object noerror)
1400 else if (EQ(noerror, Qt))
1401 return ERROR_ME_NOT;
1403 return ERROR_ME_WARN;
1406 Lisp_Object encode_error_behavior_flag(Error_behavior errb)
1408 if (ERRB_EQ(errb, ERROR_ME))
1410 else if (ERRB_EQ(errb, ERROR_ME_NOT))
1413 assert(ERRB_EQ(errb, ERROR_ME_WARN));
1418 /* Recurse up the hierarchy looking for the topmost glyph. This means
1419 that instances in layouts will inherit face properties from their
1421 Lisp_Object image_instance_parent_glyph(Lisp_Image_Instance * ii)
1423 if (IMAGE_INSTANCEP(IMAGE_INSTANCE_PARENT(ii))) {
1424 return image_instance_parent_glyph
1425 (XIMAGE_INSTANCE(IMAGE_INSTANCE_PARENT(ii)));
1427 return IMAGE_INSTANCE_PARENT(ii);
1431 make_image_instance_1(Lisp_Object data, Lisp_Object domain,
1432 Lisp_Object dest_types)
1435 struct gcpro gcpro1;
1437 Lisp_Object governing_domain;
1439 if (IMAGE_INSTANCEP(data))
1440 signal_simple_error("Image instances not allowed here", data);
1441 image_validate(data);
1442 domain = decode_domain(domain);
1443 /* instantiate_image_instantiator() will abort if given an
1444 image instance ... */
1445 dest_mask = decode_image_instance_type_list(dest_types);
1446 data = normalize_image_instantiator(data,
1447 DEVICE_TYPE(DOMAIN_XDEVICE(domain)),
1448 make_int(dest_mask));
1450 /* After normalizing the data, it's always either an image instance (which
1451 we filtered out above) or a vector. */
1452 if (EQ(INSTANTIATOR_TYPE(data), Qinherit))
1453 signal_simple_error("Inheritance not allowed here", data);
1455 get_image_instantiator_governing_domain(data, domain);
1456 ii = instantiate_image_instantiator(governing_domain, domain, data,
1457 Qnil, Qnil, dest_mask, Qnil);
1461 DEFUN("make-image-instance", Fmake_image_instance, 1, 4, 0, /*
1462 Return a new `image-instance' object.
1464 Image-instance objects encapsulate the way a particular image (pixmap,
1465 etc.) is displayed on a particular device. In most circumstances, you
1466 do not need to directly create image instances; use a glyph instead.
1467 However, it may occasionally be useful to explicitly create image
1468 instances, if you want more control over the instantiation process.
1470 DATA is an image instantiator, which describes the image; see
1471 `make-image-specifier' for a description of the allowed values.
1473 DEST-TYPES should be a list of allowed image instance types that can
1474 be generated. The recognized image instance types are
1477 Nothing is displayed.
1479 Displayed as text. The foreground and background colors and the
1480 font of the text are specified independent of the pixmap. Typically
1481 these attributes will come from the face of the surrounding text,
1482 unless a face is specified for the glyph in which the image appears.
1484 Displayed as a mono pixmap (a pixmap with only two colors where the
1485 foreground and background can be specified independent of the pixmap;
1486 typically the pixmap assumes the foreground and background colors of
1487 the text around it, unless a face is specified for the glyph in which
1490 Displayed as a color pixmap.
1492 Used as the mouse pointer for a window.
1494 A child window that is treated as an image. This allows (e.g.)
1495 another program to be responsible for drawing into the window.
1497 A child window that contains a window-system widget, e.g. a push
1498 button, text field, or slider.
1500 The DEST-TYPES list is unordered. If multiple destination types are
1501 possible for a given instantiator, the "most natural" type for the
1502 instantiator's format is chosen. (For XBM, the most natural types are
1503 `mono-pixmap', followed by `color-pixmap', followed by `pointer'. For
1504 the other normal image formats, the most natural types are
1505 `color-pixmap', followed by `mono-pixmap', followed by `pointer'. For
1506 the string and formatted-string formats, the most natural types are
1507 `text', followed by `mono-pixmap' (not currently implemented),
1508 followed by `color-pixmap' (not currently implemented). For MS
1509 Windows resources, the most natural type for pointer resources is
1510 `pointer', and for the others it's `color-pixmap'. The other formats
1511 can only be instantiated as one type. (If you want to control more
1512 specifically the order of the types into which an image is
1513 instantiated, just call `make-image-instance' repeatedly until it
1514 succeeds, passing less and less preferred destination types each
1517 See `make-image-specifier' for a description of the different image
1518 instantiator formats.
1520 If DEST-TYPES is omitted, all possible types are allowed.
1522 DOMAIN specifies the domain to which the image instance will be attached.
1523 This domain is termed the \"governing domain\". The type of the governing
1524 domain depends on the image instantiator format. (Although, more correctly,
1525 it should probably depend on the image instance type.) For example, pixmap
1526 image instances are specific to a device, but widget image instances are
1527 specific to a particular SXEmacs window because in order to display such a
1528 widget when two windows onto the same buffer want to display the widget,
1529 two separate underlying widgets must be created. (That's because a widget
1530 is actually a child window-system window, and all window-system windows have
1531 a unique existence on the screen.) This means that the governing domain for
1532 a pixmap image instance will be some device (most likely, the only existing
1533 device), whereas the governing domain for a widget image instance will be
1534 some SXEmacs window.
1536 If you specify an overly general DOMAIN (e.g. a frame when a window was
1537 wanted), an error is signaled. If you specify an overly specific DOMAIN
1538 \(e.g. a window when a device was wanted), the corresponding general domain
1539 is fetched and used instead. For `make-image-instance', it makes no
1540 difference whether you specify an overly specific domain or the properly
1541 general domain derived from it. However, it does matter when creating an
1542 image instance by instantiating a specifier or glyph (e.g. with
1543 `glyph-image-instance'), because the more specific domain causes spec lookup
1544 to start there and proceed to more general domains. (It would also matter
1545 when creating an image instance with an instantiator format of `inherit',
1546 but we currently disallow this. #### We should fix this.)
1548 If omitted, DOMAIN defaults to the selected window.
1550 NOERROR controls what happens when the image cannot be generated.
1551 If nil, an error message is generated. If t, no messages are
1552 generated and this function returns nil. If anything else, a warning
1553 message is generated and this function returns nil.
1555 (data, domain, dest_types, noerror))
1557 Error_behavior errb = decode_error_behavior_flag(noerror);
1559 return call_with_suspended_errors((lisp_fn_t) make_image_instance_1,
1561 3, data, domain, dest_types);
1564 DEFUN("image-instance-p", Fimage_instance_p, 1, 1, 0, /*
1565 Return non-nil if OBJECT is an image instance.
1569 return IMAGE_INSTANCEP(object) ? Qt : Qnil;
1572 DEFUN("image-instance-type", Fimage_instance_type, 1, 1, 0, /*
1573 Return the type of the given image instance.
1574 The return value will be one of 'nothing, 'text, 'mono-pixmap,
1575 'color-pixmap, 'pointer, or 'subwindow.
1579 CHECK_IMAGE_INSTANCE(image_instance);
1580 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1581 return encode_image_instance_type(XIMAGE_INSTANCE_TYPE(image_instance));
1584 DEFUN("image-instance-name", Fimage_instance_name, 1, 1, 0, /*
1585 Return the name of the given image instance.
1589 CHECK_IMAGE_INSTANCE(image_instance);
1590 return XIMAGE_INSTANCE_NAME(image_instance);
1593 DEFUN("image-instance-domain", Fimage_instance_domain, 1, 1, 0, /*
1594 Return the governing domain of the given image instance.
1595 The governing domain of an image instance is the domain that the image
1596 instance is specific to. It is NOT necessarily the domain that was
1597 given to the call to `specifier-instance' that resulted in the creation
1598 of this image instance. See `make-image-instance' for more information
1599 on governing domains.
1603 CHECK_IMAGE_INSTANCE(image_instance);
1604 return XIMAGE_INSTANCE_DOMAIN(image_instance);
1607 DEFUN("image-instance-string", Fimage_instance_string, 1, 1, 0, /*
1608 Return the string of the given image instance.
1609 This will only be non-nil for text image instances and widgets.
1613 CHECK_IMAGE_INSTANCE(image_instance);
1614 if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_TEXT)
1615 return XIMAGE_INSTANCE_TEXT_STRING(image_instance);
1616 else if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_WIDGET)
1617 return XIMAGE_INSTANCE_WIDGET_TEXT(image_instance);
1622 DEFUN("image-instance-property", Fimage_instance_property, 2, 2, 0, /*
1623 Return the given property of the given image instance.
1624 Returns nil if the property or the property method do not exist for
1625 the image instance in the domain.
1627 (image_instance, prop))
1629 Lisp_Image_Instance *ii;
1630 Lisp_Object type, ret;
1631 struct image_instantiator_methods *meths;
1633 CHECK_IMAGE_INSTANCE(image_instance);
1634 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1636 ii = XIMAGE_INSTANCE(image_instance);
1638 /* ... then try device specific methods ... */
1639 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1640 meths = decode_device_ii_format(image_instance_device(image_instance),
1641 type, ERROR_ME_NOT);
1642 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1645 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1648 /* ... then format specific methods ... */
1649 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1650 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1653 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1660 DEFUN("image-instance-file-name", Fimage_instance_file_name, 1, 1, 0, /*
1661 Return the file name from which IMAGE-INSTANCE was read, if known.
1665 CHECK_IMAGE_INSTANCE(image_instance);
1666 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1668 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1669 case IMAGE_MONO_PIXMAP:
1670 case IMAGE_COLOR_PIXMAP:
1672 return XIMAGE_INSTANCE_PIXMAP_FILENAME(image_instance);
1677 case IMAGE_SUBWINDOW:
1684 DEFUN("image-instance-mask-file-name", Fimage_instance_mask_file_name, 1, 1, 0, /*
1685 Return the file name from which IMAGE-INSTANCE's mask was read, if known.
1689 CHECK_IMAGE_INSTANCE(image_instance);
1690 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1692 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1693 case IMAGE_MONO_PIXMAP:
1694 case IMAGE_COLOR_PIXMAP:
1696 return XIMAGE_INSTANCE_PIXMAP_MASK_FILENAME(image_instance);
1701 case IMAGE_SUBWINDOW:
1708 DEFUN("image-instance-depth", Fimage_instance_depth, 1, 1, 0, /*
1709 Return the depth of the image instance.
1710 This is 0 for a bitmap, or a positive integer for a pixmap.
1714 CHECK_IMAGE_INSTANCE(image_instance);
1715 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1717 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1718 case IMAGE_MONO_PIXMAP:
1719 case IMAGE_COLOR_PIXMAP:
1721 return make_int(XIMAGE_INSTANCE_PIXMAP_DEPTH(image_instance));
1726 case IMAGE_SUBWINDOW:
1733 DEFUN("image-instance-height", Fimage_instance_height, 1, 1, 0, /*
1734 Return the height of the image instance, in pixels.
1738 CHECK_IMAGE_INSTANCE(image_instance);
1739 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1741 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1742 case IMAGE_MONO_PIXMAP:
1743 case IMAGE_COLOR_PIXMAP:
1745 case IMAGE_SUBWINDOW:
1747 return make_int(XIMAGE_INSTANCE_HEIGHT(image_instance));
1757 DEFUN("image-instance-width", Fimage_instance_width, 1, 1, 0, /*
1758 Return the width of the image instance, in pixels.
1762 CHECK_IMAGE_INSTANCE(image_instance);
1763 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1765 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1766 case IMAGE_MONO_PIXMAP:
1767 case IMAGE_COLOR_PIXMAP:
1769 case IMAGE_SUBWINDOW:
1771 return make_int(XIMAGE_INSTANCE_WIDTH(image_instance));
1781 DEFUN("image-instance-hotspot-x", Fimage_instance_hotspot_x, 1, 1, 0, /*
1782 Return the X coordinate of the image instance's hotspot, if known.
1783 This is a point relative to the origin of the pixmap. When an image is
1784 used as a mouse pointer, the hotspot is the point on the image that sits
1785 over the location that the pointer points to. This is, for example, the
1786 tip of the arrow or the center of the crosshairs.
1787 This will always be nil for a non-pointer image instance.
1791 CHECK_IMAGE_INSTANCE(image_instance);
1792 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1794 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1795 case IMAGE_MONO_PIXMAP:
1796 case IMAGE_COLOR_PIXMAP:
1798 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_X(image_instance);
1803 case IMAGE_SUBWINDOW:
1810 DEFUN("image-instance-hotspot-y", Fimage_instance_hotspot_y, 1, 1, 0, /*
1811 Return the Y coordinate of the image instance's hotspot, if known.
1812 This is a point relative to the origin of the pixmap. When an image is
1813 used as a mouse pointer, the hotspot is the point on the image that sits
1814 over the location that the pointer points to. This is, for example, the
1815 tip of the arrow or the center of the crosshairs.
1816 This will always be nil for a non-pointer image instance.
1820 CHECK_IMAGE_INSTANCE(image_instance);
1821 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1823 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1824 case IMAGE_MONO_PIXMAP:
1825 case IMAGE_COLOR_PIXMAP:
1827 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(image_instance);
1832 case IMAGE_SUBWINDOW:
1839 DEFUN("image-instance-foreground", Fimage_instance_foreground, 1, 1, 0, /*
1840 Return the foreground color of IMAGE-INSTANCE, if applicable.
1841 This will be a color instance or nil. (It will only be non-nil for
1842 colorized mono pixmaps and for pointers.)
1846 CHECK_IMAGE_INSTANCE(image_instance);
1847 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1849 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1850 case IMAGE_MONO_PIXMAP:
1851 case IMAGE_COLOR_PIXMAP:
1853 return XIMAGE_INSTANCE_PIXMAP_FG(image_instance);
1857 FACE_FOREGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1858 XIMAGE_INSTANCE_FRAME(image_instance));
1863 case IMAGE_SUBWINDOW:
1869 DEFUN("image-instance-background", Fimage_instance_background, 1, 1, 0, /*
1870 Return the background color of IMAGE-INSTANCE, if applicable.
1871 This will be a color instance or nil. (It will only be non-nil for
1872 colorized mono pixmaps and for pointers.)
1876 CHECK_IMAGE_INSTANCE(image_instance);
1877 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1879 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1880 case IMAGE_MONO_PIXMAP:
1881 case IMAGE_COLOR_PIXMAP:
1883 return XIMAGE_INSTANCE_PIXMAP_BG(image_instance);
1887 FACE_BACKGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1888 XIMAGE_INSTANCE_FRAME(image_instance));
1893 case IMAGE_SUBWINDOW:
1899 DEFUN("colorize-image-instance", Fcolorize_image_instance, 3, 3, 0, /*
1900 Make the image instance be displayed in the given colors.
1901 This function returns a new image instance that is exactly like the
1902 specified one except that (if possible) the foreground and background
1903 colors and as specified. Currently, this only does anything if the image
1904 instance is a mono pixmap; otherwise, the same image instance is returned.
1906 (image_instance, foreground, background))
1911 CHECK_IMAGE_INSTANCE(image_instance);
1912 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1913 CHECK_COLOR_INSTANCE(foreground);
1914 CHECK_COLOR_INSTANCE(background);
1916 device = image_instance_device(image_instance);
1917 if (!HAS_DEVMETH_P(XDEVICE(device), colorize_image_instance))
1918 return image_instance;
1920 /* #### There should be a copy_image_instance(), which calls a
1921 device-specific method to copy the window-system subobject. */
1922 new = allocate_image_instance(XIMAGE_INSTANCE_DOMAIN(image_instance),
1924 copy_lcrecord(XIMAGE_INSTANCE(new), XIMAGE_INSTANCE(image_instance));
1925 /* note that if this method returns non-zero, this method MUST
1926 copy any window-system resources, so that when one image instance is
1927 freed, the other one is not hosed. */
1928 if (!DEVMETH(XDEVICE(device), colorize_image_instance, (new, foreground,
1930 return image_instance;
1934 /************************************************************************/
1935 /* Geometry calculations */
1936 /************************************************************************/
1938 /* Find out desired geometry of the image instance. If there is no
1939 special function then just return the width and / or height. */
1941 image_instance_query_geometry(Lisp_Object image_instance,
1942 int *width, int *height,
1943 enum image_instance_geometry disp,
1946 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1948 struct image_instantiator_methods *meths;
1949 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1951 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1952 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1954 if (meths && HAS_IIFORMAT_METH_P(meths, query_geometry)) {
1955 IIFORMAT_METH(meths, query_geometry,
1956 (image_instance, width, height, disp, domain));
1959 *width = IMAGE_INSTANCE_WIDTH(ii);
1961 *height = IMAGE_INSTANCE_HEIGHT(ii);
1965 /* Layout the image instance using the provided dimensions. Layout
1966 widgets are going to do different kinds of calculations to
1967 determine what size to give things so we could make the layout
1968 function relatively simple to take account of that. An alternative
1969 approach is to consider separately the two cases, one where you
1970 don't mind what size you have (normal widgets) and one where you
1971 want to specify something (layout widgets). */
1973 image_instance_layout(Lisp_Object image_instance,
1974 int width, int height,
1975 int xoffset, int yoffset, Lisp_Object domain)
1977 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1979 struct image_instantiator_methods *meths;
1981 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1983 /* Nothing is as nothing does. */
1984 if (NOTHING_IMAGE_INSTANCEP(image_instance))
1987 /* We don't want carefully calculated offsets to be mucked up by
1989 if (xoffset != IMAGE_UNCHANGED_GEOMETRY)
1990 XIMAGE_INSTANCE_XOFFSET(image_instance) = xoffset;
1991 if (yoffset != IMAGE_UNCHANGED_GEOMETRY)
1992 XIMAGE_INSTANCE_YOFFSET(image_instance) = yoffset;
1994 /* If geometry is unspecified then get some reasonable values for it. */
1995 if (width == IMAGE_UNSPECIFIED_GEOMETRY
1996 || height == IMAGE_UNSPECIFIED_GEOMETRY) {
1997 int dwidth = IMAGE_UNSPECIFIED_GEOMETRY;
1998 int dheight = IMAGE_UNSPECIFIED_GEOMETRY;
1999 /* Get the desired geometry. */
2000 image_instance_query_geometry(image_instance,
2002 IMAGE_DESIRED_GEOMETRY, domain);
2003 /* Compare with allowed geometry. */
2004 if (width == IMAGE_UNSPECIFIED_GEOMETRY)
2006 if (height == IMAGE_UNSPECIFIED_GEOMETRY)
2010 /* If we don't have sane values then we cannot layout at this point and
2011 must just return. */
2012 if (width == IMAGE_UNSPECIFIED_GEOMETRY
2013 || height == IMAGE_UNSPECIFIED_GEOMETRY)
2016 /* At this point width and height should contain sane values. Thus
2017 we set the glyph geometry and lay it out. */
2018 if (IMAGE_INSTANCE_WIDTH(ii) != width
2019 || IMAGE_INSTANCE_HEIGHT(ii) != height) {
2020 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
2023 IMAGE_INSTANCE_WIDTH(ii) = width;
2024 IMAGE_INSTANCE_HEIGHT(ii) = height;
2026 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2027 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2029 MAYBE_IIFORMAT_METH(meths, layout,
2030 (image_instance, width, height, xoffset, yoffset,
2032 /* Do not clear the dirty flag here - redisplay will do this for
2034 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 0;
2037 /* Update an image instance from its changed instantiator. */
2039 update_image_instance(Lisp_Object image_instance, Lisp_Object instantiator)
2041 struct image_instantiator_methods *meths;
2042 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2044 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
2046 if (NOTHING_IMAGE_INSTANCEP(image_instance))
2049 assert(!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2051 (internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2052 && internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator,
2055 /* If the instantiator is identical then do nothing. We must use
2056 equal here because the specifier code copies the instantiator. */
2057 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)) {
2058 /* Extract the changed properties so that device / format
2059 methods only have to cope with these. We assume that
2060 normalization has already been done. */
2061 Lisp_Object diffs = find_instantiator_differences(instantiator,
2062 IMAGE_INSTANCE_INSTANTIATOR
2065 encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2066 struct gcpro gcpro1;
2069 /* try device specific methods first ... */
2071 decode_device_ii_format(image_instance_device
2072 (image_instance), type,
2074 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2075 /* ... then format specific methods ... */
2076 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2077 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2079 /* Instance and therefore glyph has changed so mark as dirty.
2080 If we don't do this output optimizations will assume the
2081 glyph is unchanged. */
2082 set_image_instance_dirty_p(image_instance, 1);
2083 /* Structure has changed. */
2084 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2088 /* We should now have a consistent instantiator so keep a record of
2089 it. It is important that we don't actually update the window
2090 system widgets here - we must do that when redisplay tells us
2093 #### should we delay doing this until the display is up-to-date
2095 IMAGE_INSTANCE_INSTANTIATOR(ii) = instantiator;
2099 * Mark image instance in W as dirty if (a) W's faces have changed and
2100 * (b) GLYPH_OR_II instance in W is a string.
2102 * Return non-zero if instance has been marked dirty.
2104 int invalidate_glyph_geometry_maybe(Lisp_Object glyph_or_ii, struct window *w)
2106 if (XFRAME(WINDOW_FRAME(w))->faces_changed) {
2107 Lisp_Object image = glyph_or_ii;
2109 if (GLYPHP(glyph_or_ii)) {
2111 XSETWINDOW(window, w);
2113 glyph_image_instance(glyph_or_ii, window,
2117 if (TEXT_IMAGE_INSTANCEP(image)) {
2118 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image);
2119 IMAGE_INSTANCE_DIRTYP(ii) = 1;
2120 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2121 if (GLYPHP(glyph_or_ii))
2122 XGLYPH_DIRTYP(glyph_or_ii) = 1;
2130 /************************************************************************/
2132 /************************************************************************/
2133 DOESNT_RETURN signal_image_error(const char *reason, Lisp_Object frob)
2135 signal_error(Qimage_conversion_error,
2136 list2(build_translated_string(reason), frob));
2140 signal_image_error_2(const char *reason, Lisp_Object frob0, Lisp_Object frob1)
2142 signal_error(Qimage_conversion_error,
2143 list3(build_translated_string(reason), frob0, frob1));
2146 /****************************************************************************
2148 ****************************************************************************/
2150 static int nothing_possible_dest_types(void)
2152 return IMAGE_NOTHING_MASK;
2156 nothing_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2157 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2158 int dest_mask, Lisp_Object domain)
2160 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2162 if (dest_mask & IMAGE_NOTHING_MASK) {
2163 IMAGE_INSTANCE_TYPE(ii) = IMAGE_NOTHING;
2164 IMAGE_INSTANCE_HEIGHT(ii) = 0;
2165 IMAGE_INSTANCE_WIDTH(ii) = 0;
2167 incompatible_image_types(instantiator, dest_mask,
2168 IMAGE_NOTHING_MASK);
2171 /****************************************************************************
2173 ****************************************************************************/
2175 static void inherit_validate(Lisp_Object instantiator)
2177 face_must_be_present(instantiator);
2181 inherit_normalize(Lisp_Object inst, Lisp_Object console_type,
2182 Lisp_Object dest_mask)
2186 assert(XVECTOR_LENGTH(inst) == 3);
2187 face = XVECTOR_DATA(inst)[2];
2189 inst = vector3(Qinherit, Q_face, Fget_face(face));
2193 static int inherit_possible_dest_types(void)
2195 return IMAGE_MONO_PIXMAP_MASK;
2199 inherit_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2200 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2201 int dest_mask, Lisp_Object domain)
2203 /* handled specially in image_instantiate */
2207 /****************************************************************************
2209 ****************************************************************************/
2211 static void string_validate(Lisp_Object instantiator)
2213 data_must_be_present(instantiator);
2216 static int string_possible_dest_types(void)
2218 return IMAGE_TEXT_MASK;
2221 /* Called from autodetect_instantiate() */
2223 string_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2224 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2225 int dest_mask, Lisp_Object domain)
2227 Lisp_Object string = find_keyword_in_vector(instantiator, Q_data);
2228 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2230 /* Should never get here with a domain other than a window. */
2231 assert(!NILP(string) && WINDOWP(DOMAIN_WINDOW(domain)));
2232 if (dest_mask & IMAGE_TEXT_MASK) {
2233 IMAGE_INSTANCE_TYPE(ii) = IMAGE_TEXT;
2234 IMAGE_INSTANCE_TEXT_STRING(ii) = string;
2236 incompatible_image_types(instantiator, dest_mask,
2240 /* Sort out the size of the text that is being displayed. Calculating
2241 it dynamically allows us to change the text and still see
2242 everything. Note that the following methods are for text not string
2243 since that is what the instantiated type is. The first method is a
2244 helper that is used elsewhere for calculating text geometry. */
2246 query_string_geometry(Lisp_Object string, Lisp_Object face,
2247 int *width, int *height, int *descent, Lisp_Object domain)
2249 struct font_metric_info fm;
2250 unsigned char charsets[NUM_LEADING_BYTES];
2251 struct face_cachel frame_cachel;
2252 struct face_cachel *cachel;
2253 Lisp_Object frame = DOMAIN_FRAME(domain);
2255 CHECK_STRING(string);
2257 /* Compute height */
2259 /* Compute string metric info */
2260 find_charsets_in_bufbyte_string(charsets,
2261 XSTRING_DATA(string),
2262 XSTRING_LENGTH(string));
2264 /* Fallback to the default face if none was provided. */
2266 reset_face_cachel(&frame_cachel);
2267 update_face_cachel_data(&frame_cachel, frame, face);
2268 cachel = &frame_cachel;
2270 cachel = WINDOW_FACE_CACHEL(DOMAIN_XWINDOW(domain),
2274 ensure_face_cachel_complete(cachel, domain, charsets);
2275 face_cachel_charset_font_metric_info(cachel, charsets, &fm);
2277 *height = fm.ascent + fm.descent;
2278 /* #### descent only gets set if we query the height as well. */
2280 *descent = fm.descent;
2287 redisplay_frame_text_width_string(XFRAME(frame),
2292 redisplay_frame_text_width_string(XFRAME(frame),
2299 query_string_font(Lisp_Object string, Lisp_Object face, Lisp_Object domain)
2301 unsigned char charsets[NUM_LEADING_BYTES];
2302 struct face_cachel frame_cachel;
2303 struct face_cachel *cachel;
2305 Lisp_Object frame = DOMAIN_FRAME(domain);
2307 /* Compute string font info */
2308 find_charsets_in_bufbyte_string(charsets,
2309 XSTRING_DATA(string),
2310 XSTRING_LENGTH(string));
2312 reset_face_cachel(&frame_cachel);
2313 update_face_cachel_data(&frame_cachel, frame, face);
2314 cachel = &frame_cachel;
2316 ensure_face_cachel_complete(cachel, domain, charsets);
2318 for (i = 0; i < NUM_LEADING_BYTES; i++) {
2321 CHARSET_BY_LEADING_BYTE(i + MIN_LEADING_BYTE);
2322 return FACE_CACHEL_FONT(cachel, tmp);
2326 return Qnil; /* NOT REACHED */
2330 text_query_geometry(Lisp_Object image_instance,
2331 int *width, int *height,
2332 enum image_instance_geometry disp, Lisp_Object domain)
2334 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2337 query_string_geometry(IMAGE_INSTANCE_TEXT_STRING(ii),
2338 IMAGE_INSTANCE_FACE(ii),
2339 width, height, &descent, domain);
2341 /* The descent gets set as a side effect of querying the
2343 IMAGE_INSTANCE_TEXT_DESCENT(ii) = descent;
2346 /* set the properties of a string */
2347 static void text_update(Lisp_Object image_instance, Lisp_Object instantiator)
2349 Lisp_Object val = find_keyword_in_vector(instantiator, Q_data);
2353 XIMAGE_INSTANCE_TEXT_STRING(image_instance) = val;
2357 /****************************************************************************
2358 * formatted-string *
2359 ****************************************************************************/
2361 static void formatted_string_validate(Lisp_Object instantiator)
2363 data_must_be_present(instantiator);
2366 static int formatted_string_possible_dest_types(void)
2368 return IMAGE_TEXT_MASK;
2372 formatted_string_instantiate(Lisp_Object image_instance,
2373 Lisp_Object instantiator,
2374 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2375 int dest_mask, Lisp_Object domain)
2377 /* #### implement this */
2378 warn_when_safe(Qunimplemented, Qnotice,
2379 "`formatted-string' not yet implemented; assuming `string'");
2381 string_instantiate(image_instance, instantiator,
2382 pointer_fg, pointer_bg, dest_mask, domain);
2385 /************************************************************************/
2386 /* pixmap file functions */
2387 /************************************************************************/
2389 /* If INSTANTIATOR refers to inline data, return Qnil.
2390 If INSTANTIATOR refers to data in a file, return the full filename
2391 if it exists; otherwise, return a cons of (filename).
2393 FILE_KEYWORD and DATA_KEYWORD are symbols specifying the
2394 keywords used to look up the file and inline data,
2395 respectively, in the instantiator. Normally these would
2396 be Q_file and Q_data, but might be different for mask data. */
2399 potential_pixmap_file_instantiator(Lisp_Object instantiator,
2400 Lisp_Object file_keyword,
2401 Lisp_Object data_keyword,
2402 Lisp_Object console_type)
2407 assert(VECTORP(instantiator));
2409 data = find_keyword_in_vector(instantiator, data_keyword);
2410 file = find_keyword_in_vector(instantiator, file_keyword);
2412 if (!NILP(file) && NILP(data)) {
2413 Lisp_Object retval = MAYBE_LISP_CONTYPE_METH
2414 (decode_console_type(console_type, ERROR_ME),
2415 locate_pixmap_file, (file));
2420 return Fcons(file, Qnil); /* should have been file */
2427 simple_image_type_normalize(Lisp_Object inst, Lisp_Object console_type,
2428 Lisp_Object image_type_tag)
2430 /* This function can call lisp */
2431 Lisp_Object file = Qnil;
2432 struct gcpro gcpro1, gcpro2;
2433 Lisp_Object alist = Qnil;
2435 GCPRO2(file, alist);
2437 /* Now, convert any file data into inline data. At the end of this,
2438 `data' will contain the inline data (if any) or Qnil, and `file'
2439 will contain the name this data was derived from (if known) or
2442 Note that if we cannot generate any regular inline data, we
2445 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2448 if (CONSP(file)) /* failure locating filename */
2449 signal_double_file_error("Opening pixmap file",
2450 "no such file or directory",
2453 if (NILP(file)) /* no conversion necessary */
2454 RETURN_UNGCPRO(inst);
2456 alist = tagged_vector_to_alist(inst);
2459 Lisp_Object data = make_string_from_file(file);
2460 alist = remassq_no_quit(Q_file, alist);
2461 /* there can't be a :data at this point. */
2462 alist = Fcons(Fcons(Q_file, file),
2463 Fcons(Fcons(Q_data, data), alist));
2467 Lisp_Object result =
2468 alist_to_tagged_vector(image_type_tag, alist);
2470 RETURN_UNGCPRO(result);
2474 #ifdef HAVE_WINDOW_SYSTEM
2475 /**********************************************************************
2477 **********************************************************************/
2479 /* Check if DATA represents a valid inline XBM spec (i.e. a list
2480 of (width height bits), with checking done on the dimensions).
2481 If not, signal an error. */
2483 static void check_valid_xbm_inline(Lisp_Object data)
2485 Lisp_Object width, height, bits;
2488 !CONSP(XCDR(data)) ||
2489 !CONSP(XCDR(XCDR(data))) || !NILP(XCDR(XCDR(XCDR(data)))))
2490 signal_simple_error("Must be list of 3 elements", data);
2493 height = XCAR(XCDR(data));
2494 bits = XCAR(XCDR(XCDR(data)));
2498 if (!NATNUMP(width))
2499 signal_simple_error("Width must be a natural number", width);
2501 if (!NATNUMP(height))
2502 signal_simple_error("Height must be a natural number", height);
2504 if (((XINT(width) * XINT(height)) / 8) > XSTRING_CHAR_LENGTH(bits))
2505 signal_simple_error("data is too short for width and height",
2506 vector3(width, height, bits));
2509 /* Validate method for XBM's. */
2511 static void xbm_validate(Lisp_Object instantiator)
2513 file_or_data_must_be_present(instantiator);
2516 /* Given a filename that is supposed to contain XBM data, return
2517 the inline representation of it as (width height bits). Return
2518 the hotspot through XHOT and YHOT, if those pointers are not 0.
2519 If there is no hotspot, XHOT and YHOT will contain -1.
2521 If the function fails:
2523 -- if OK_IF_DATA_INVALID is set and the data was invalid,
2525 -- maybe return an error, or return Qnil.
2528 #ifdef HAVE_X_WINDOWS
2529 #include <X11/Xlib.h>
2531 #define XFree(data) free(data)
2535 bitmap_to_lisp_data(Lisp_Object name, int *xhot, int *yhot,
2536 int ok_if_data_invalid)
2541 const char *filename_ext;
2543 LISP_STRING_TO_EXTERNAL(name, filename_ext, Qfile_name);
2544 result = read_bitmap_data_from_file(filename_ext, &w, &h,
2545 (unsigned char **)((void*)&data),
2548 if (result == BitmapSuccess) {
2550 int len = (w + 7) / 8 * h;
2552 retval = list3(make_int(w), make_int(h),
2553 make_ext_string(data, len, Qbinary));
2559 case BitmapOpenFailed:
2561 /* should never happen */
2562 signal_double_file_error("Opening bitmap file",
2563 "no such file or directory",
2566 case BitmapFileInvalid:
2568 if (ok_if_data_invalid)
2570 signal_double_file_error("Reading bitmap file",
2571 "invalid data in file", name);
2573 case BitmapNoMemory:
2575 signal_double_file_error("Reading bitmap file",
2576 "out of memory", name);
2580 signal_double_file_error_2("Reading bitmap file",
2581 "unknown error code",
2582 make_int(result), name);
2586 return Qnil; /* not reached */
2590 xbm_mask_file_munging(Lisp_Object alist, Lisp_Object file,
2591 Lisp_Object mask_file, Lisp_Object console_type)
2593 /* This is unclean but it's fairly standard -- a number of the
2594 bitmaps in /usr/include/X11/bitmaps use it -- so we support
2597 /* don't override explicitly specified mask data. */
2598 && NILP(assq_no_quit(Q_mask_data, alist))
2600 mask_file = MAYBE_LISP_CONTYPE_METH
2601 (decode_console_type(console_type, ERROR_ME),
2602 locate_pixmap_file, (concat2(file, build_string("Mask"))));
2603 if (NILP(mask_file))
2604 mask_file = MAYBE_LISP_CONTYPE_METH
2605 (decode_console_type(console_type, ERROR_ME),
2607 (concat2(file, build_string("msk"))));
2610 if (!NILP(mask_file)) {
2611 Lisp_Object mask_data = bitmap_to_lisp_data(mask_file, 0, 0, 0);
2612 alist = remassq_no_quit(Q_mask_file, alist);
2613 /* there can't be a :mask-data at this point. */
2614 alist = Fcons(Fcons(Q_mask_file, mask_file),
2615 Fcons(Fcons(Q_mask_data, mask_data), alist));
2621 /* Normalize method for XBM's. */
2624 xbm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2626 Lisp_Object file = Qnil, mask_file = Qnil;
2627 struct gcpro gcpro1, gcpro2, gcpro3;
2628 Lisp_Object alist = Qnil;
2630 GCPRO3(file, mask_file, alist);
2632 /* Now, convert any file data into inline data for both the regular
2633 data and the mask data. At the end of this, `data' will contain
2634 the inline data (if any) or Qnil, and `file' will contain
2635 the name this data was derived from (if known) or Qnil.
2636 Likewise for `mask_file' and `mask_data'.
2638 Note that if we cannot generate any regular inline data, we
2641 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2643 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2647 if (CONSP(file)) /* failure locating filename */
2648 signal_double_file_error("Opening bitmap file",
2649 "no such file or directory",
2652 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2653 RETURN_UNGCPRO(inst);
2655 alist = tagged_vector_to_alist(inst);
2659 Lisp_Object data = bitmap_to_lisp_data(file, &xhot, &yhot, 0);
2660 alist = remassq_no_quit(Q_file, alist);
2661 /* there can't be a :data at this point. */
2662 alist = Fcons(Fcons(Q_file, file),
2663 Fcons(Fcons(Q_data, data), alist));
2665 if (xhot != -1 && NILP(assq_no_quit(Q_hotspot_x, alist)))
2666 alist = Fcons(Fcons(Q_hotspot_x, make_int(xhot)),
2668 if (yhot != -1 && NILP(assq_no_quit(Q_hotspot_y, alist)))
2669 alist = Fcons(Fcons(Q_hotspot_y, make_int(yhot)),
2673 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2676 Lisp_Object result = alist_to_tagged_vector(Qxbm, alist);
2678 RETURN_UNGCPRO(result);
2682 static int xbm_possible_dest_types(void)
2685 IMAGE_MONO_PIXMAP_MASK |
2686 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2692 /**********************************************************************
2694 **********************************************************************/
2696 static void xface_validate(Lisp_Object instantiator)
2698 file_or_data_must_be_present(instantiator);
2702 xface_normalize(Lisp_Object inst, Lisp_Object console_type,
2703 Lisp_Object dest_mask)
2705 /* This function can call lisp */
2706 Lisp_Object file = Qnil, mask_file = Qnil;
2707 struct gcpro gcpro1, gcpro2, gcpro3;
2708 Lisp_Object alist = Qnil;
2710 GCPRO3(file, mask_file, alist);
2712 /* Now, convert any file data into inline data for both the regular
2713 data and the mask data. At the end of this, `data' will contain
2714 the inline data (if any) or Qnil, and `file' will contain
2715 the name this data was derived from (if known) or Qnil.
2716 Likewise for `mask_file' and `mask_data'.
2718 Note that if we cannot generate any regular inline data, we
2721 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2723 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2727 if (CONSP(file)) /* failure locating filename */
2728 signal_double_file_error("Opening bitmap file",
2729 "no such file or directory",
2732 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2733 RETURN_UNGCPRO(inst);
2735 #ifdef HAVE_WINDOW_SYSTEM
2736 alist = tagged_vector_to_alist(inst);
2739 Lisp_Object data = make_string_from_file(file);
2740 alist = remassq_no_quit(Q_file, alist);
2741 /* there can't be a :data at this point. */
2742 alist = Fcons(Fcons(Q_file, file),
2743 Fcons(Fcons(Q_data, data), alist));
2746 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2749 Lisp_Object result = alist_to_tagged_vector(Qxface, alist);
2751 RETURN_UNGCPRO(result);
2754 RETURN_UNGCPRO(Qnil);
2758 static int xface_possible_dest_types(void)
2761 IMAGE_MONO_PIXMAP_MASK |
2762 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2765 #endif /* HAVE_XFACE */
2769 /**********************************************************************
2771 **********************************************************************/
2774 /* Gtk has to be gratuitously different, eh? */
2775 Lisp_Object pixmap_to_lisp_data(Lisp_Object name, int ok_if_data_invalid)
2777 return (make_string_from_file(name));
2780 Lisp_Object pixmap_to_lisp_data(Lisp_Object name, int ok_if_data_invalid)
2786 LISP_STRING_TO_EXTERNAL(name, fname, Qfile_name);
2787 result = XpmReadFileToData(fname, &data);
2789 if (result == XpmSuccess) {
2790 Lisp_Object retval = Qnil;
2791 struct buffer *old_buffer = current_buffer;
2792 Lisp_Object temp_buffer =
2793 Fget_buffer_create(build_string(" *pixmap conversion*"));
2795 int height, width, ncolors;
2796 struct gcpro gcpro1, gcpro2, gcpro3;
2797 int speccount = specpdl_depth();
2799 GCPRO3(name, retval, temp_buffer);
2801 specbind(Qinhibit_quit, Qt);
2802 set_buffer_internal(XBUFFER(temp_buffer));
2803 Ferase_buffer(Qnil);
2805 buffer_insert_c_string(current_buffer, "/* XPM */\r");
2806 buffer_insert_c_string(current_buffer,
2807 "static char *pixmap[] = {\r");
2809 sscanf(data[0], "%d %d %d", &height, &width, &ncolors);
2810 for (elt = 0; elt <= width + ncolors; elt++) {
2811 buffer_insert_c_string(current_buffer, "\"");
2812 buffer_insert_c_string(current_buffer, data[elt]);
2814 if (elt < width + ncolors)
2815 buffer_insert_c_string(current_buffer, "\",\r");
2817 buffer_insert_c_string(current_buffer,
2821 retval = Fbuffer_substring(Qnil, Qnil, Qnil);
2824 set_buffer_internal(old_buffer);
2825 unbind_to(speccount, Qnil);
2827 RETURN_UNGCPRO(retval);
2831 case XpmFileInvalid:
2833 if (ok_if_data_invalid)
2835 signal_image_error("invalid XPM data in file", name);
2839 signal_double_file_error("Reading pixmap file",
2840 "out of memory", name);
2844 /* should never happen? */
2845 signal_double_file_error("Opening pixmap file",
2846 "no such file or directory",
2851 signal_double_file_error_2("Parsing pixmap file",
2852 "unknown error code",
2853 make_int(result), name);
2858 return Qnil; /* not reached */
2860 #endif /* !HAVE_GTK */
2862 static void check_valid_xpm_color_symbols(Lisp_Object data)
2866 for (rest = data; !NILP(rest); rest = XCDR(rest)) {
2868 !CONSP(XCAR(rest)) ||
2869 !STRINGP(XCAR(XCAR(rest))) ||
2870 (!STRINGP(XCDR(XCAR(rest))) &&
2871 !COLOR_SPECIFIERP(XCDR(XCAR(rest)))))
2872 signal_simple_error("Invalid color symbol alist", data);
2876 static void xpm_validate(Lisp_Object instantiator)
2878 file_or_data_must_be_present(instantiator);
2881 Lisp_Object Vxpm_color_symbols;
2883 Lisp_Object evaluate_xpm_color_symbols(void)
2885 Lisp_Object rest, results = Qnil;
2886 struct gcpro gcpro1, gcpro2;
2888 GCPRO2(rest, results);
2889 for (rest = Vxpm_color_symbols; !NILP(rest); rest = XCDR(rest)) {
2890 Lisp_Object name, value, cons;
2899 value = XCAR(value);
2900 value = Feval(value);
2903 if (!STRINGP(value) && !COLOR_SPECIFIERP(value))
2905 ("Result from xpm-color-symbols eval must be nil, string, or color",
2907 results = Fcons(Fcons(name, value), results);
2909 UNGCPRO; /* no more evaluation */
2914 xpm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2916 Lisp_Object file = Qnil;
2917 Lisp_Object color_symbols;
2918 struct gcpro gcpro1, gcpro2;
2919 Lisp_Object alist = Qnil;
2921 GCPRO2(file, alist);
2923 /* Now, convert any file data into inline data. At the end of this,
2924 `data' will contain the inline data (if any) or Qnil, and
2925 `file' will contain the name this data was derived from (if
2928 Note that if we cannot generate any regular inline data, we
2931 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2934 if (CONSP(file)) /* failure locating filename */
2935 signal_double_file_error("Opening pixmap file",
2936 "no such file or directory",
2939 color_symbols = find_keyword_in_vector_or_given(inst, Q_color_symbols,
2942 if (NILP(file) && !UNBOUNDP(color_symbols))
2943 /* no conversion necessary */
2944 RETURN_UNGCPRO(inst);
2946 alist = tagged_vector_to_alist(inst);
2949 Lisp_Object data = pixmap_to_lisp_data(file, 0);
2950 alist = remassq_no_quit(Q_file, alist);
2951 /* there can't be a :data at this point. */
2952 alist = Fcons(Fcons(Q_file, file),
2953 Fcons(Fcons(Q_data, data), alist));
2956 if (UNBOUNDP(color_symbols)) {
2957 color_symbols = evaluate_xpm_color_symbols();
2958 alist = Fcons(Fcons(Q_color_symbols, color_symbols), alist);
2962 Lisp_Object result = alist_to_tagged_vector(Qxpm, alist);
2964 RETURN_UNGCPRO(result);
2968 static int xpm_possible_dest_types(void)
2971 IMAGE_MONO_PIXMAP_MASK |
2972 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2975 #endif /* HAVE_XPM */
2977 /****************************************************************************
2978 * Image Specifier Object *
2979 ****************************************************************************/
2981 DEFINE_SPECIFIER_TYPE(image);
2983 static void image_create(Lisp_Object obj)
2985 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2987 IMAGE_SPECIFIER_ALLOWED(image) = ~0; /* all are allowed */
2988 IMAGE_SPECIFIER_ATTACHEE(image) = Qnil;
2989 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = Qnil;
2992 static void image_mark(Lisp_Object obj)
2994 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2996 mark_object(IMAGE_SPECIFIER_ATTACHEE(image));
2997 mark_object(IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image));
3000 static int instantiator_eq_equal(Lisp_Object obj1, Lisp_Object obj2)
3005 else if (CONSP(obj1) && CONSP(obj2)) {
3006 return instantiator_eq_equal(XCAR(obj1), XCAR(obj2))
3007 && instantiator_eq_equal(XCDR(obj1), XCDR(obj2));
3012 static hcode_t instantiator_eq_hash(Lisp_Object obj)
3015 /* no point in worrying about tail recursion, since we're not
3017 return HASH2(instantiator_eq_hash(XCAR(obj)),
3018 instantiator_eq_hash(XCDR(obj)));
3020 return LISP_HASH(obj);
3023 /* We need a special hash table for storing image instances. */
3024 Lisp_Object make_image_instance_cache_hash_table(void)
3026 return make_general_lisp_hash_table
3027 (instantiator_eq_hash, instantiator_eq_equal,
3028 30, -1.0, -1.0, HASH_TABLE_KEY_CAR_VALUE_WEAK);
3031 static Lisp_Object image_instantiate_cache_result(Lisp_Object locative)
3033 /* locative = (instance instantiator . subtable)
3035 So we are using the instantiator as the key and the instance as
3036 the value. Since the hashtable is key-weak this means that the
3037 image instance will stay around as long as the instantiator stays
3038 around. The instantiator is stored in the `image' slot of the
3039 glyph, so as long as the glyph is marked the instantiator will be
3040 as well and hence the cached image instance also. */
3041 Fputhash(XCAR(XCDR(locative)), XCAR(locative), XCDR(XCDR(locative)));
3042 free_cons(XCONS(XCDR(locative)));
3043 free_cons(XCONS(locative));
3047 /* Given a specification for an image, return an instance of
3048 the image which matches the given instantiator and which can be
3049 displayed in the given domain. */
3052 image_instantiate(Lisp_Object specifier, Lisp_Object matchspec,
3053 Lisp_Object domain, Lisp_Object instantiator,
3057 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3058 int dest_mask = XIMAGE_SPECIFIER_ALLOWED(specifier);
3059 int pointerp = dest_mask & image_instance_type_to_mask(IMAGE_POINTER);
3061 if (IMAGE_INSTANCEP(instantiator)) {
3062 /* make sure that the image instance's governing domain and type are
3064 Lisp_Object governing_domain =
3065 XIMAGE_INSTANCE_DOMAIN(instantiator);
3067 if ((DEVICEP(governing_domain)
3068 && EQ(governing_domain, DOMAIN_DEVICE(domain)))
3069 || (FRAMEP(governing_domain)
3070 && EQ(governing_domain, DOMAIN_FRAME(domain)))
3071 || (WINDOWP(governing_domain)
3072 && EQ(governing_domain, DOMAIN_WINDOW(domain)))) {
3074 image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE
3076 if (mask & dest_mask)
3077 return instantiator;
3080 ("Type of image instance not allowed here",
3083 signal_simple_error_2("Wrong domain for image instance",
3084 instantiator, domain);
3086 /* How ugly !! An image instanciator that uses a kludgy syntax to snarf in
3087 face properties. There's a design flaw here. -- didier */
3088 else if (VECTORP(instantiator)
3089 && EQ(INSTANTIATOR_TYPE(instantiator), Qinherit)) {
3090 assert(XVECTOR_LENGTH(instantiator) == 3);
3091 return (FACE_PROPERTY_INSTANCE
3092 (Fget_face(XVECTOR_DATA(instantiator)[2]),
3093 Qbackground_pixmap, domain, 1, depth));
3095 Lisp_Object instance = Qnil;
3096 Lisp_Object subtable = Qnil;
3097 /* #### Should this be GCPRO'd? */
3098 Lisp_Object hash_key = Qnil;
3099 Lisp_Object pointer_fg = Qnil;
3100 Lisp_Object pointer_bg = Qnil;
3101 Lisp_Object governing_domain =
3102 get_image_instantiator_governing_domain(instantiator,
3104 struct gcpro gcpro1;
3108 /* We have to put subwindow, widget and text image instances in
3109 a per-window cache so that we can see the same glyph in
3110 different windows. We use governing_domain to determine the type
3111 of image_instance that will be created. */
3114 pointer_fg = FACE_FOREGROUND(Vpointer_face, domain);
3115 pointer_bg = FACE_BACKGROUND(Vpointer_face, domain);
3116 hash_key = list4(glyph, INSTANTIATOR_TYPE(instantiator),
3117 pointer_fg, pointer_bg);
3119 /* We cannot simply key on the glyph since fallbacks could use
3120 the same glyph but have a totally different instantiator
3121 type. Thus we key on the glyph and the type (but not any
3122 other parts of the instantiator. */
3124 list2(glyph, INSTANTIATOR_TYPE(instantiator));
3126 /* First look in the device cache. */
3127 if (DEVICEP(governing_domain)) {
3128 subtable = Fgethash(make_int(dest_mask),
3129 XDEVICE(governing_domain)->
3130 image_instance_cache, Qunbound);
3131 if (UNBOUNDP(subtable)) {
3132 /* For the image instance cache, we do comparisons with
3133 EQ rather than with EQUAL, as we do for color and
3134 font names. The reasons are:
3136 1) pixmap data can be very long, and thus the hashing
3137 and comparing will take awhile.
3139 2) It's not so likely that we'll run into things that
3140 are EQUAL but not EQ (that can happen a lot with
3141 faces, because their specifiers are copied around);
3142 but pixmaps tend not to be in faces.
3144 However, if the image-instance could be a pointer, we
3145 have to use EQUAL because we massaged the
3146 instantiator into a cons3 also containing the
3147 foreground and background of the pointer face. */
3149 make_image_instance_cache_hash_table();
3151 Fputhash(make_int(dest_mask), subtable,
3152 XDEVICE(governing_domain)->
3153 image_instance_cache);
3154 instance = Qunbound;
3157 Fgethash(hash_key, subtable, Qunbound);
3159 } else if (WINDOWP(governing_domain)) {
3160 /* Subwindows have a per-window cache and have to be treated
3164 XWINDOW(governing_domain)->
3165 subwindow_instance_cache, Qunbound);
3167 abort(); /* We're not allowed anything else currently. */
3169 /* If we don't have an instance at this point then create
3171 if (UNBOUNDP(instance)) {
3172 Lisp_Object locative = noseeum_cons(Qnil,
3181 subwindow_instance_cache));
3182 int speccount = specpdl_depth();
3184 /* Make sure we cache the failures, too. Use an
3185 unwind-protect to catch such errors. If we fail, the
3186 unwind-protect records nil in the hash table. If we
3187 succeed, we change the car of the locative to the
3188 resulting instance, which gets recorded instead. */
3189 record_unwind_protect(image_instantiate_cache_result,
3192 instantiate_image_instantiator(governing_domain,
3193 domain, instantiator,
3198 /* We need a per-frame cache for redisplay. */
3199 cache_subwindow_instance_in_frame_maybe(instance);
3201 Fsetcar(locative, instance);
3202 #ifdef ERROR_CHECK_GLYPHS
3203 if (image_instance_type_to_mask
3204 (XIMAGE_INSTANCE_TYPE(instance))
3205 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3206 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3207 DOMAIN_FRAME(domain)));
3209 unbind_to(speccount, Qnil);
3210 #ifdef ERROR_CHECK_GLYPHS
3211 if (image_instance_type_to_mask
3212 (XIMAGE_INSTANCE_TYPE(instance))
3213 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3214 assert(EQ(Fgethash(hash_key,
3215 XWINDOW(governing_domain)
3216 ->subwindow_instance_cache,
3217 Qunbound), instance));
3219 } else if (NILP(instance))
3221 ("Can't instantiate image (probably cached)",
3223 /* We found an instance. However, because we are using the glyph
3224 as the hash key instead of the instantiator, the current
3225 instantiator may not be the same as the original. Thus we
3226 must update the instance based on the new
3227 instantiator. Preserving instance identity like this is
3228 important to stop excessive window system widget creation and
3229 deletion - and hence flashing. */
3231 /* #### This function should be able to cope with *all*
3232 changes to the instantiator, but currently only copes
3233 with the most used properties. This means that it is
3234 possible to make changes that don't get reflected in the
3236 update_image_instance(instance, instantiator);
3237 free_list(hash_key);
3240 #ifdef ERROR_CHECK_GLYPHS
3241 if (image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE(instance))
3242 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3243 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3244 DOMAIN_FRAME(domain)));
3246 ERROR_CHECK_IMAGE_INSTANCE(instance);
3247 RETURN_UNGCPRO(instance);
3251 return Qnil; /* not reached */
3254 /* Validate an image instantiator. */
3256 static void image_validate(Lisp_Object instantiator)
3258 if (IMAGE_INSTANCEP(instantiator) || STRINGP(instantiator))
3260 else if (VECTORP(instantiator)) {
3261 Lisp_Object *elt = XVECTOR_DATA(instantiator);
3262 int instantiator_len = XVECTOR_LENGTH(instantiator);
3263 struct image_instantiator_methods *meths;
3264 Lisp_Object already_seen = Qnil;
3265 struct gcpro gcpro1;
3268 if (instantiator_len < 1)
3269 signal_simple_error("Vector length must be at least 1",
3272 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3273 if (!(instantiator_len & 1))
3275 ("Must have alternating keyword/value pairs",
3278 GCPRO1(already_seen);
3280 for (i = 1; i < instantiator_len; i += 2) {
3281 Lisp_Object keyword = elt[i];
3282 Lisp_Object value = elt[i + 1];
3285 CHECK_SYMBOL(keyword);
3286 if (!SYMBOL_IS_KEYWORD(keyword))
3288 ("Symbol must begin with a colon", keyword);
3290 for (j = 0; j < Dynarr_length(meths->keywords); j++)
3293 Dynarr_at(meths->keywords, j).keyword))
3296 if (j == Dynarr_length(meths->keywords))
3297 signal_simple_error("Unrecognized keyword",
3300 if (!Dynarr_at(meths->keywords, j).multiple_p) {
3301 if (!NILP(memq_no_quit(keyword, already_seen)))
3303 ("Keyword may not appear more than once",
3305 already_seen = Fcons(keyword, already_seen);
3308 (Dynarr_at(meths->keywords, j).validate) (value);
3313 MAYBE_IIFORMAT_METH(meths, validate, (instantiator));
3315 signal_simple_error("Must be string or vector", instantiator);
3318 static void image_after_change(Lisp_Object specifier, Lisp_Object locale)
3320 Lisp_Object attachee =
3321 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3322 Lisp_Object property =
3323 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(XIMAGE_SPECIFIER(specifier));
3324 if (FACEP(attachee)) {
3325 face_property_was_changed(attachee, property, locale);
3326 if (BUFFERP(locale))
3327 XBUFFER(locale)->buffer_local_face_property = 1;
3328 } else if (GLYPHP(attachee))
3329 glyph_property_was_changed(attachee, property, locale);
3333 set_image_attached_to(Lisp_Object obj, Lisp_Object face_or_glyph,
3334 Lisp_Object property)
3336 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
3338 IMAGE_SPECIFIER_ATTACHEE(image) = face_or_glyph;
3339 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = property;
3343 image_going_to_add(Lisp_Object specifier, Lisp_Object locale,
3344 Lisp_Object tag_set, Lisp_Object instantiator)
3346 Lisp_Object possible_console_types = Qnil;
3348 Lisp_Object retlist = Qnil;
3349 struct gcpro gcpro1, gcpro2;
3351 LIST_LOOP(rest, Vconsole_type_list) {
3352 Lisp_Object contype = XCAR(rest);
3353 if (!NILP(memq_no_quit(contype, tag_set)))
3354 possible_console_types =
3355 Fcons(contype, possible_console_types);
3358 if (XINT(Flength(possible_console_types)) > 1)
3359 /* two conflicting console types specified */
3362 if (NILP(possible_console_types))
3363 possible_console_types = Vconsole_type_list;
3365 GCPRO2(retlist, possible_console_types);
3367 LIST_LOOP(rest, possible_console_types) {
3368 Lisp_Object contype = XCAR(rest);
3369 Lisp_Object newinst = call_with_suspended_errors
3370 ((lisp_fn_t) normalize_image_instantiator,
3371 Qnil, Qimage, ERROR_ME_NOT, 3, instantiator, contype,
3372 make_int(XIMAGE_SPECIFIER_ALLOWED(specifier)));
3374 if (!NILP(newinst)) {
3376 if (NILP(memq_no_quit(contype, tag_set)))
3377 newtag = Fcons(contype, tag_set);
3380 retlist = Fcons(Fcons(newtag, newinst), retlist);
3389 /* Copy an image instantiator. We can't use Fcopy_tree since widgets
3390 may contain circular references which would send Fcopy_tree into
3392 static Lisp_Object image_copy_vector_instantiator(Lisp_Object instantiator)
3395 struct image_instantiator_methods *meths;
3397 int instantiator_len;
3399 CHECK_VECTOR(instantiator);
3401 instantiator = Fcopy_sequence(instantiator);
3402 elt = XVECTOR_DATA(instantiator);
3403 instantiator_len = XVECTOR_LENGTH(instantiator);
3405 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3407 for (i = 1; i < instantiator_len; i += 2) {
3409 Lisp_Object keyword = elt[i];
3410 Lisp_Object value = elt[i + 1];
3412 /* Find the keyword entry. */
3413 for (j = 0; j < Dynarr_length(meths->keywords); j++) {
3414 if (EQ(keyword, Dynarr_at(meths->keywords, j).keyword))
3418 /* Only copy keyword values that should be copied. */
3419 if (Dynarr_at(meths->keywords, j).copy_p
3420 && (CONSP(value) || VECTORP(value))) {
3421 elt[i + 1] = Fcopy_tree(value, Qt);
3425 return instantiator;
3428 static Lisp_Object image_copy_instantiator(Lisp_Object arg)
3432 rest = arg = Fcopy_sequence(arg);
3433 while (CONSP(rest)) {
3434 Lisp_Object elt = XCAR(rest);
3436 XCAR(rest) = Fcopy_tree(elt, Qt);
3437 else if (VECTORP(elt))
3439 image_copy_vector_instantiator(elt);
3440 if (VECTORP(XCDR(rest))) /* hack for (a b . [c d]) */
3441 XCDR(rest) = Fcopy_tree(XCDR(rest), Qt);
3444 } else if (VECTORP(arg)) {
3445 arg = image_copy_vector_instantiator(arg);
3450 DEFUN("image-specifier-p", Fimage_specifier_p, 1, 1, 0, /*
3451 Return non-nil if OBJECT is an image specifier.
3452 See `make-image-specifier' for a description of image instantiators.
3456 return IMAGE_SPECIFIERP(object) ? Qt : Qnil;
3459 /****************************************************************************
3461 ****************************************************************************/
3463 static Lisp_Object mark_glyph(Lisp_Object obj)
3465 Lisp_Glyph *glyph = XGLYPH(obj);
3467 mark_object(glyph->image);
3468 mark_object(glyph->contrib_p);
3469 mark_object(glyph->baseline);
3470 mark_object(glyph->face);
3472 return glyph->plist;
3476 print_glyph(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
3478 Lisp_Glyph *glyph = XGLYPH(obj);
3482 error("printing unreadable object #<glyph 0x%x>",
3485 write_c_string("#<glyph (", printcharfun);
3486 print_internal(Fglyph_type(obj), printcharfun, 0);
3487 write_c_string(") ", printcharfun);
3488 print_internal(glyph->image, printcharfun, 1);
3489 sprintf(buf, "0x%x>", glyph->header.uid);
3490 write_c_string(buf, printcharfun);
3493 /* Glyphs are equal if all of their display attributes are equal. We
3494 don't compare names or doc-strings, because that would make equal
3497 This isn't concerned with "unspecified" attributes, that's what
3498 #'glyph-differs-from-default-p is for. */
3499 static int glyph_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
3501 Lisp_Glyph *g1 = XGLYPH(obj1);
3502 Lisp_Glyph *g2 = XGLYPH(obj2);
3506 return (internal_equal(g1->image, g2->image, depth) &&
3507 internal_equal(g1->contrib_p, g2->contrib_p, depth) &&
3508 internal_equal(g1->baseline, g2->baseline, depth) &&
3509 internal_equal(g1->face, g2->face, depth) &&
3510 !plists_differ(g1->plist, g2->plist, 0, 0, depth + 1));
3513 static unsigned long glyph_hash(Lisp_Object obj, int depth)
3517 /* No need to hash all of the elements; that would take too long.
3518 Just hash the most common ones. */
3519 return HASH2(internal_hash(XGLYPH(obj)->image, depth),
3520 internal_hash(XGLYPH(obj)->face, depth));
3523 static Lisp_Object glyph_getprop(Lisp_Object obj, Lisp_Object prop)
3525 Lisp_Glyph *g = XGLYPH(obj);
3527 if (EQ(prop, Qimage))
3529 if (EQ(prop, Qcontrib_p))
3530 return g->contrib_p;
3531 if (EQ(prop, Qbaseline))
3533 if (EQ(prop, Qface))
3536 return external_plist_get(&g->plist, prop, 0, ERROR_ME);
3539 static int glyph_putprop(Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
3541 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3544 if (EQ(prop, Qface)) {
3545 XGLYPH(obj)->face = Fget_face(value);
3549 external_plist_put(&XGLYPH(obj)->plist, prop, value, 0, ERROR_ME);
3553 static int glyph_remprop(Lisp_Object obj, Lisp_Object prop)
3555 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3558 if (EQ(prop, Qface)) {
3559 XGLYPH(obj)->face = Qnil;
3563 return external_remprop(&XGLYPH(obj)->plist, prop, 0, ERROR_ME);
3566 static Lisp_Object glyph_plist(Lisp_Object obj)
3568 Lisp_Glyph *glyph = XGLYPH(obj);
3569 Lisp_Object result = glyph->plist;
3571 result = cons3(Qface, glyph->face, result);
3572 result = cons3(Qbaseline, glyph->baseline, result);
3573 result = cons3(Qcontrib_p, glyph->contrib_p, result);
3574 result = cons3(Qimage, glyph->image, result);
3579 static const struct lrecord_description glyph_description[] = {
3580 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, image)},
3581 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, contrib_p)},
3582 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, baseline)},
3583 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, face)},
3584 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, plist)},
3588 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS("glyph", glyph,
3589 mark_glyph, print_glyph, 0,
3590 glyph_equal, glyph_hash,
3591 glyph_description, glyph_getprop,
3592 glyph_putprop, glyph_remprop,
3593 glyph_plist, Lisp_Glyph);
3596 allocate_glyph(enum glyph_type type,
3597 void (*after_change) (Lisp_Object glyph, Lisp_Object property,
3598 Lisp_Object locale))
3600 /* This function can GC */
3601 Lisp_Object obj = Qnil;
3602 Lisp_Glyph *g = alloc_lcrecord_type(Lisp_Glyph, &lrecord_glyph);
3605 g->image = Fmake_specifier(Qimage); /* This function can GC */
3609 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3610 IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK
3611 | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
3612 | IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK;
3615 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3616 IMAGE_NOTHING_MASK | IMAGE_POINTER_MASK;
3619 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3620 IMAGE_NOTHING_MASK | IMAGE_MONO_PIXMAP_MASK
3621 | IMAGE_COLOR_PIXMAP_MASK;
3628 /* I think Fmake_specifier can GC. I think set_specifier_fallback can GC. */
3629 /* We're getting enough reports of odd behavior in this area it seems */
3630 /* best to GCPRO everything. */
3632 Lisp_Object tem1 = list1(Fcons(Qnil, Vthe_nothing_vector));
3633 Lisp_Object tem2 = list1(Fcons(Qnil, Qt));
3634 Lisp_Object tem3 = list1(Fcons(Qnil, Qnil));
3635 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3637 GCPRO4(obj, tem1, tem2, tem3);
3639 set_specifier_fallback(g->image, tem1);
3640 g->contrib_p = Fmake_specifier(Qboolean);
3641 set_specifier_fallback(g->contrib_p, tem2);
3642 /* #### should have a specifier for the following */
3643 g->baseline = Fmake_specifier(Qgeneric);
3644 set_specifier_fallback(g->baseline, tem3);
3647 g->after_change = after_change;
3650 set_image_attached_to(g->image, obj, Qimage);
3657 static enum glyph_type decode_glyph_type(Lisp_Object type, Error_behavior errb)
3660 return GLYPH_BUFFER;
3662 if (ERRB_EQ(errb, ERROR_ME))
3665 if (EQ(type, Qbuffer))
3666 return GLYPH_BUFFER;
3667 if (EQ(type, Qpointer))
3668 return GLYPH_POINTER;
3669 if (EQ(type, Qicon))
3672 maybe_signal_simple_error("Invalid glyph type", type, Qimage, errb);
3674 return GLYPH_UNKNOWN;
3677 static int valid_glyph_type_p(Lisp_Object type)
3679 return !NILP(memq_no_quit(type, Vglyph_type_list));
3682 DEFUN("valid-glyph-type-p", Fvalid_glyph_type_p, 1, 1, 0, /*
3683 Given a GLYPH-TYPE, return non-nil if it is valid.
3684 Valid types are `buffer', `pointer', and `icon'.
3688 return valid_glyph_type_p(glyph_type) ? Qt : Qnil;
3691 DEFUN("glyph-type-list", Fglyph_type_list, 0, 0, 0, /*
3692 Return a list of valid glyph types.
3696 return Fcopy_sequence(Vglyph_type_list);
3699 DEFUN("make-glyph-internal", Fmake_glyph_internal, 0, 1, 0, /*
3700 Create and return a new uninitialized glyph of type TYPE.
3702 TYPE specifies the type of the glyph; this should be one of `buffer',
3703 `pointer', or `icon', and defaults to `buffer'. The type of the glyph
3704 specifies in which contexts the glyph can be used, and controls the
3705 allowable image types into which the glyph's image can be
3708 `buffer' glyphs can be used as the begin-glyph or end-glyph of an
3709 extent, in the modeline, and in the toolbar. Their image can be
3710 instantiated as `nothing', `mono-pixmap', `color-pixmap', `text',
3713 `pointer' glyphs can be used to specify the mouse pointer. Their
3714 image can be instantiated as `pointer'.
3716 `icon' glyphs can be used to specify the icon used when a frame is
3717 iconified. Their image can be instantiated as `mono-pixmap' and
3722 enum glyph_type typeval = decode_glyph_type(type, ERROR_ME);
3723 return allocate_glyph(typeval, 0);
3726 DEFUN("glyphp", Fglyphp, 1, 1, 0, /*
3727 Return non-nil if OBJECT is a glyph.
3729 A glyph is an object used for pixmaps, widgets and the like. It is used
3730 in begin-glyphs and end-glyphs attached to extents, in marginal and textual
3731 annotations, in overlay arrows (overlay-arrow-* variables), in toolbar
3732 buttons, and the like. Much more detailed information can be found at
3733 `make-glyph'. Its image is described using an image specifier --
3734 see `make-image-specifier'. See also `make-image-instance' for further
3739 return GLYPHP(object) ? Qt : Qnil;
3742 DEFUN("glyph-type", Fglyph_type, 1, 1, 0, /*
3743 Return the type of the given glyph.
3744 The return value will be one of 'buffer, 'pointer, or 'icon.
3749 switch (XGLYPH_TYPE(glyph)) {
3763 glyph_image_instance(Lisp_Object glyph, Lisp_Object domain,
3764 Error_behavior errb, int no_quit)
3766 Lisp_Object specifier = GLYPH_IMAGE(XGLYPH(glyph));
3768 /* This can never return Qunbound. All glyphs have 'nothing as
3770 Lisp_Object image_instance = specifier_instance(specifier, Qunbound,
3771 domain, errb, no_quit,
3774 assert(!UNBOUNDP(image_instance));
3775 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
3777 return image_instance;
3781 glyph_image_instance_maybe(Lisp_Object glyph_or_image, Lisp_Object window)
3783 Lisp_Object instance = glyph_or_image;
3785 if (GLYPHP(glyph_or_image))
3787 glyph_image_instance(glyph_or_image, window, ERROR_ME_NOT,
3793 /*****************************************************************************
3796 Return the width of the given GLYPH on the given WINDOW.
3797 Calculations are done based on recursively querying the geometry of
3798 the associated image instances.
3799 ****************************************************************************/
3800 unsigned short glyph_width(Lisp_Object glyph_or_image, Lisp_Object domain)
3802 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3804 if (!IMAGE_INSTANCEP(instance))
3807 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3808 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3809 IMAGE_UNSPECIFIED_GEOMETRY,
3810 IMAGE_UNCHANGED_GEOMETRY,
3811 IMAGE_UNCHANGED_GEOMETRY, domain);
3813 return XIMAGE_INSTANCE_WIDTH(instance);
3816 DEFUN("glyph-width", Fglyph_width, 1, 2, 0, /*
3817 Return the width of GLYPH on WINDOW.
3818 This may not be exact as it does not take into account all of the context
3819 that redisplay will.
3823 XSETWINDOW(window, decode_window(window));
3826 return make_int(glyph_width(glyph, window));
3829 unsigned short glyph_ascent(Lisp_Object glyph_or_image, Lisp_Object domain)
3831 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3833 if (!IMAGE_INSTANCEP(instance))
3836 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3837 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3838 IMAGE_UNSPECIFIED_GEOMETRY,
3839 IMAGE_UNCHANGED_GEOMETRY,
3840 IMAGE_UNCHANGED_GEOMETRY, domain);
3842 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3843 return XIMAGE_INSTANCE_TEXT_ASCENT(instance);
3845 return XIMAGE_INSTANCE_HEIGHT(instance);
3848 unsigned short glyph_descent(Lisp_Object glyph_or_image, Lisp_Object domain)
3850 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3852 if (!IMAGE_INSTANCEP(instance))
3855 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3856 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3857 IMAGE_UNSPECIFIED_GEOMETRY,
3858 IMAGE_UNCHANGED_GEOMETRY,
3859 IMAGE_UNCHANGED_GEOMETRY, domain);
3861 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3862 return XIMAGE_INSTANCE_TEXT_DESCENT(instance);
3867 /* strictly a convenience function. */
3868 unsigned short glyph_height(Lisp_Object glyph_or_image, Lisp_Object domain)
3870 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3873 if (!IMAGE_INSTANCEP(instance))
3876 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3877 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3878 IMAGE_UNSPECIFIED_GEOMETRY,
3879 IMAGE_UNCHANGED_GEOMETRY,
3880 IMAGE_UNCHANGED_GEOMETRY, domain);
3882 return XIMAGE_INSTANCE_HEIGHT(instance);
3885 DEFUN("glyph-ascent", Fglyph_ascent, 1, 2, 0, /*
3886 Return the ascent value of GLYPH on WINDOW.
3887 This may not be exact as it does not take into account all of the context
3888 that redisplay will.
3892 XSETWINDOW(window, decode_window(window));
3895 return make_int(glyph_ascent(glyph, window));
3898 DEFUN("glyph-descent", Fglyph_descent, 1, 2, 0, /*
3899 Return the descent value of GLYPH on WINDOW.
3900 This may not be exact as it does not take into account all of the context
3901 that redisplay will.
3905 XSETWINDOW(window, decode_window(window));
3908 return make_int(glyph_descent(glyph, window));
3911 /* This is redundant but I bet a lot of people expect it to exist. */
3912 DEFUN("glyph-height", Fglyph_height, 1, 2, 0, /*
3913 Return the height of GLYPH on WINDOW.
3914 This may not be exact as it does not take into account all of the context
3915 that redisplay will.
3919 XSETWINDOW(window, decode_window(window));
3922 return make_int(glyph_height(glyph, window));
3926 set_glyph_dirty_p(Lisp_Object glyph_or_image, Lisp_Object window, int dirty)
3928 Lisp_Object instance = glyph_or_image;
3930 if (!NILP(glyph_or_image)) {
3931 if (GLYPHP(glyph_or_image)) {
3932 instance = glyph_image_instance(glyph_or_image, window,
3934 XGLYPH_DIRTYP(glyph_or_image) = dirty;
3937 if (!IMAGE_INSTANCEP(instance))
3940 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3944 static void set_image_instance_dirty_p(Lisp_Object instance, int dirty)
3946 if (IMAGE_INSTANCEP(instance)) {
3947 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3948 /* Now cascade up the hierarchy. */
3949 set_image_instance_dirty_p(XIMAGE_INSTANCE_PARENT(instance),
3951 } else if (GLYPHP(instance)) {
3952 XGLYPH_DIRTYP(instance) = dirty;
3956 /* #### do we need to cache this info to speed things up? */
3958 Lisp_Object glyph_baseline(Lisp_Object glyph, Lisp_Object domain)
3963 Lisp_Object retval =
3964 specifier_instance_no_quit(GLYPH_BASELINE(XGLYPH(glyph)),
3965 /* #### look into ERROR_ME_NOT */
3966 Qunbound, domain, ERROR_ME_NOT,
3968 if (!NILP(retval) && !INTP(retval))
3970 else if (INTP(retval)) {
3971 if (XINT(retval) < 0)
3973 if (XINT(retval) > 100)
3974 retval = make_int(100);
3980 Lisp_Object glyph_face(Lisp_Object glyph, Lisp_Object domain)
3982 /* #### Domain parameter not currently used but it will be */
3983 return GLYPHP(glyph) ? GLYPH_FACE(XGLYPH(glyph)) : Qnil;
3986 int glyph_contrib_p(Lisp_Object glyph, Lisp_Object domain)
3991 return !NILP(specifier_instance_no_quit
3992 (GLYPH_CONTRIB_P(XGLYPH(glyph)), Qunbound, domain,
3993 /* #### look into ERROR_ME_NOT */
3994 ERROR_ME_NOT, 0, Qzero));
3998 glyph_property_was_changed(Lisp_Object glyph, Lisp_Object property,
4001 if (XGLYPH(glyph)->after_change)
4002 (XGLYPH(glyph)->after_change) (glyph, property, locale);
4006 glyph_query_geometry(Lisp_Object glyph_or_image, int *width, int *height,
4007 enum image_instance_geometry disp, Lisp_Object domain)
4009 Lisp_Object instance = glyph_or_image;
4011 if (GLYPHP(glyph_or_image))
4013 glyph_image_instance(glyph_or_image, domain, ERROR_ME_NOT,
4016 image_instance_query_geometry(instance, width, height, disp, domain);
4020 glyph_do_layout(Lisp_Object glyph_or_image, int width, int height,
4021 int xoffset, int yoffset, Lisp_Object domain)
4023 Lisp_Object instance = glyph_or_image;
4025 if (GLYPHP(glyph_or_image))
4027 glyph_image_instance(glyph_or_image, domain, ERROR_ME_NOT,
4030 image_instance_layout(instance, width, height, xoffset, yoffset,
4034 /*****************************************************************************
4035 * glyph cachel functions *
4036 *****************************************************************************/
4038 /* #### All of this is 95% copied from face cachels. Consider
4041 Why do we need glyph_cachels? Simply because a glyph_cachel captures
4042 per-window information about a particular glyph. A glyph itself is
4043 not created in any particular context, so if we were to rely on a
4044 glyph to tell us about its dirtiness we would not be able to reset
4045 the dirty flag after redisplaying it as it may exist in other
4046 contexts. When we have redisplayed we need to know which glyphs to
4047 reset the dirty flags on - the glyph_cachels give us a nice list we
4048 can iterate through doing this. */
4049 void mark_glyph_cachels(glyph_cachel_dynarr * elements)
4056 for (elt = 0; elt < Dynarr_length(elements); elt++) {
4057 struct glyph_cachel *cachel = Dynarr_atp(elements, elt);
4058 mark_object(cachel->glyph);
4063 update_glyph_cachel_data(struct window *w, Lisp_Object glyph,
4064 struct glyph_cachel *cachel)
4066 if (!cachel->updated || NILP(cachel->glyph) || !EQ(cachel->glyph, glyph)
4067 || XGLYPH_DIRTYP(cachel->glyph)
4068 || XFRAME(WINDOW_FRAME(w))->faces_changed) {
4069 Lisp_Object window, instance;
4071 XSETWINDOW(window, w);
4073 cachel->glyph = glyph;
4074 /* Speed things up slightly by grabbing the glyph instantiation
4075 and passing it to the size functions. */
4076 instance = glyph_image_instance(glyph, window, ERROR_ME_NOT, 1);
4078 if (!IMAGE_INSTANCEP(instance))
4081 /* Mark text instance of the glyph dirty if faces have changed,
4082 because its geometry might have changed. */
4083 invalidate_glyph_geometry_maybe(instance, w);
4085 /* #### Do the following 2 lines buy us anything? --kkm */
4086 XGLYPH_DIRTYP(glyph) = XIMAGE_INSTANCE_DIRTYP(instance);
4087 cachel->dirty = XGLYPH_DIRTYP(glyph);
4088 cachel->width = glyph_width(instance, window);
4089 cachel->ascent = glyph_ascent(instance, window);
4090 cachel->descent = glyph_descent(instance, window);
4093 cachel->updated = 1;
4096 static void add_glyph_cachel(struct window *w, Lisp_Object glyph)
4098 struct glyph_cachel new_cachel;
4101 new_cachel.glyph = Qnil;
4103 update_glyph_cachel_data(w, glyph, &new_cachel);
4104 Dynarr_add(w->glyph_cachels, new_cachel);
4107 glyph_index get_glyph_cachel_index(struct window *w, Lisp_Object glyph)
4114 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4115 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4117 if (EQ(cachel->glyph, glyph) && !NILP(glyph)) {
4118 update_glyph_cachel_data(w, glyph, cachel);
4123 /* If we didn't find the glyph, add it and then return its index. */
4124 add_glyph_cachel(w, glyph);
4128 void reset_glyph_cachels(struct window *w)
4130 Dynarr_reset(w->glyph_cachels);
4131 get_glyph_cachel_index(w, Vcontinuation_glyph);
4132 get_glyph_cachel_index(w, Vtruncation_glyph);
4133 get_glyph_cachel_index(w, Vhscroll_glyph);
4134 get_glyph_cachel_index(w, Vcontrol_arrow_glyph);
4135 get_glyph_cachel_index(w, Voctal_escape_glyph);
4136 get_glyph_cachel_index(w, Vinvisible_text_glyph);
4139 void mark_glyph_cachels_as_not_updated(struct window *w)
4143 /* We need to have a dirty flag to tell if the glyph has changed.
4144 We can check to see if each glyph variable is actually a
4145 completely different glyph, though. */
4146 #define FROB(glyph_obj, gindex) \
4147 update_glyph_cachel_data (w, glyph_obj, \
4148 Dynarr_atp (w->glyph_cachels, gindex))
4150 FROB(Vcontinuation_glyph, CONT_GLYPH_INDEX);
4151 FROB(Vtruncation_glyph, TRUN_GLYPH_INDEX);
4152 FROB(Vhscroll_glyph, HSCROLL_GLYPH_INDEX);
4153 FROB(Vcontrol_arrow_glyph, CONTROL_GLYPH_INDEX);
4154 FROB(Voctal_escape_glyph, OCT_ESC_GLYPH_INDEX);
4155 FROB(Vinvisible_text_glyph, INVIS_GLYPH_INDEX);
4158 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4159 Dynarr_atp(w->glyph_cachels, elt)->updated = 0;
4163 /* Unset the dirty bit on all the glyph cachels that have it. */
4164 void mark_glyph_cachels_as_clean(struct window *w)
4168 XSETWINDOW(window, w);
4169 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4170 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4172 set_glyph_dirty_p(cachel->glyph, window, 0);
4176 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
4179 compute_glyph_cachel_usage(glyph_cachel_dynarr * glyph_cachels,
4180 struct overhead_stats *ovstats)
4185 total += Dynarr_memory_usage(glyph_cachels, ovstats);
4190 #endif /* MEMORY_USAGE_STATS */
4192 /*****************************************************************************
4193 * subwindow cachel functions *
4194 *****************************************************************************/
4195 /* Subwindows are curious in that you have to physically unmap them to
4196 not display them. It is problematic deciding what to do in
4197 redisplay. We have two caches - a per-window instance cache that
4198 keeps track of subwindows on a window, these are linked to their
4199 instantiator in the hashtable and when the instantiator goes away
4200 we want the instance to go away also. However we also have a
4201 per-frame instance cache that we use to determine if a subwindow is
4202 obscuring an area that we want to clear. We need to be able to flip
4203 through this quickly so a hashtable is not suitable hence the
4204 subwindow_cachels. This is a weak list so unreference instances
4205 will get deleted properly. */
4207 /* redisplay in general assumes that drawing something will erase
4208 what was there before. unfortunately this does not apply to
4209 subwindows that need to be specifically unmapped in order to
4210 disappear. we take a brute force approach - on the basis that its
4211 cheap - and unmap all subwindows in a display line */
4213 /* Put new instances in the frame subwindow cache. This is less costly than
4214 doing it every time something gets mapped, and deleted instances will be
4215 removed automatically. */
4216 static void cache_subwindow_instance_in_frame_maybe(Lisp_Object instance)
4218 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(instance);
4219 if (!NILP(DOMAIN_FRAME(IMAGE_INSTANCE_DOMAIN(ii)))) {
4220 struct frame *f = DOMAIN_XFRAME(IMAGE_INSTANCE_DOMAIN(ii));
4221 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4223 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f)));
4227 /* Unmap and finalize all subwindow instances in the frame cache. This
4228 is necessary because GC will not guarantee the order things get
4229 deleted in and moreover, frame finalization deletes the window
4230 system windows before deleting SXEmacs windows, and hence
4233 unmap_subwindow_instance_cache_mapper(Lisp_Object key, Lisp_Object value,
4236 /* value can be nil; we cache failures as well as successes */
4238 struct frame *f = XFRAME(XIMAGE_INSTANCE_FRAME(value));
4239 unmap_subwindow(value);
4241 /* In case GC doesn't catch up fast enough, remove from the frame
4242 cache also. Otherwise code that checks the sanity of the instance
4244 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4245 = delq_no_quit(value,
4246 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE
4248 finalize_image_instance(XIMAGE_INSTANCE(value), 0);
4254 static void finalize_all_subwindow_instances(struct window *w)
4257 finalize_all_subwindow_instances(XWINDOW(w->next));
4258 if (!NILP(w->vchild))
4259 finalize_all_subwindow_instances(XWINDOW(w->vchild));
4260 if (!NILP(w->hchild))
4261 finalize_all_subwindow_instances(XWINDOW(w->hchild));
4263 elisp_maphash(unmap_subwindow_instance_cache_mapper,
4264 w->subwindow_instance_cache, (void *)1);
4267 void free_frame_subwindow_instances(struct frame *f)
4269 /* Make sure all instances are finalized. We have to do this via the
4270 instance cache since some instances may be extant but not
4271 displayed (and hence not in the frame cache). */
4272 finalize_all_subwindow_instances(XWINDOW(f->root_window));
4275 /* Unmap all instances in the frame cache. */
4276 void reset_frame_subwindow_instance_cache(struct frame *f)
4280 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4281 Lisp_Object value = XCAR(rest);
4282 unmap_subwindow(value);
4286 /*****************************************************************************
4287 * subwindow exposure ignorance *
4288 *****************************************************************************/
4289 /* when we unmap subwindows the associated window system will generate
4290 expose events. This we do not want as redisplay already copes with
4291 the repainting necessary. Worse, we can get in an endless cycle of
4292 redisplay if we are not careful. Thus we keep a per-frame list of
4293 expose events that are going to come and ignore them as
4296 struct expose_ignore_blocktype {
4297 Blocktype_declare(struct expose_ignore);
4298 } *the_expose_ignore_blocktype;
4301 check_for_ignored_expose(struct frame *f, int x, int y, int width, int height)
4303 struct expose_ignore *ei, *prev;
4304 /* the ignore list is FIFO so we should generally get a match with
4305 the first element in the list */
4306 for (ei = f->subwindow_exposures, prev = 0; ei; ei = ei->next) {
4307 /* Checking for exact matches just isn't good enough as we
4308 might get exposures for partially obscured subwindows, thus
4309 we have to check for overlaps. Being conservative, we will
4310 check for exposures wholly contained by the subwindow - this
4311 might give us what we want. */
4312 if (ei->x <= (unsigned)x && ei->y <= (unsigned)y
4313 && ei->x + ei->width >= (unsigned)(x + width)
4314 && ei->y + ei->height >= (unsigned)(y + height)) {
4315 #ifdef DEBUG_WIDGETS
4317 ("ignored %d+%d, %dx%d for exposure %d+%d, %dx%d\n",
4318 x, y, width, height, ei->x, ei->y, ei->width,
4322 f->subwindow_exposures = ei->next;
4324 prev->next = ei->next;
4326 if (ei == f->subwindow_exposures_tail)
4327 f->subwindow_exposures_tail = prev;
4329 Blocktype_free(the_expose_ignore_blocktype, ei);
4338 register_ignored_expose(struct frame *f, int x, int y, int width, int height)
4340 if (!hold_ignored_expose_registration) {
4341 struct expose_ignore *ei;
4343 ei = Blocktype_alloc(the_expose_ignore_blocktype);
4349 ei->height = height;
4351 /* we have to add the exposure to the end of the list, since we
4352 want to check the oldest events first. for speed we keep a record
4353 of the end so that we can add right to it. */
4354 if (f->subwindow_exposures_tail) {
4355 f->subwindow_exposures_tail->next = ei;
4357 if (!f->subwindow_exposures) {
4358 f->subwindow_exposures = ei;
4360 f->subwindow_exposures_tail = ei;
4364 /****************************************************************************
4365 find_matching_subwindow
4367 See if there is a subwindow that completely encloses the requested
4369 ****************************************************************************/
4370 int find_matching_subwindow(struct frame *f, int x, int y, int width,
4375 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4376 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(XCAR(rest));
4378 if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii)
4380 IMAGE_INSTANCE_DISPLAY_X(ii) <= (unsigned)x
4382 IMAGE_INSTANCE_DISPLAY_Y(ii) <= (unsigned)y
4383 && IMAGE_INSTANCE_DISPLAY_X(ii)
4384 + IMAGE_INSTANCE_DISPLAY_WIDTH(ii) >= (unsigned)(x + width)
4385 && IMAGE_INSTANCE_DISPLAY_Y(ii)
4386 + IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) >=
4387 (unsigned)(y + height)) {
4394 /*****************************************************************************
4395 * subwindow functions *
4396 *****************************************************************************/
4398 /* Update the displayed characteristics of a subwindow. This function
4399 should generally only get called if the subwindow is actually
4401 void redisplay_subwindow(Lisp_Object subwindow)
4403 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4404 int count = specpdl_depth();
4406 /* The update method is allowed to call eval. Since it is quite
4407 common for this function to get called from somewhere in
4408 redisplay we need to make sure that quits are ignored. Otherwise
4409 Fsignal will abort. */
4410 specbind(Qinhibit_quit, Qt);
4412 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4414 if (WIDGET_IMAGE_INSTANCEP(subwindow)) {
4415 if (image_instance_changed(subwindow))
4416 redisplay_widget(subwindow);
4417 /* Reset the changed flags. */
4418 IMAGE_INSTANCE_WIDGET_FACE_CHANGED(ii) = 0;
4419 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii) = 0;
4420 IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii) = 0;
4421 IMAGE_INSTANCE_TEXT_CHANGED(ii) = 0;
4422 } else if (IMAGE_INSTANCE_TYPE(ii) == IMAGE_SUBWINDOW
4423 && !NILP(IMAGE_INSTANCE_FRAME(ii))) {
4424 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4425 redisplay_subwindow, (ii));
4428 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 0;
4429 /* This function is typically called by redisplay just before
4430 outputting the information to the screen. Thus we record a hash
4431 of the output to determine whether on-screen is the same as
4432 recorded structure. This approach has limitations in there is a
4433 good chance that hash values will be different for the same
4434 visual appearance. However, we would rather that then the other
4435 way round - it simply means that we will get more displays than
4436 we might need. We can get better hashing by making the depth
4437 negative - currently it will recurse down 7 levels. */
4438 IMAGE_INSTANCE_DISPLAY_HASH(ii) = internal_hash(subwindow,
4439 IMAGE_INSTANCE_HASH_DEPTH);
4441 unbind_to(count, Qnil);
4444 /* Determine whether an image_instance has changed structurally and
4445 hence needs redisplaying in some way.
4447 #### This should just look at the instantiator differences when we
4448 get rid of the stored items altogether. In fact we should probably
4449 store the new instantiator as well as the old - as we do with
4450 gui_items currently - and then pick-up the new on the next
4451 redisplay. This would obviate the need for any of this trickery
4453 int image_instance_changed(Lisp_Object subwindow)
4455 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4457 if (internal_hash(subwindow, IMAGE_INSTANCE_HASH_DEPTH) !=
4458 IMAGE_INSTANCE_DISPLAY_HASH(ii))
4460 /* #### I think there is probably a bug here. This gets called for
4461 layouts - and yet the pending items are always nil for
4462 layouts. We are saved by layout optimization, but I'm undecided
4463 as to what the correct fix is. */
4464 else if (WIDGET_IMAGE_INSTANCEP(subwindow)
4465 && (!internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(ii),
4466 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii), 0)
4467 || !NILP(IMAGE_INSTANCE_LAYOUT_CHILDREN(ii))
4468 || IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii)))
4474 /* Update all the subwindows on a frame. */
4475 void update_widget_instances(Lisp_Object frame)
4480 /* Its possible for the preceding callback to have deleted the
4481 frame, so cope with this. */
4482 if (!FRAMEP(frame) || !FRAME_LIVE_P(XFRAME(frame)))
4488 /* If we get called we know something has changed. */
4489 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4490 Lisp_Object widget = XCAR(rest);
4492 if (XIMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(widget)
4493 && image_instance_changed(widget)) {
4494 set_image_instance_dirty_p(widget, 1);
4495 MARK_FRAME_GLYPHS_CHANGED(f);
4500 /* remove a subwindow from its frame */
4501 void unmap_subwindow(Lisp_Object subwindow)
4503 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4506 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4508 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4509 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK))
4510 || !IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii))
4513 #ifdef DEBUG_WIDGETS
4514 stderr_out("unmapping subwindow %p\n", IMAGE_INSTANCE_SUBWINDOW_ID(ii));
4516 f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
4518 /* make sure we don't get expose events */
4519 register_ignored_expose(f, IMAGE_INSTANCE_DISPLAY_X(ii),
4520 IMAGE_INSTANCE_DISPLAY_Y(ii),
4521 IMAGE_INSTANCE_DISPLAY_WIDTH(ii),
4522 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii));
4523 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4525 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(ii)),
4526 unmap_subwindow, (ii));
4529 /* show a subwindow in its frame */
4530 void map_subwindow(Lisp_Object subwindow, int x, int y,
4531 struct display_glyph_area *dga)
4533 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4535 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4537 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4538 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK)))
4541 #ifdef DEBUG_WIDGETS
4542 stderr_out("mapping subwindow %p, %dx%d@%d+%d\n",
4543 IMAGE_INSTANCE_SUBWINDOW_ID(ii),
4544 dga->width, dga->height, x, y);
4546 (void)XFRAME(IMAGE_INSTANCE_FRAME(ii));
4547 IMAGE_INSTANCE_DISPLAY_X(ii) = x;
4548 IMAGE_INSTANCE_DISPLAY_Y(ii) = y;
4549 IMAGE_INSTANCE_DISPLAY_WIDTH(ii) = dga->width;
4550 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) = dga->height;
4552 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4553 map_subwindow, (ii, x, y, dga));
4554 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 1;
4557 static int subwindow_possible_dest_types(void)
4559 return IMAGE_SUBWINDOW_MASK;
4562 int subwindow_governing_domain(void)
4564 return GOVERNING_DOMAIN_WINDOW;
4567 /* Partially instantiate a subwindow. */
4569 subwindow_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
4570 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
4571 int dest_mask, Lisp_Object domain)
4573 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
4574 Lisp_Object device = image_instance_device(image_instance);
4575 Lisp_Object frame = DOMAIN_FRAME(domain);
4576 Lisp_Object width = find_keyword_in_vector(instantiator, Q_pixel_width);
4577 Lisp_Object height =
4578 find_keyword_in_vector(instantiator, Q_pixel_height);
4581 signal_simple_error("No selected frame", device);
4583 if (!(dest_mask & IMAGE_SUBWINDOW_MASK))
4584 incompatible_image_types(instantiator, dest_mask,
4585 IMAGE_SUBWINDOW_MASK);
4588 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = 0;
4589 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4593 if (XINT(width) > 1)
4595 IMAGE_INSTANCE_WIDTH(ii) = w;
4596 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP(ii) = 0;
4601 if (XINT(height) > 1)
4603 IMAGE_INSTANCE_HEIGHT(ii) = h;
4604 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP(ii) = 0;
4608 #ifdef HAVE_X_WINDOWS
4609 extern void x_subwindow_query_geometry(Lisp_Object image_instance,
4610 int *width, int *height);
4613 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4614 int *height, enum image_instance_geometry disp,
4617 if (IMAGE_INSTANCE_INITIALIZED(XIMAGE_INSTANCE(image_instance)))
4619 /* Query real size of subwindow */
4620 x_subwindow_query_geometry(image_instance, width, height);
4622 /* Set them in case of initial layout instantiation */
4630 /* This is just a backup in case no-one has assigned a suitable geometry.
4631 #### It should really query the enclose window for geometry. */
4633 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4634 int *height, enum image_instance_geometry disp,
4642 #endif /* HAVE_X_WINDOWS */
4644 DEFUN("subwindowp", Fsubwindowp, 1, 1, 0, /*
4645 Return non-nil if OBJECT is a subwindow.
4649 CHECK_IMAGE_INSTANCE(object);
4650 return (XIMAGE_INSTANCE_TYPE(object) == IMAGE_SUBWINDOW) ? Qt : Qnil;
4653 DEFUN("image-instance-subwindow-id", Fimage_instance_subwindow_id, 1, 1, 0, /*
4654 Return the window id of SUBWINDOW as a number.
4658 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4659 return make_int((EMACS_INT) XIMAGE_INSTANCE_SUBWINDOW_ID(subwindow));
4662 DEFUN("resize-subwindow", Fresize_subwindow, 1, 3, 0, /*
4663 Resize SUBWINDOW to WIDTH x HEIGHT.
4664 If a value is nil that parameter is not changed.
4666 (subwindow, width, height))
4669 Lisp_Image_Instance *ii;
4671 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4672 ii = XIMAGE_INSTANCE(subwindow);
4675 neww = IMAGE_INSTANCE_WIDTH(ii);
4680 newh = IMAGE_INSTANCE_HEIGHT(ii);
4682 newh = XINT(height);
4684 /* The actual resizing gets done asynchronously by
4685 update_subwindow. */
4686 IMAGE_INSTANCE_HEIGHT(ii) = newh;
4687 IMAGE_INSTANCE_WIDTH(ii) = neww;
4688 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
4693 DEFUN("force-subwindow-map", Fforce_subwindow_map, 1, 1, 0, /*
4694 Generate a Map event for SUBWINDOW.
4698 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4700 map_subwindow(subwindow, 0, 0);
4705 /*****************************************************************************
4707 *****************************************************************************/
4709 /* Get the display tables for use currently on window W with face
4710 FACE. #### This will have to be redone. */
4713 get_display_tables(struct window *w, face_index findex,
4714 Lisp_Object * face_table, Lisp_Object * window_table)
4717 tem = WINDOW_FACE_CACHEL_DISPLAY_TABLE(w, findex);
4721 tem = noseeum_cons(tem, Qnil);
4723 tem = w->display_table;
4727 tem = noseeum_cons(tem, Qnil);
4728 *window_table = tem;
4732 display_table_entry(Emchar ch, Lisp_Object face_table, Lisp_Object window_table)
4736 /* Loop over FACE_TABLE, and then over WINDOW_TABLE. */
4737 for (tail = face_table; 1; tail = XCDR(tail)) {
4740 if (!NILP(window_table)) {
4741 tail = window_table;
4742 window_table = Qnil;
4748 if (VECTORP(table)) {
4749 if (ch < XVECTOR_LENGTH(table)
4750 && !NILP(XVECTOR_DATA(table)[ch]))
4751 return XVECTOR_DATA(table)[ch];
4754 } else if (CHAR_TABLEP(table)
4755 && XCHAR_TABLE_TYPE(table) == CHAR_TABLE_TYPE_CHAR) {
4756 return get_char_table(ch, XCHAR_TABLE(table));
4757 } else if (CHAR_TABLEP(table)
4758 && XCHAR_TABLE_TYPE(table) ==
4759 CHAR_TABLE_TYPE_GENERIC) {
4761 get_char_table(ch, XCHAR_TABLE(table));
4766 } else if (RANGE_TABLEP(table)) {
4768 Fget_range_table(make_char(ch), table, Qnil);
4778 /*****************************************************************************
4779 * timeouts for animated glyphs *
4780 *****************************************************************************/
4781 static Lisp_Object Qglyph_animated_timeout_handler;
4783 DEFUN("glyph-animated-timeout-handler", Fglyph_animated_timeout_handler, 1, 1, 0, /*
4784 Callback function for updating animated images.
4789 CHECK_WEAK_LIST(arg);
4791 if (!NILP(XWEAK_LIST_LIST(arg)) && !NILP(XCAR(XWEAK_LIST_LIST(arg)))) {
4792 Lisp_Object value = XCAR(XWEAK_LIST_LIST(arg));
4794 if (IMAGE_INSTANCEP(value)) {
4795 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(value);
4797 if (COLOR_PIXMAP_IMAGE_INSTANCEP(value)
4799 IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii) > 1
4800 && !disable_animated_pixmaps) {
4802 /* Increment the index of the image slice we are
4803 currently viewing. */
4804 IMAGE_INSTANCE_PIXMAP_SLICE(ii) =
4805 (IMAGE_INSTANCE_PIXMAP_SLICE(ii) + 1)
4806 % IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii);
4807 /* We might need to kick redisplay at this point
4808 - but we also might not. */
4809 tmp = image_instance_device(value);
4810 MARK_DEVICE_FRAMES_GLYPHS_CHANGED(XDEVICE(tmp));
4811 /* Cascade dirtiness so that we can have an
4812 animated glyph in a layout for instance. */
4813 set_image_instance_dirty_p(value, 1);
4820 Lisp_Object add_glyph_animated_timeout(EMACS_INT tickms, Lisp_Object image)
4822 Lisp_Object ret = Qnil;
4824 if (tickms > 0 && IMAGE_INSTANCEP(image)) {
4825 double ms = ((double)tickms) / 1000.0;
4826 struct gcpro gcpro1;
4827 Lisp_Object holder = make_weak_list(WEAK_LIST_SIMPLE);
4830 XWEAK_LIST_LIST(holder) = Fcons(image, Qnil);
4832 ret = Fadd_timeout(make_float(ms),
4833 Qglyph_animated_timeout_handler,
4834 holder, make_float(ms));
4841 void disable_glyph_animated_timeout(int i)
4846 Fdisable_timeout(id);
4849 /*****************************************************************************
4851 *****************************************************************************/
4853 void syms_of_glyphs(void)
4855 INIT_LRECORD_IMPLEMENTATION(glyph);
4856 INIT_LRECORD_IMPLEMENTATION(image_instance);
4858 /* image instantiators */
4860 DEFSUBR(Fimage_instantiator_format_list);
4861 DEFSUBR(Fvalid_image_instantiator_format_p);
4862 DEFSUBR(Fset_console_type_image_conversion_list);
4863 DEFSUBR(Fconsole_type_image_conversion_list);
4866 DEFKEYWORD(Q_pixel_height);
4867 DEFKEYWORD(Q_pixel_width);
4870 DEFKEYWORD(Q_color_symbols);
4873 DEFKEYWORD(Q_mask_file);
4874 DEFKEYWORD(Q_mask_data);
4875 DEFKEYWORD(Q_hotspot_x);
4876 DEFKEYWORD(Q_hotspot_y);
4877 DEFKEYWORD(Q_foreground);
4878 DEFKEYWORD(Q_background);
4880 /* image specifiers */
4882 DEFSUBR(Fimage_specifier_p);
4883 /* Qimage in general.c */
4885 /* image instances */
4887 defsymbol(&Qimage_instancep, "image-instance-p");
4889 DEFSYMBOL(Qnothing_image_instance_p);
4890 DEFSYMBOL(Qtext_image_instance_p);
4891 DEFSYMBOL(Qmono_pixmap_image_instance_p);
4892 DEFSYMBOL(Qcolor_pixmap_image_instance_p);
4893 DEFSYMBOL(Qpointer_image_instance_p);
4894 DEFSYMBOL(Qwidget_image_instance_p);
4895 DEFSYMBOL(Qsubwindow_image_instance_p);
4897 DEFSUBR(Fmake_image_instance);
4898 DEFSUBR(Fimage_instance_p);
4899 DEFSUBR(Fimage_instance_type);
4900 DEFSUBR(Fvalid_image_instance_type_p);
4901 DEFSUBR(Fimage_instance_type_list);
4902 DEFSUBR(Fimage_instance_name);
4903 DEFSUBR(Fimage_instance_domain);
4904 DEFSUBR(Fimage_instance_string);
4905 DEFSUBR(Fimage_instance_file_name);
4906 DEFSUBR(Fimage_instance_mask_file_name);
4907 DEFSUBR(Fimage_instance_depth);
4908 DEFSUBR(Fimage_instance_height);
4909 DEFSUBR(Fimage_instance_width);
4910 DEFSUBR(Fimage_instance_hotspot_x);
4911 DEFSUBR(Fimage_instance_hotspot_y);
4912 DEFSUBR(Fimage_instance_foreground);
4913 DEFSUBR(Fimage_instance_background);
4914 DEFSUBR(Fimage_instance_property);
4915 DEFSUBR(Fcolorize_image_instance);
4917 DEFSUBR(Fsubwindowp);
4918 DEFSUBR(Fimage_instance_subwindow_id);
4919 DEFSUBR(Fresize_subwindow);
4920 DEFSUBR(Fforce_subwindow_map);
4922 /* Qnothing defined as part of the "nothing" image-instantiator
4924 /* Qtext defined in general.c */
4925 DEFSYMBOL(Qmono_pixmap);
4926 DEFSYMBOL(Qcolor_pixmap);
4927 /* Qpointer defined in general.c */
4932 DEFSYMBOL(Qcontrib_p);
4933 DEFSYMBOL(Qbaseline);
4935 DEFSYMBOL(Qbuffer_glyph_p);
4936 DEFSYMBOL(Qpointer_glyph_p);
4937 DEFSYMBOL(Qicon_glyph_p);
4939 DEFSYMBOL(Qconst_glyph_variable);
4941 DEFSUBR(Fglyph_type);
4942 DEFSUBR(Fvalid_glyph_type_p);
4943 DEFSUBR(Fglyph_type_list);
4945 DEFSUBR(Fmake_glyph_internal);
4946 DEFSUBR(Fglyph_width);
4947 DEFSUBR(Fglyph_ascent);
4948 DEFSUBR(Fglyph_descent);
4949 DEFSUBR(Fglyph_height);
4950 DEFSUBR(Fset_instantiator_property);
4952 /* Qbuffer defined in general.c. */
4953 /* Qpointer defined above */
4955 /* Unfortunately, timeout handlers must be lisp functions. This is
4956 for animated glyphs. */
4957 DEFSYMBOL(Qglyph_animated_timeout_handler);
4958 DEFSUBR(Fglyph_animated_timeout_handler);
4961 DEFERROR_STANDARD(Qimage_conversion_error, Qio_error);
4964 static const struct lrecord_description image_specifier_description[] = {
4966 specifier_data_offset + offsetof(struct image_specifier, attachee)},
4968 specifier_data_offset + offsetof(struct image_specifier,
4969 attachee_property)},
4973 void specifier_type_create_image(void)
4975 /* image specifiers */
4977 INITIALIZE_SPECIFIER_TYPE_WITH_DATA(image, "image", "imagep");
4979 SPECIFIER_HAS_METHOD(image, create);
4980 SPECIFIER_HAS_METHOD(image, mark);
4981 SPECIFIER_HAS_METHOD(image, instantiate);
4982 SPECIFIER_HAS_METHOD(image, validate);
4983 SPECIFIER_HAS_METHOD(image, after_change);
4984 SPECIFIER_HAS_METHOD(image, going_to_add);
4985 SPECIFIER_HAS_METHOD(image, copy_instantiator);
4988 void reinit_specifier_type_create_image(void)
4990 REINITIALIZE_SPECIFIER_TYPE(image);
4993 static const struct lrecord_description iike_description_1[] = {
4994 {XD_LISP_OBJECT, offsetof(ii_keyword_entry, keyword)},
4998 static const struct struct_description iike_description = {
4999 sizeof(ii_keyword_entry),
5003 static const struct lrecord_description iiked_description_1[] = {
5004 XD_DYNARR_DESC(ii_keyword_entry_dynarr, &iike_description),
5008 static const struct struct_description iiked_description = {
5009 sizeof(ii_keyword_entry_dynarr),
5013 static const struct lrecord_description iife_description_1[] = {
5014 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, symbol)},
5015 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, device)},
5016 {XD_STRUCT_PTR, offsetof(image_instantiator_format_entry, meths), 1,
5021 static const struct struct_description iife_description = {
5022 sizeof(image_instantiator_format_entry),
5026 static const struct lrecord_description iifed_description_1[] = {
5027 XD_DYNARR_DESC(image_instantiator_format_entry_dynarr,
5032 static const struct struct_description iifed_description = {
5033 sizeof(image_instantiator_format_entry_dynarr),
5037 static const struct lrecord_description iim_description_1[] = {
5038 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, symbol)},
5039 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, device)},
5040 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, keywords),
5041 1, &iiked_description},
5042 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, consoles),
5043 1, &cted_description},
5047 const struct struct_description iim_description = {
5048 sizeof(struct image_instantiator_methods),
5052 void image_instantiator_format_create(void)
5054 /* image instantiators */
5056 the_image_instantiator_format_entry_dynarr =
5057 Dynarr_new(image_instantiator_format_entry);
5059 Vimage_instantiator_format_list = Qnil;
5060 staticpro(&Vimage_instantiator_format_list);
5062 dump_add_root_struct_ptr(&the_image_instantiator_format_entry_dynarr,
5063 &iifed_description);
5065 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(nothing, "nothing");
5067 IIFORMAT_HAS_METHOD(nothing, possible_dest_types);
5068 IIFORMAT_HAS_METHOD(nothing, instantiate);
5070 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(inherit, "inherit");
5072 IIFORMAT_HAS_METHOD(inherit, validate);
5073 IIFORMAT_HAS_METHOD(inherit, normalize);
5074 IIFORMAT_HAS_METHOD(inherit, possible_dest_types);
5075 IIFORMAT_HAS_METHOD(inherit, instantiate);
5077 IIFORMAT_VALID_KEYWORD(inherit, Q_face, check_valid_face);
5079 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(string, "string");
5081 IIFORMAT_HAS_METHOD(string, validate);
5082 IIFORMAT_HAS_SHARED_METHOD(string, governing_domain, subwindow);
5083 IIFORMAT_HAS_METHOD(string, possible_dest_types);
5084 IIFORMAT_HAS_METHOD(string, instantiate);
5086 IIFORMAT_VALID_KEYWORD(string, Q_data, check_valid_string);
5087 /* Do this so we can set strings. */
5088 /* #### Andy, what is this? This is a bogus format and should not be
5089 visible to the user. */
5090 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(text, "text");
5091 IIFORMAT_HAS_METHOD(text, update);
5092 IIFORMAT_HAS_METHOD(text, query_geometry);
5094 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(formatted_string,
5095 "formatted-string");
5097 IIFORMAT_HAS_METHOD(formatted_string, validate);
5098 IIFORMAT_HAS_METHOD(formatted_string, possible_dest_types);
5099 IIFORMAT_HAS_METHOD(formatted_string, instantiate);
5100 IIFORMAT_VALID_KEYWORD(formatted_string, Q_data, check_valid_string);
5102 /* Do this so pointers have geometry. */
5103 /* #### Andy, what is this? This is a bogus format and should not be
5104 visible to the user. */
5105 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(pointer, "pointer");
5106 IIFORMAT_HAS_SHARED_METHOD(pointer, query_geometry, subwindow);
5109 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(subwindow, "subwindow");
5110 IIFORMAT_HAS_METHOD(subwindow, possible_dest_types);
5111 IIFORMAT_HAS_METHOD(subwindow, governing_domain);
5112 IIFORMAT_HAS_METHOD(subwindow, instantiate);
5113 IIFORMAT_HAS_METHOD(subwindow, query_geometry);
5114 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_width, check_valid_int);
5115 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_height, check_valid_int);
5117 #ifdef HAVE_WINDOW_SYSTEM
5118 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xbm, "xbm");
5120 IIFORMAT_HAS_METHOD(xbm, validate);
5121 IIFORMAT_HAS_METHOD(xbm, normalize);
5122 IIFORMAT_HAS_METHOD(xbm, possible_dest_types);
5124 IIFORMAT_VALID_KEYWORD(xbm, Q_data, check_valid_xbm_inline);
5125 IIFORMAT_VALID_KEYWORD(xbm, Q_file, check_valid_string);
5126 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_data, check_valid_xbm_inline);
5127 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_file, check_valid_string);
5128 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_x, check_valid_int);
5129 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_y, check_valid_int);
5130 IIFORMAT_VALID_KEYWORD(xbm, Q_foreground, check_valid_string);
5131 IIFORMAT_VALID_KEYWORD(xbm, Q_background, check_valid_string);
5132 #endif /* HAVE_WINDOW_SYSTEM */
5135 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xface, "xface");
5137 IIFORMAT_HAS_METHOD(xface, validate);
5138 IIFORMAT_HAS_METHOD(xface, normalize);
5139 IIFORMAT_HAS_METHOD(xface, possible_dest_types);
5141 IIFORMAT_VALID_KEYWORD(xface, Q_data, check_valid_string);
5142 IIFORMAT_VALID_KEYWORD(xface, Q_file, check_valid_string);
5143 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_x, check_valid_int);
5144 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_y, check_valid_int);
5145 IIFORMAT_VALID_KEYWORD(xface, Q_foreground, check_valid_string);
5146 IIFORMAT_VALID_KEYWORD(xface, Q_background, check_valid_string);
5150 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xpm, "xpm");
5152 IIFORMAT_HAS_METHOD(xpm, validate);
5153 IIFORMAT_HAS_METHOD(xpm, normalize);
5154 IIFORMAT_HAS_METHOD(xpm, possible_dest_types);
5156 IIFORMAT_VALID_KEYWORD(xpm, Q_data, check_valid_string);
5157 IIFORMAT_VALID_KEYWORD(xpm, Q_file, check_valid_string);
5158 IIFORMAT_VALID_KEYWORD(xpm, Q_color_symbols,
5159 check_valid_xpm_color_symbols);
5160 #endif /* HAVE_XPM */
5163 void reinit_vars_of_glyphs(void)
5165 the_expose_ignore_blocktype =
5166 Blocktype_new(struct expose_ignore_blocktype);
5168 hold_ignored_expose_registration = 0;
5171 void vars_of_glyphs(void)
5173 reinit_vars_of_glyphs();
5175 Vthe_nothing_vector = vector1(Qnothing);
5176 staticpro(&Vthe_nothing_vector);
5178 /* image instances */
5180 Vimage_instance_type_list = Fcons(Qnothing,
5181 list6(Qtext, Qmono_pixmap,
5182 Qcolor_pixmap, Qpointer,
5183 Qsubwindow, Qwidget));
5184 staticpro(&Vimage_instance_type_list);
5188 Vglyph_type_list = list3(Qbuffer, Qpointer, Qicon);
5189 staticpro(&Vglyph_type_list);
5191 /* The octal-escape glyph, control-arrow-glyph and
5192 invisible-text-glyph are completely initialized in glyphs.el */
5194 DEFVAR_LISP("octal-escape-glyph", &Voctal_escape_glyph /*
5195 What to prefix character codes displayed in octal with.
5197 Voctal_escape_glyph =
5198 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5200 DEFVAR_LISP("control-arrow-glyph", &Vcontrol_arrow_glyph /*
5201 What to use as an arrow for control characters.
5203 Vcontrol_arrow_glyph = allocate_glyph(GLYPH_BUFFER,
5204 redisplay_glyph_changed);
5206 DEFVAR_LISP("invisible-text-glyph", &Vinvisible_text_glyph /*
5207 What to use to indicate the presence of invisible text.
5208 This is the glyph that is displayed when an ellipsis is called for
5209 \(see `selective-display-ellipses' and `buffer-invisibility-spec').
5210 Normally this is three dots ("...").
5212 Vinvisible_text_glyph = allocate_glyph(GLYPH_BUFFER,
5213 redisplay_glyph_changed);
5215 /* Partially initialized in glyphs.el */
5216 DEFVAR_LISP("hscroll-glyph", &Vhscroll_glyph /*
5217 What to display at the beginning of horizontally scrolled lines.
5219 Vhscroll_glyph = allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5220 #ifdef HAVE_WINDOW_SYSTEM
5226 DEFVAR_LISP("xpm-color-symbols", &Vxpm_color_symbols /*
5227 Definitions of logical color-names used when reading XPM files.
5228 Elements of this list should be of the form (COLOR-NAME FORM-TO-EVALUATE).
5229 The COLOR-NAME should be a string, which is the name of the color to define;
5230 the FORM should evaluate to a `color' specifier object, or a string to be
5231 passed to `make-color-instance'. If a loaded XPM file references a symbolic
5232 color called COLOR-NAME, it will display as the computed color instead.
5234 The default value of this variable defines the logical color names
5235 \"foreground\" and \"background\" to be the colors of the `default' face.
5237 Vxpm_color_symbols = Qnil; /* initialized in x-faces.el */
5238 #endif /* HAVE_XPM */
5243 DEFVAR_BOOL("disable-animated-pixmaps", &disable_animated_pixmaps /*
5244 Whether animated pixmaps should be animated.
5247 disable_animated_pixmaps = 0;
5250 void specifier_vars_of_glyphs(void)
5252 /* #### Can we GC here? The set_specifier_* calls definitely need */
5254 /* display tables */
5256 DEFVAR_SPECIFIER("current-display-table", &Vcurrent_display_table /*
5257 *The display table currently in use.
5258 This is a specifier; use `set-specifier' to change it.
5260 Display tables are used to control how characters are displayed. Each
5261 time that redisplay processes a character, it is looked up in all the
5262 display tables that apply (obtained by calling `specifier-instance' on
5263 `current-display-table' and any overriding display tables specified in
5264 currently active faces). The first entry found that matches the
5265 character determines how the character is displayed. If there is no
5266 matching entry, the default display method is used. (Non-control
5267 characters are displayed as themselves and control characters are
5268 displayed according to the buffer-local variable `ctl-arrow'. Control
5269 characters are further affected by `control-arrow-glyph' and
5270 `octal-escape-glyph'.)
5272 Each instantiator in this specifier and the display-table specifiers
5273 in faces is a display table or a list of such tables. If a list, each
5274 table will be searched in turn for an entry matching a particular
5275 character. Each display table is one of
5277 -- a vector, specifying values for characters starting at 0
5278 -- a char table, either of type `char' or `generic'
5281 Each entry in a display table should be one of
5283 -- nil (this entry is ignored and the search continues)
5284 -- a character (use this character; if it happens to be the same as
5285 the original character, default processing happens, otherwise
5286 redisplay attempts to display this character directly;
5287 #### At some point recursive display-table lookup will be
5289 -- a string (display each character in the string directly;
5290 #### At some point recursive display-table lookup will be
5292 -- a glyph (display the glyph;
5293 #### At some point recursive display-table lookup will be
5294 implemented when a string glyph is being processed.)
5295 -- a cons of the form (format "STRING") where STRING is a printf-like
5296 spec used to process the character. #### Unfortunately no
5297 formatting directives other than %% are implemented.
5298 -- a vector (each element of the vector is processed recursively;
5299 in such a case, nil elements in the vector are simply ignored)
5301 #### At some point in the near future, display tables are likely to
5302 be expanded to include other features, such as referencing characters
5303 in particular fonts and allowing the character search to continue
5304 all the way up the chain of specifier instantiators. These features
5305 are necessary to properly display Unicode characters.
5307 Vcurrent_display_table = Fmake_specifier(Qdisplay_table);
5308 set_specifier_fallback(Vcurrent_display_table,
5309 list1(Fcons(Qnil, Qnil)));
5310 set_specifier_caching(Vcurrent_display_table,
5311 offsetof(struct window, display_table),
5312 some_window_value_changed, 0, 0, 0);
5315 void complex_vars_of_glyphs(void)
5317 /* Partially initialized in glyphs-x.c, glyphs.el */
5318 DEFVAR_LISP("truncation-glyph", &Vtruncation_glyph /*
5319 What to display at the end of truncated lines.
5322 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5324 /* Partially initialized in glyphs-x.c, glyphs.el */
5325 DEFVAR_LISP("continuation-glyph", &Vcontinuation_glyph /*
5326 What to display at the end of wrapped lines.
5328 Vcontinuation_glyph =
5329 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5331 /* Partially initialized in glyphs-x.c, glyphs.el */
5332 DEFVAR_LISP("sxemacs-logo", &Vsxemacs_logo /*
5333 The glyph used to display the SXEmacs logo at startup.
5335 Vsxemacs_logo = allocate_glyph(GLYPH_BUFFER, 0);