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)
884 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(obj);
887 error("printing unreadable object #<image-instance 0x%x>",
889 write_c_string("#<image-instance (", printcharfun);
890 print_internal(Fimage_instance_type(obj), printcharfun, 0);
891 write_c_string(") ", printcharfun);
892 if (!NILP(ii->name)) {
893 print_internal(ii->name, printcharfun, 1);
894 write_c_string(" ", printcharfun);
896 write_c_string("on ", printcharfun);
897 print_internal(ii->domain, printcharfun, 0);
898 write_c_string(" ", printcharfun);
899 switch (IMAGE_INSTANCE_TYPE(ii)) {
904 print_internal(IMAGE_INSTANCE_TEXT_STRING(ii), printcharfun, 1);
907 case IMAGE_MONO_PIXMAP:
908 case IMAGE_COLOR_PIXMAP:
910 if (STRINGP(IMAGE_INSTANCE_PIXMAP_FILENAME(ii))) {
912 Lisp_Object filename =
913 IMAGE_INSTANCE_PIXMAP_FILENAME(ii);
914 s = strrchr((char *)XSTRING_DATA(filename), '/');
916 print_internal(build_string(s + 1),
919 print_internal(filename, printcharfun, 1);
921 if (IMAGE_INSTANCE_PIXMAP_DEPTH(ii) > 1)
922 write_fmt_str(printcharfun, " %dx%dx%d",
923 IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
924 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii),
925 IMAGE_INSTANCE_PIXMAP_DEPTH(ii));
927 write_fmt_str(printcharfun, " %dx%d", IMAGE_INSTANCE_PIXMAP_WIDTH(ii),
928 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii));
929 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) ||
930 !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
931 write_c_string(" @", printcharfun);
932 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii))) {
933 write_fmt_str(printcharfun,"%ld",
934 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)));
936 write_c_string("??", printcharfun);
937 write_c_string(",", printcharfun);
938 if (!NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii))) {
939 write_fmt_str(printcharfun,"%ld",
940 XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii)));
942 write_c_string("??", printcharfun);
944 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii)) ||
945 !NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
946 write_c_string(" (", printcharfun);
947 if (!NILP(IMAGE_INSTANCE_PIXMAP_FG(ii))) {
950 (IMAGE_INSTANCE_PIXMAP_FG(ii))->name,
953 write_c_string("/", printcharfun);
954 if (!NILP(IMAGE_INSTANCE_PIXMAP_BG(ii))) {
957 (IMAGE_INSTANCE_PIXMAP_BG(ii))->name,
960 write_c_string(")", printcharfun);
965 print_internal(IMAGE_INSTANCE_WIDGET_TYPE(ii), printcharfun, 0);
967 if (GUI_ITEMP(IMAGE_INSTANCE_WIDGET_ITEM(ii))) {
968 write_c_string(" ", printcharfun);
969 print_internal(IMAGE_INSTANCE_WIDGET_TEXT(ii),
973 if (!NILP(IMAGE_INSTANCE_WIDGET_FACE(ii))) {
974 write_c_string(" face=", printcharfun);
976 (IMAGE_INSTANCE_WIDGET_FACE(ii), printcharfun, 0);
980 case IMAGE_SUBWINDOW:
981 write_fmt_str(printcharfun, " %dx%d", IMAGE_INSTANCE_WIDTH(ii),
982 IMAGE_INSTANCE_HEIGHT(ii));
984 /* This is stolen from frame.c. Subwindows are strange in that they
985 are specific to a particular frame so we want to print in their
986 description what that frame is. */
988 write_c_string(" on #<", printcharfun);
990 struct frame *f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
992 if (!FRAME_LIVE_P(f))
993 write_c_string("dead", printcharfun);
995 write_c_string(DEVICE_TYPE_NAME
996 (XDEVICE(FRAME_DEVICE(f))),
999 write_c_string("-frame>", printcharfun);
1000 write_hex_ptr( IMAGE_INSTANCE_SUBWINDOW_ID(ii), printcharfun);
1009 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain), print_image_instance,
1010 (ii, printcharfun, escapeflag));
1011 write_fmt_str(printcharfun, " 0x%x>", ii->header.uid);
1014 static void finalize_image_instance(void *header, int for_disksave)
1016 Lisp_Image_Instance *i = (Lisp_Image_Instance *) header;
1018 /* objects like this exist at dump time, so don't bomb out. */
1019 if (IMAGE_INSTANCE_TYPE(i) == IMAGE_NOTHING
1020 || NILP(IMAGE_INSTANCE_DEVICE(i)))
1025 /* We can't use the domain here, because it might have
1027 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(i)),
1028 finalize_image_instance, (i));
1030 /* Make sure we don't try this twice. */
1031 IMAGE_INSTANCE_DEVICE(i) = Qnil;
1034 static int image_instance_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
1036 Lisp_Image_Instance *i1 = XIMAGE_INSTANCE(obj1);
1037 Lisp_Image_Instance *i2 = XIMAGE_INSTANCE(obj2);
1039 ERROR_CHECK_IMAGE_INSTANCE(obj1);
1040 ERROR_CHECK_IMAGE_INSTANCE(obj2);
1042 if (!EQ(IMAGE_INSTANCE_DOMAIN(i1), IMAGE_INSTANCE_DOMAIN(i2))
1043 || IMAGE_INSTANCE_TYPE(i1) != IMAGE_INSTANCE_TYPE(i2)
1044 || IMAGE_INSTANCE_WIDTH(i1) != IMAGE_INSTANCE_WIDTH(i2)
1045 || IMAGE_INSTANCE_MARGIN_WIDTH(i1) !=
1046 IMAGE_INSTANCE_MARGIN_WIDTH(i2)
1047 || IMAGE_INSTANCE_HEIGHT(i1) != IMAGE_INSTANCE_HEIGHT(i2)
1048 || IMAGE_INSTANCE_XOFFSET(i1) != IMAGE_INSTANCE_XOFFSET(i2)
1049 || IMAGE_INSTANCE_YOFFSET(i1) != IMAGE_INSTANCE_YOFFSET(i2))
1051 if (!internal_equal(IMAGE_INSTANCE_NAME(i1), IMAGE_INSTANCE_NAME(i2),
1054 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(i1),
1055 IMAGE_INSTANCE_INSTANTIATOR(i2), depth + 1))
1058 switch (IMAGE_INSTANCE_TYPE(i1)) {
1063 if (!internal_equal(IMAGE_INSTANCE_TEXT_STRING(i1),
1064 IMAGE_INSTANCE_TEXT_STRING(i2), depth + 1))
1068 case IMAGE_MONO_PIXMAP:
1069 case IMAGE_COLOR_PIXMAP:
1071 if (!(IMAGE_INSTANCE_PIXMAP_DEPTH(i1) ==
1072 IMAGE_INSTANCE_PIXMAP_DEPTH(i2) &&
1073 IMAGE_INSTANCE_PIXMAP_SLICE(i1) ==
1074 IMAGE_INSTANCE_PIXMAP_SLICE(i2) &&
1075 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i1),
1076 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(i2)) &&
1077 EQ(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i1),
1078 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(i2)) &&
1079 internal_equal(IMAGE_INSTANCE_PIXMAP_FILENAME(i1),
1080 IMAGE_INSTANCE_PIXMAP_FILENAME(i2),
1082 internal_equal(IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i1),
1083 IMAGE_INSTANCE_PIXMAP_MASK_FILENAME(i2),
1089 if (!(EQ(IMAGE_INSTANCE_WIDGET_TYPE(i1),
1090 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1091 && IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1092 IMAGE_INSTANCE_SUBWINDOW_ID(i2)
1094 EQ(IMAGE_INSTANCE_WIDGET_FACE(i1),
1095 IMAGE_INSTANCE_WIDGET_TYPE(i2))
1096 && internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(i1),
1097 IMAGE_INSTANCE_WIDGET_ITEMS(i2),
1099 && internal_equal(IMAGE_INSTANCE_LAYOUT_CHILDREN(i1),
1100 IMAGE_INSTANCE_LAYOUT_CHILDREN(i2),
1102 && internal_equal(IMAGE_INSTANCE_WIDGET_PROPS(i1),
1103 IMAGE_INSTANCE_WIDGET_PROPS(i2),
1105 && internal_equal(IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i1),
1106 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR(i2),
1108 && internal_equal(IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i1),
1109 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR(i2),
1115 case IMAGE_SUBWINDOW:
1116 if (!(IMAGE_INSTANCE_SUBWINDOW_ID(i1) ==
1117 IMAGE_INSTANCE_SUBWINDOW_ID(i2)))
1126 return DEVMETH_OR_GIVEN(DOMAIN_XDEVICE(i1->domain),
1127 image_instance_equal, (i1, i2, depth), 1);
1130 /* Image instance domain manipulators. We can't error check in these
1131 otherwise we get into infinite recursion. */
1132 Lisp_Object image_instance_device(Lisp_Object instance)
1134 return XIMAGE_INSTANCE_DEVICE(instance);
1137 Lisp_Object image_instance_frame(Lisp_Object instance)
1139 return XIMAGE_INSTANCE_FRAME(instance);
1142 Lisp_Object image_instance_window(Lisp_Object instance)
1144 return DOMAIN_WINDOW(XIMAGE_INSTANCE_DOMAIN(instance));
1147 int image_instance_live_p(Lisp_Object instance)
1149 return DOMAIN_LIVE_P(XIMAGE_INSTANCE_DOMAIN(instance));
1152 static unsigned long image_instance_hash(Lisp_Object obj, int depth)
1154 Lisp_Image_Instance *i = XIMAGE_INSTANCE(obj);
1155 unsigned long hash = HASH5(LISP_HASH(IMAGE_INSTANCE_DOMAIN(i)),
1156 IMAGE_INSTANCE_WIDTH(i),
1157 IMAGE_INSTANCE_MARGIN_WIDTH(i),
1158 IMAGE_INSTANCE_HEIGHT(i),
1159 internal_hash(IMAGE_INSTANCE_INSTANTIATOR(i),
1162 ERROR_CHECK_IMAGE_INSTANCE(obj);
1164 switch (IMAGE_INSTANCE_TYPE(i)) {
1169 hash = HASH2(hash, internal_hash(IMAGE_INSTANCE_TEXT_STRING(i),
1173 case IMAGE_MONO_PIXMAP:
1174 case IMAGE_COLOR_PIXMAP:
1176 hash = HASH4(hash, IMAGE_INSTANCE_PIXMAP_DEPTH(i),
1177 IMAGE_INSTANCE_PIXMAP_SLICE(i),
1178 internal_hash(IMAGE_INSTANCE_PIXMAP_FILENAME(i),
1183 /* We need the hash to be equivalent to what should be
1186 LISP_HASH(IMAGE_INSTANCE_WIDGET_TYPE(i)),
1187 internal_hash(IMAGE_INSTANCE_WIDGET_PROPS(i),
1189 internal_hash(IMAGE_INSTANCE_WIDGET_ITEMS(i),
1191 internal_hash(IMAGE_INSTANCE_LAYOUT_CHILDREN(i),
1193 case IMAGE_SUBWINDOW:
1194 hash = HASH2(hash, (EMACS_INT) IMAGE_INSTANCE_SUBWINDOW_ID(i));
1203 Lisp_Object tmp = image_instance_device(obj);
1204 return HASH2(hash, DEVMETH_OR_GIVEN(
1205 XDEVICE(tmp), image_instance_hash,
1210 DEFINE_LRECORD_IMPLEMENTATION("image-instance", image_instance,
1211 mark_image_instance, print_image_instance,
1212 finalize_image_instance, image_instance_equal,
1213 image_instance_hash, 0, Lisp_Image_Instance);
1216 allocate_image_instance(Lisp_Object governing_domain, Lisp_Object parent,
1217 Lisp_Object instantiator)
1219 Lisp_Image_Instance *lp =
1220 alloc_lcrecord_type(Lisp_Image_Instance, &lrecord_image_instance);
1224 /* It's not possible to simply keep a record of the domain in which
1225 the instance was instantiated. This is because caching may mean
1226 that the domain becomes invalid but the instance remains
1227 valid. However, the only truly relevant domain is the domain in
1228 which the instance is cached since this is the one that will be
1229 common to the instances. */
1230 lp->domain = governing_domain;
1231 /* The cache domain is not quite sufficient since the domain can get
1232 deleted before the image instance does. We need to know the
1233 domain device in order to finalize the image instance
1234 properly. We therefore record the device also. */
1235 lp->device = DOMAIN_DEVICE(governing_domain);
1236 lp->type = IMAGE_NOTHING;
1240 lp->width = IMAGE_UNSPECIFIED_GEOMETRY;
1241 lp->margin_width = 0;
1242 lp->height = IMAGE_UNSPECIFIED_GEOMETRY;
1243 lp->parent = parent;
1244 lp->instantiator = instantiator;
1245 /* So that layouts get done. */
1246 lp->layout_changed = 1;
1247 lp->initialized = 0;
1249 XSETIMAGE_INSTANCE(val, lp);
1250 MARK_GLYPHS_CHANGED;
1255 static enum image_instance_type
1256 decode_image_instance_type(Lisp_Object type, Error_behavior errb)
1258 if (ERRB_EQ(errb, ERROR_ME))
1261 if (EQ(type, Qnothing))
1262 return IMAGE_NOTHING;
1263 if (EQ(type, Qtext))
1265 if (EQ(type, Qmono_pixmap))
1266 return IMAGE_MONO_PIXMAP;
1267 if (EQ(type, Qcolor_pixmap))
1268 return IMAGE_COLOR_PIXMAP;
1269 if (EQ(type, Qpointer))
1270 return IMAGE_POINTER;
1271 if (EQ(type, Qsubwindow))
1272 return IMAGE_SUBWINDOW;
1273 if (EQ(type, Qwidget))
1274 return IMAGE_WIDGET;
1276 maybe_signal_simple_error("Invalid image-instance type", type,
1279 return IMAGE_UNKNOWN; /* not reached */
1282 static Lisp_Object encode_image_instance_type(enum image_instance_type type)
1289 case IMAGE_MONO_PIXMAP:
1290 return Qmono_pixmap;
1291 case IMAGE_COLOR_PIXMAP:
1292 return Qcolor_pixmap;
1295 case IMAGE_SUBWINDOW:
1305 return Qnil; /* not reached */
1308 static int decode_image_instance_type_list(Lisp_Object list)
1317 enum image_instance_type type =
1318 decode_image_instance_type(list, ERROR_ME);
1319 return image_instance_type_to_mask(type);
1322 EXTERNAL_LIST_LOOP(rest, list) {
1323 enum image_instance_type type =
1324 decode_image_instance_type(XCAR(rest), ERROR_ME);
1325 mask |= image_instance_type_to_mask(type);
1331 static Lisp_Object encode_image_instance_type_list(int mask)
1334 Lisp_Object result = Qnil;
1339 result = Fcons(encode_image_instance_type
1340 ((enum image_instance_type)count),
1345 return Fnreverse(result);
1349 incompatible_image_types(Lisp_Object instantiator, int given_dest_mask,
1350 int desired_dest_mask)
1352 signal_error(Qerror, list2(emacs_doprnt_string_lisp_2((const Bufbyte *)
1353 "No compatible image-instance types given: wanted one of %s, got %s",
1355 encode_image_instance_type_list
1356 (desired_dest_mask),
1357 encode_image_instance_type_list
1362 static int valid_image_instance_type_p(Lisp_Object type)
1364 return !NILP(memq_no_quit(type, Vimage_instance_type_list));
1367 DEFUN("valid-image-instance-type-p", Fvalid_image_instance_type_p, 1, 1, 0, /*
1368 Given an IMAGE-INSTANCE-TYPE, return non-nil if it is valid.
1369 Valid types are some subset of 'nothing, 'text, 'mono-pixmap, 'color-pixmap,
1370 'pointer, 'subwindow, and 'widget, depending on how SXEmacs was compiled.
1372 (image_instance_type))
1374 return valid_image_instance_type_p(image_instance_type) ? Qt : Qnil;
1377 DEFUN("image-instance-type-list", Fimage_instance_type_list, 0, 0, 0, /*
1378 Return a list of valid image-instance types.
1382 return Fcopy_sequence(Vimage_instance_type_list);
1385 Error_behavior decode_error_behavior_flag(Lisp_Object noerror)
1389 else if (EQ(noerror, Qt))
1390 return ERROR_ME_NOT;
1392 return ERROR_ME_WARN;
1395 Lisp_Object encode_error_behavior_flag(Error_behavior errb)
1397 if (ERRB_EQ(errb, ERROR_ME))
1399 else if (ERRB_EQ(errb, ERROR_ME_NOT))
1402 assert(ERRB_EQ(errb, ERROR_ME_WARN));
1407 /* Recurse up the hierarchy looking for the topmost glyph. This means
1408 that instances in layouts will inherit face properties from their
1410 Lisp_Object image_instance_parent_glyph(Lisp_Image_Instance * ii)
1412 if (IMAGE_INSTANCEP(IMAGE_INSTANCE_PARENT(ii))) {
1413 return image_instance_parent_glyph
1414 (XIMAGE_INSTANCE(IMAGE_INSTANCE_PARENT(ii)));
1416 return IMAGE_INSTANCE_PARENT(ii);
1420 make_image_instance_1(Lisp_Object data, Lisp_Object domain,
1421 Lisp_Object dest_types)
1424 struct gcpro gcpro1;
1426 Lisp_Object governing_domain;
1428 if (IMAGE_INSTANCEP(data))
1429 signal_simple_error("Image instances not allowed here", data);
1430 image_validate(data);
1431 domain = decode_domain(domain);
1432 /* instantiate_image_instantiator() will abort if given an
1433 image instance ... */
1434 dest_mask = decode_image_instance_type_list(dest_types);
1435 data = normalize_image_instantiator(data,
1436 DEVICE_TYPE(DOMAIN_XDEVICE(domain)),
1437 make_int(dest_mask));
1439 /* After normalizing the data, it's always either an image instance (which
1440 we filtered out above) or a vector. */
1441 if (EQ(INSTANTIATOR_TYPE(data), Qinherit))
1442 signal_simple_error("Inheritance not allowed here", data);
1444 get_image_instantiator_governing_domain(data, domain);
1445 ii = instantiate_image_instantiator(governing_domain, domain, data,
1446 Qnil, Qnil, dest_mask, Qnil);
1450 DEFUN("make-image-instance", Fmake_image_instance, 1, 4, 0, /*
1451 Return a new `image-instance' object.
1453 Image-instance objects encapsulate the way a particular image (pixmap,
1454 etc.) is displayed on a particular device. In most circumstances, you
1455 do not need to directly create image instances; use a glyph instead.
1456 However, it may occasionally be useful to explicitly create image
1457 instances, if you want more control over the instantiation process.
1459 DATA is an image instantiator, which describes the image; see
1460 `make-image-specifier' for a description of the allowed values.
1462 DEST-TYPES should be a list of allowed image instance types that can
1463 be generated. The recognized image instance types are
1466 Nothing is displayed.
1468 Displayed as text. The foreground and background colors and the
1469 font of the text are specified independent of the pixmap. Typically
1470 these attributes will come from the face of the surrounding text,
1471 unless a face is specified for the glyph in which the image appears.
1473 Displayed as a mono pixmap (a pixmap with only two colors where the
1474 foreground and background can be specified independent of the pixmap;
1475 typically the pixmap assumes the foreground and background colors of
1476 the text around it, unless a face is specified for the glyph in which
1479 Displayed as a color pixmap.
1481 Used as the mouse pointer for a window.
1483 A child window that is treated as an image. This allows (e.g.)
1484 another program to be responsible for drawing into the window.
1486 A child window that contains a window-system widget, e.g. a push
1487 button, text field, or slider.
1489 The DEST-TYPES list is unordered. If multiple destination types are
1490 possible for a given instantiator, the "most natural" type for the
1491 instantiator's format is chosen. (For XBM, the most natural types are
1492 `mono-pixmap', followed by `color-pixmap', followed by `pointer'. For
1493 the other normal image formats, the most natural types are
1494 `color-pixmap', followed by `mono-pixmap', followed by `pointer'. For
1495 the string and formatted-string formats, the most natural types are
1496 `text', followed by `mono-pixmap' (not currently implemented),
1497 followed by `color-pixmap' (not currently implemented). For MS
1498 Windows resources, the most natural type for pointer resources is
1499 `pointer', and for the others it's `color-pixmap'. The other formats
1500 can only be instantiated as one type. (If you want to control more
1501 specifically the order of the types into which an image is
1502 instantiated, just call `make-image-instance' repeatedly until it
1503 succeeds, passing less and less preferred destination types each
1506 See `make-image-specifier' for a description of the different image
1507 instantiator formats.
1509 If DEST-TYPES is omitted, all possible types are allowed.
1511 DOMAIN specifies the domain to which the image instance will be attached.
1512 This domain is termed the \"governing domain\". The type of the governing
1513 domain depends on the image instantiator format. (Although, more correctly,
1514 it should probably depend on the image instance type.) For example, pixmap
1515 image instances are specific to a device, but widget image instances are
1516 specific to a particular SXEmacs window because in order to display such a
1517 widget when two windows onto the same buffer want to display the widget,
1518 two separate underlying widgets must be created. (That's because a widget
1519 is actually a child window-system window, and all window-system windows have
1520 a unique existence on the screen.) This means that the governing domain for
1521 a pixmap image instance will be some device (most likely, the only existing
1522 device), whereas the governing domain for a widget image instance will be
1523 some SXEmacs window.
1525 If you specify an overly general DOMAIN (e.g. a frame when a window was
1526 wanted), an error is signaled. If you specify an overly specific DOMAIN
1527 \(e.g. a window when a device was wanted), the corresponding general domain
1528 is fetched and used instead. For `make-image-instance', it makes no
1529 difference whether you specify an overly specific domain or the properly
1530 general domain derived from it. However, it does matter when creating an
1531 image instance by instantiating a specifier or glyph (e.g. with
1532 `glyph-image-instance'), because the more specific domain causes spec lookup
1533 to start there and proceed to more general domains. (It would also matter
1534 when creating an image instance with an instantiator format of `inherit',
1535 but we currently disallow this. #### We should fix this.)
1537 If omitted, DOMAIN defaults to the selected window.
1539 NOERROR controls what happens when the image cannot be generated.
1540 If nil, an error message is generated. If t, no messages are
1541 generated and this function returns nil. If anything else, a warning
1542 message is generated and this function returns nil.
1544 (data, domain, dest_types, noerror))
1546 Error_behavior errb = decode_error_behavior_flag(noerror);
1548 return call_with_suspended_errors((lisp_fn_t) make_image_instance_1,
1550 3, data, domain, dest_types);
1553 DEFUN("image-instance-p", Fimage_instance_p, 1, 1, 0, /*
1554 Return non-nil if OBJECT is an image instance.
1558 return IMAGE_INSTANCEP(object) ? Qt : Qnil;
1561 DEFUN("image-instance-type", Fimage_instance_type, 1, 1, 0, /*
1562 Return the type of the given image instance.
1563 The return value will be one of 'nothing, 'text, 'mono-pixmap,
1564 'color-pixmap, 'pointer, or 'subwindow.
1568 CHECK_IMAGE_INSTANCE(image_instance);
1569 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1570 return encode_image_instance_type(XIMAGE_INSTANCE_TYPE(image_instance));
1573 DEFUN("image-instance-name", Fimage_instance_name, 1, 1, 0, /*
1574 Return the name of the given image instance.
1578 CHECK_IMAGE_INSTANCE(image_instance);
1579 return XIMAGE_INSTANCE_NAME(image_instance);
1582 DEFUN("image-instance-domain", Fimage_instance_domain, 1, 1, 0, /*
1583 Return the governing domain of the given image instance.
1584 The governing domain of an image instance is the domain that the image
1585 instance is specific to. It is NOT necessarily the domain that was
1586 given to the call to `specifier-instance' that resulted in the creation
1587 of this image instance. See `make-image-instance' for more information
1588 on governing domains.
1592 CHECK_IMAGE_INSTANCE(image_instance);
1593 return XIMAGE_INSTANCE_DOMAIN(image_instance);
1596 DEFUN("image-instance-string", Fimage_instance_string, 1, 1, 0, /*
1597 Return the string of the given image instance.
1598 This will only be non-nil for text image instances and widgets.
1602 CHECK_IMAGE_INSTANCE(image_instance);
1603 if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_TEXT)
1604 return XIMAGE_INSTANCE_TEXT_STRING(image_instance);
1605 else if (XIMAGE_INSTANCE_TYPE(image_instance) == IMAGE_WIDGET)
1606 return XIMAGE_INSTANCE_WIDGET_TEXT(image_instance);
1611 DEFUN("image-instance-property", Fimage_instance_property, 2, 2, 0, /*
1612 Return the given property of the given image instance.
1613 Returns nil if the property or the property method do not exist for
1614 the image instance in the domain.
1616 (image_instance, prop))
1618 Lisp_Image_Instance *ii;
1619 Lisp_Object type, ret;
1620 struct image_instantiator_methods *meths;
1622 CHECK_IMAGE_INSTANCE(image_instance);
1623 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1625 ii = XIMAGE_INSTANCE(image_instance);
1627 /* ... then try device specific methods ... */
1628 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1629 meths = decode_device_ii_format(image_instance_device(image_instance),
1630 type, ERROR_ME_NOT);
1631 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1634 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1637 /* ... then format specific methods ... */
1638 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1639 if (meths && HAS_IIFORMAT_METH_P(meths, property)
1642 IIFORMAT_METH(meths, property, (image_instance, prop)))) {
1649 DEFUN("image-instance-file-name", Fimage_instance_file_name, 1, 1, 0, /*
1650 Return the file name from which IMAGE-INSTANCE was read, if known.
1654 CHECK_IMAGE_INSTANCE(image_instance);
1655 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1657 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1658 case IMAGE_MONO_PIXMAP:
1659 case IMAGE_COLOR_PIXMAP:
1661 return XIMAGE_INSTANCE_PIXMAP_FILENAME(image_instance);
1666 case IMAGE_SUBWINDOW:
1673 DEFUN("image-instance-mask-file-name", Fimage_instance_mask_file_name, 1, 1, 0, /*
1674 Return the file name from which IMAGE-INSTANCE's mask was read, if known.
1678 CHECK_IMAGE_INSTANCE(image_instance);
1679 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1681 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1682 case IMAGE_MONO_PIXMAP:
1683 case IMAGE_COLOR_PIXMAP:
1685 return XIMAGE_INSTANCE_PIXMAP_MASK_FILENAME(image_instance);
1690 case IMAGE_SUBWINDOW:
1697 DEFUN("image-instance-depth", Fimage_instance_depth, 1, 1, 0, /*
1698 Return the depth of the image instance.
1699 This is 0 for a bitmap, or a positive integer for a pixmap.
1703 CHECK_IMAGE_INSTANCE(image_instance);
1704 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1706 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1707 case IMAGE_MONO_PIXMAP:
1708 case IMAGE_COLOR_PIXMAP:
1710 return make_int(XIMAGE_INSTANCE_PIXMAP_DEPTH(image_instance));
1715 case IMAGE_SUBWINDOW:
1722 DEFUN("image-instance-height", Fimage_instance_height, 1, 1, 0, /*
1723 Return the height of the image instance, in pixels.
1727 CHECK_IMAGE_INSTANCE(image_instance);
1728 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1730 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1731 case IMAGE_MONO_PIXMAP:
1732 case IMAGE_COLOR_PIXMAP:
1734 case IMAGE_SUBWINDOW:
1736 return make_int(XIMAGE_INSTANCE_HEIGHT(image_instance));
1746 DEFUN("image-instance-width", Fimage_instance_width, 1, 1, 0, /*
1747 Return the width of the image instance, in pixels.
1751 CHECK_IMAGE_INSTANCE(image_instance);
1752 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1754 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1755 case IMAGE_MONO_PIXMAP:
1756 case IMAGE_COLOR_PIXMAP:
1758 case IMAGE_SUBWINDOW:
1760 return make_int(XIMAGE_INSTANCE_WIDTH(image_instance));
1770 DEFUN("image-instance-hotspot-x", Fimage_instance_hotspot_x, 1, 1, 0, /*
1771 Return the X coordinate of the image instance's hotspot, if known.
1772 This is a point relative to the origin of the pixmap. When an image is
1773 used as a mouse pointer, the hotspot is the point on the image that sits
1774 over the location that the pointer points to. This is, for example, the
1775 tip of the arrow or the center of the crosshairs.
1776 This will always be nil for a non-pointer image instance.
1780 CHECK_IMAGE_INSTANCE(image_instance);
1781 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1783 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1784 case IMAGE_MONO_PIXMAP:
1785 case IMAGE_COLOR_PIXMAP:
1787 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_X(image_instance);
1792 case IMAGE_SUBWINDOW:
1799 DEFUN("image-instance-hotspot-y", Fimage_instance_hotspot_y, 1, 1, 0, /*
1800 Return the Y coordinate of the image instance's hotspot, if known.
1801 This is a point relative to the origin of the pixmap. When an image is
1802 used as a mouse pointer, the hotspot is the point on the image that sits
1803 over the location that the pointer points to. This is, for example, the
1804 tip of the arrow or the center of the crosshairs.
1805 This will always be nil for a non-pointer image instance.
1809 CHECK_IMAGE_INSTANCE(image_instance);
1810 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1812 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1813 case IMAGE_MONO_PIXMAP:
1814 case IMAGE_COLOR_PIXMAP:
1816 return XIMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(image_instance);
1821 case IMAGE_SUBWINDOW:
1828 DEFUN("image-instance-foreground", Fimage_instance_foreground, 1, 1, 0, /*
1829 Return the foreground color of IMAGE-INSTANCE, if applicable.
1830 This will be a color instance or nil. (It will only be non-nil for
1831 colorized mono pixmaps and for pointers.)
1835 CHECK_IMAGE_INSTANCE(image_instance);
1836 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1838 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1839 case IMAGE_MONO_PIXMAP:
1840 case IMAGE_COLOR_PIXMAP:
1842 return XIMAGE_INSTANCE_PIXMAP_FG(image_instance);
1846 FACE_FOREGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1847 XIMAGE_INSTANCE_FRAME(image_instance));
1852 case IMAGE_SUBWINDOW:
1858 DEFUN("image-instance-background", Fimage_instance_background, 1, 1, 0, /*
1859 Return the background color of IMAGE-INSTANCE, if applicable.
1860 This will be a color instance or nil. (It will only be non-nil for
1861 colorized mono pixmaps and for pointers.)
1865 CHECK_IMAGE_INSTANCE(image_instance);
1866 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1868 switch (XIMAGE_INSTANCE_TYPE(image_instance)) {
1869 case IMAGE_MONO_PIXMAP:
1870 case IMAGE_COLOR_PIXMAP:
1872 return XIMAGE_INSTANCE_PIXMAP_BG(image_instance);
1876 FACE_BACKGROUND(XIMAGE_INSTANCE_WIDGET_FACE(image_instance),
1877 XIMAGE_INSTANCE_FRAME(image_instance));
1882 case IMAGE_SUBWINDOW:
1888 DEFUN("colorize-image-instance", Fcolorize_image_instance, 3, 3, 0, /*
1889 Make the image instance be displayed in the given colors.
1890 This function returns a new image instance that is exactly like the
1891 specified one except that (if possible) the foreground and background
1892 colors and as specified. Currently, this only does anything if the image
1893 instance is a mono pixmap; otherwise, the same image instance is returned.
1895 (image_instance, foreground, background))
1900 CHECK_IMAGE_INSTANCE(image_instance);
1901 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1902 CHECK_COLOR_INSTANCE(foreground);
1903 CHECK_COLOR_INSTANCE(background);
1905 device = image_instance_device(image_instance);
1906 if (!HAS_DEVMETH_P(XDEVICE(device), colorize_image_instance))
1907 return image_instance;
1909 /* #### There should be a copy_image_instance(), which calls a
1910 device-specific method to copy the window-system subobject. */
1911 new = allocate_image_instance(XIMAGE_INSTANCE_DOMAIN(image_instance),
1913 copy_lcrecord(XIMAGE_INSTANCE(new), XIMAGE_INSTANCE(image_instance));
1914 /* note that if this method returns non-zero, this method MUST
1915 copy any window-system resources, so that when one image instance is
1916 freed, the other one is not hosed. */
1917 if (!DEVMETH(XDEVICE(device), colorize_image_instance, (new, foreground,
1919 return image_instance;
1923 /************************************************************************/
1924 /* Geometry calculations */
1925 /************************************************************************/
1927 /* Find out desired geometry of the image instance. If there is no
1928 special function then just return the width and / or height. */
1930 image_instance_query_geometry(Lisp_Object image_instance,
1931 int *width, int *height,
1932 enum image_instance_geometry disp,
1935 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1937 struct image_instantiator_methods *meths;
1938 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1940 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
1941 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
1943 if (meths && HAS_IIFORMAT_METH_P(meths, query_geometry)) {
1944 IIFORMAT_METH(meths, query_geometry,
1945 (image_instance, width, height, disp, domain));
1948 *width = IMAGE_INSTANCE_WIDTH(ii);
1950 *height = IMAGE_INSTANCE_HEIGHT(ii);
1954 /* Layout the image instance using the provided dimensions. Layout
1955 widgets are going to do different kinds of calculations to
1956 determine what size to give things so we could make the layout
1957 function relatively simple to take account of that. An alternative
1958 approach is to consider separately the two cases, one where you
1959 don't mind what size you have (normal widgets) and one where you
1960 want to specify something (layout widgets). */
1962 image_instance_layout(Lisp_Object image_instance,
1963 int width, int height,
1964 int xoffset, int yoffset, Lisp_Object domain)
1966 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1968 struct image_instantiator_methods *meths;
1970 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
1972 /* Nothing is as nothing does. */
1973 if (NOTHING_IMAGE_INSTANCEP(image_instance))
1976 /* We don't want carefully calculated offsets to be mucked up by
1978 if (xoffset != IMAGE_UNCHANGED_GEOMETRY)
1979 XIMAGE_INSTANCE_XOFFSET(image_instance) = xoffset;
1980 if (yoffset != IMAGE_UNCHANGED_GEOMETRY)
1981 XIMAGE_INSTANCE_YOFFSET(image_instance) = yoffset;
1983 /* If geometry is unspecified then get some reasonable values for it. */
1984 if (width == IMAGE_UNSPECIFIED_GEOMETRY
1985 || height == IMAGE_UNSPECIFIED_GEOMETRY) {
1986 int dwidth = IMAGE_UNSPECIFIED_GEOMETRY;
1987 int dheight = IMAGE_UNSPECIFIED_GEOMETRY;
1988 /* Get the desired geometry. */
1989 image_instance_query_geometry(image_instance,
1991 IMAGE_DESIRED_GEOMETRY, domain);
1992 /* Compare with allowed geometry. */
1993 if (width == IMAGE_UNSPECIFIED_GEOMETRY)
1995 if (height == IMAGE_UNSPECIFIED_GEOMETRY)
1999 /* If we don't have sane values then we cannot layout at this point and
2000 must just return. */
2001 if (width == IMAGE_UNSPECIFIED_GEOMETRY
2002 || height == IMAGE_UNSPECIFIED_GEOMETRY)
2005 /* At this point width and height should contain sane values. Thus
2006 we set the glyph geometry and lay it out. */
2007 if (IMAGE_INSTANCE_WIDTH(ii) != width
2008 || IMAGE_INSTANCE_HEIGHT(ii) != height) {
2009 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
2012 IMAGE_INSTANCE_WIDTH(ii) = width;
2013 IMAGE_INSTANCE_HEIGHT(ii) = height;
2015 type = encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2016 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2018 MAYBE_IIFORMAT_METH(meths, layout,
2019 (image_instance, width, height, xoffset, yoffset,
2021 /* Do not clear the dirty flag here - redisplay will do this for
2023 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 0;
2026 /* Update an image instance from its changed instantiator. */
2028 update_image_instance(Lisp_Object image_instance, Lisp_Object instantiator)
2030 struct image_instantiator_methods *meths;
2031 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2033 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
2035 if (NOTHING_IMAGE_INSTANCEP(image_instance))
2038 assert(!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2040 (internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)
2041 && internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator,
2044 /* If the instantiator is identical then do nothing. We must use
2045 equal here because the specifier code copies the instantiator. */
2046 if (!internal_equal(IMAGE_INSTANCE_INSTANTIATOR(ii), instantiator, 0)) {
2047 /* Extract the changed properties so that device / format
2048 methods only have to cope with these. We assume that
2049 normalization has already been done. */
2050 Lisp_Object diffs = find_instantiator_differences(instantiator,
2051 IMAGE_INSTANCE_INSTANTIATOR
2054 encode_image_instance_type(IMAGE_INSTANCE_TYPE(ii));
2055 struct gcpro gcpro1;
2058 /* try device specific methods first ... */
2060 decode_device_ii_format(image_instance_device
2061 (image_instance), type,
2063 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2064 /* ... then format specific methods ... */
2065 meths = decode_device_ii_format(Qnil, type, ERROR_ME_NOT);
2066 MAYBE_IIFORMAT_METH(meths, update, (image_instance, diffs));
2068 /* Instance and therefore glyph has changed so mark as dirty.
2069 If we don't do this output optimizations will assume the
2070 glyph is unchanged. */
2071 set_image_instance_dirty_p(image_instance, 1);
2072 /* Structure has changed. */
2073 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2077 /* We should now have a consistent instantiator so keep a record of
2078 it. It is important that we don't actually update the window
2079 system widgets here - we must do that when redisplay tells us
2082 #### should we delay doing this until the display is up-to-date
2084 IMAGE_INSTANCE_INSTANTIATOR(ii) = instantiator;
2088 * Mark image instance in W as dirty if (a) W's faces have changed and
2089 * (b) GLYPH_OR_II instance in W is a string.
2091 * Return non-zero if instance has been marked dirty.
2093 int invalidate_glyph_geometry_maybe(Lisp_Object glyph_or_ii, struct window *w)
2095 if (XFRAME(WINDOW_FRAME(w))->faces_changed) {
2096 Lisp_Object image = glyph_or_ii;
2098 if (GLYPHP(glyph_or_ii)) {
2100 XSETWINDOW(window, w);
2102 glyph_image_instance(glyph_or_ii, window,
2106 if (TEXT_IMAGE_INSTANCEP(image)) {
2107 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image);
2108 IMAGE_INSTANCE_DIRTYP(ii) = 1;
2109 IMAGE_INSTANCE_LAYOUT_CHANGED(ii) = 1;
2110 if (GLYPHP(glyph_or_ii))
2111 XGLYPH_DIRTYP(glyph_or_ii) = 1;
2119 /************************************************************************/
2121 /************************************************************************/
2122 DOESNT_RETURN signal_image_error(const char *reason, Lisp_Object frob)
2124 signal_error(Qimage_conversion_error,
2125 list2(build_translated_string(reason), frob));
2129 signal_image_error_2(const char *reason, Lisp_Object frob0, Lisp_Object frob1)
2131 signal_error(Qimage_conversion_error,
2132 list3(build_translated_string(reason), frob0, frob1));
2135 /****************************************************************************
2137 ****************************************************************************/
2139 static int nothing_possible_dest_types(void)
2141 return IMAGE_NOTHING_MASK;
2145 nothing_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2146 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2147 int dest_mask, Lisp_Object domain)
2149 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2151 if (dest_mask & IMAGE_NOTHING_MASK) {
2152 IMAGE_INSTANCE_TYPE(ii) = IMAGE_NOTHING;
2153 IMAGE_INSTANCE_HEIGHT(ii) = 0;
2154 IMAGE_INSTANCE_WIDTH(ii) = 0;
2156 incompatible_image_types(instantiator, dest_mask,
2157 IMAGE_NOTHING_MASK);
2160 /****************************************************************************
2162 ****************************************************************************/
2164 static void inherit_validate(Lisp_Object instantiator)
2166 face_must_be_present(instantiator);
2170 inherit_normalize(Lisp_Object inst, Lisp_Object console_type,
2171 Lisp_Object dest_mask)
2175 assert(XVECTOR_LENGTH(inst) == 3);
2176 face = XVECTOR_DATA(inst)[2];
2178 inst = vector3(Qinherit, Q_face, Fget_face(face));
2182 static int inherit_possible_dest_types(void)
2184 return IMAGE_MONO_PIXMAP_MASK;
2188 inherit_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2189 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2190 int dest_mask, Lisp_Object domain)
2192 /* handled specially in image_instantiate */
2196 /****************************************************************************
2198 ****************************************************************************/
2200 static void string_validate(Lisp_Object instantiator)
2202 data_must_be_present(instantiator);
2205 static int string_possible_dest_types(void)
2207 return IMAGE_TEXT_MASK;
2210 /* Called from autodetect_instantiate() */
2212 string_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2213 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2214 int dest_mask, Lisp_Object domain)
2216 Lisp_Object string = find_keyword_in_vector(instantiator, Q_data);
2217 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2219 /* Should never get here with a domain other than a window. */
2220 assert(!NILP(string) && WINDOWP(DOMAIN_WINDOW(domain)));
2221 if (dest_mask & IMAGE_TEXT_MASK) {
2222 IMAGE_INSTANCE_TYPE(ii) = IMAGE_TEXT;
2223 IMAGE_INSTANCE_TEXT_STRING(ii) = string;
2225 incompatible_image_types(instantiator, dest_mask,
2229 /* Sort out the size of the text that is being displayed. Calculating
2230 it dynamically allows us to change the text and still see
2231 everything. Note that the following methods are for text not string
2232 since that is what the instantiated type is. The first method is a
2233 helper that is used elsewhere for calculating text geometry. */
2235 query_string_geometry(Lisp_Object string, Lisp_Object face,
2236 int *width, int *height, int *descent, Lisp_Object domain)
2238 struct font_metric_info fm;
2239 unsigned char charsets[NUM_LEADING_BYTES];
2240 struct face_cachel frame_cachel;
2241 struct face_cachel *cachel;
2242 Lisp_Object frame = DOMAIN_FRAME(domain);
2244 CHECK_STRING(string);
2246 /* Compute height */
2248 /* Compute string metric info */
2249 find_charsets_in_bufbyte_string(charsets,
2250 XSTRING_DATA(string),
2251 XSTRING_LENGTH(string));
2253 /* Fallback to the default face if none was provided. */
2255 reset_face_cachel(&frame_cachel);
2256 update_face_cachel_data(&frame_cachel, frame, face);
2257 cachel = &frame_cachel;
2259 cachel = WINDOW_FACE_CACHEL(DOMAIN_XWINDOW(domain),
2263 ensure_face_cachel_complete(cachel, domain, charsets);
2264 face_cachel_charset_font_metric_info(cachel, charsets, &fm);
2266 *height = fm.ascent + fm.descent;
2267 /* #### descent only gets set if we query the height as well. */
2269 *descent = fm.descent;
2276 redisplay_frame_text_width_string(XFRAME(frame),
2281 redisplay_frame_text_width_string(XFRAME(frame),
2288 query_string_font(Lisp_Object string, Lisp_Object face, Lisp_Object domain)
2290 unsigned char charsets[NUM_LEADING_BYTES];
2291 struct face_cachel frame_cachel;
2292 struct face_cachel *cachel;
2294 Lisp_Object frame = DOMAIN_FRAME(domain);
2296 /* Compute string font info */
2297 find_charsets_in_bufbyte_string(charsets,
2298 XSTRING_DATA(string),
2299 XSTRING_LENGTH(string));
2301 reset_face_cachel(&frame_cachel);
2302 update_face_cachel_data(&frame_cachel, frame, face);
2303 cachel = &frame_cachel;
2305 ensure_face_cachel_complete(cachel, domain, charsets);
2307 for (i = 0; i < NUM_LEADING_BYTES; i++) {
2310 CHARSET_BY_LEADING_BYTE(i + MIN_LEADING_BYTE);
2311 return FACE_CACHEL_FONT(cachel, tmp);
2315 return Qnil; /* NOT REACHED */
2319 text_query_geometry(Lisp_Object image_instance,
2320 int *width, int *height,
2321 enum image_instance_geometry disp, Lisp_Object domain)
2323 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2326 query_string_geometry(IMAGE_INSTANCE_TEXT_STRING(ii),
2327 IMAGE_INSTANCE_FACE(ii),
2328 width, height, &descent, domain);
2330 /* The descent gets set as a side effect of querying the
2332 IMAGE_INSTANCE_TEXT_DESCENT(ii) = descent;
2335 /* set the properties of a string */
2336 static void text_update(Lisp_Object image_instance, Lisp_Object instantiator)
2338 Lisp_Object val = find_keyword_in_vector(instantiator, Q_data);
2342 XIMAGE_INSTANCE_TEXT_STRING(image_instance) = val;
2346 /****************************************************************************
2347 * formatted-string *
2348 ****************************************************************************/
2350 static void formatted_string_validate(Lisp_Object instantiator)
2352 data_must_be_present(instantiator);
2355 static int formatted_string_possible_dest_types(void)
2357 return IMAGE_TEXT_MASK;
2361 formatted_string_instantiate(Lisp_Object image_instance,
2362 Lisp_Object instantiator,
2363 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2364 int dest_mask, Lisp_Object domain)
2366 /* #### implement this */
2367 warn_when_safe(Qunimplemented, Qnotice,
2368 "`formatted-string' not yet implemented; assuming `string'");
2370 string_instantiate(image_instance, instantiator,
2371 pointer_fg, pointer_bg, dest_mask, domain);
2374 /************************************************************************/
2375 /* pixmap file functions */
2376 /************************************************************************/
2378 /* If INSTANTIATOR refers to inline data, return Qnil.
2379 If INSTANTIATOR refers to data in a file, return the full filename
2380 if it exists; otherwise, return a cons of (filename).
2382 FILE_KEYWORD and DATA_KEYWORD are symbols specifying the
2383 keywords used to look up the file and inline data,
2384 respectively, in the instantiator. Normally these would
2385 be Q_file and Q_data, but might be different for mask data. */
2388 potential_pixmap_file_instantiator(Lisp_Object instantiator,
2389 Lisp_Object file_keyword,
2390 Lisp_Object data_keyword,
2391 Lisp_Object console_type)
2396 assert(VECTORP(instantiator));
2398 data = find_keyword_in_vector(instantiator, data_keyword);
2399 file = find_keyword_in_vector(instantiator, file_keyword);
2401 if (!NILP(file) && NILP(data)) {
2402 Lisp_Object retval = MAYBE_LISP_CONTYPE_METH
2403 (decode_console_type(console_type, ERROR_ME),
2404 locate_pixmap_file, (file));
2409 return Fcons(file, Qnil); /* should have been file */
2416 simple_image_type_normalize(Lisp_Object inst, Lisp_Object console_type,
2417 Lisp_Object image_type_tag)
2419 /* This function can call lisp */
2420 Lisp_Object file = Qnil;
2421 struct gcpro gcpro1, gcpro2;
2422 Lisp_Object alist = Qnil;
2424 GCPRO2(file, alist);
2426 /* Now, convert any file data into inline data. At the end of this,
2427 `data' will contain the inline data (if any) or Qnil, and `file'
2428 will contain the name this data was derived from (if known) or
2431 Note that if we cannot generate any regular inline data, we
2434 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2437 if (CONSP(file)) /* failure locating filename */
2438 signal_double_file_error("Opening pixmap file",
2439 "no such file or directory",
2442 if (NILP(file)) /* no conversion necessary */
2443 RETURN_UNGCPRO(inst);
2445 alist = tagged_vector_to_alist(inst);
2448 Lisp_Object data = make_string_from_file(file);
2449 alist = remassq_no_quit(Q_file, alist);
2450 /* there can't be a :data at this point. */
2451 alist = Fcons(Fcons(Q_file, file),
2452 Fcons(Fcons(Q_data, data), alist));
2456 Lisp_Object result =
2457 alist_to_tagged_vector(image_type_tag, alist);
2459 RETURN_UNGCPRO(result);
2463 #ifdef HAVE_WINDOW_SYSTEM
2464 /**********************************************************************
2466 **********************************************************************/
2468 /* Check if DATA represents a valid inline XBM spec (i.e. a list
2469 of (width height bits), with checking done on the dimensions).
2470 If not, signal an error. */
2472 static void check_valid_xbm_inline(Lisp_Object data)
2474 Lisp_Object width, height, bits;
2477 !CONSP(XCDR(data)) ||
2478 !CONSP(XCDR(XCDR(data))) || !NILP(XCDR(XCDR(XCDR(data)))))
2479 signal_simple_error("Must be list of 3 elements", data);
2482 height = XCAR(XCDR(data));
2483 bits = XCAR(XCDR(XCDR(data)));
2487 if (!NATNUMP(width))
2488 signal_simple_error("Width must be a natural number", width);
2490 if (!NATNUMP(height))
2491 signal_simple_error("Height must be a natural number", height);
2493 if (((XINT(width) * XINT(height)) / 8) > XSTRING_CHAR_LENGTH(bits))
2494 signal_simple_error("data is too short for width and height",
2495 vector3(width, height, bits));
2498 /* Validate method for XBM's. */
2500 static void xbm_validate(Lisp_Object instantiator)
2502 file_or_data_must_be_present(instantiator);
2505 /* Given a filename that is supposed to contain XBM data, return
2506 the inline representation of it as (width height bits). Return
2507 the hotspot through XHOT and YHOT, if those pointers are not 0.
2508 If there is no hotspot, XHOT and YHOT will contain -1.
2510 If the function fails:
2512 -- if OK_IF_DATA_INVALID is set and the data was invalid,
2514 -- maybe return an error, or return Qnil.
2517 #ifdef HAVE_X_WINDOWS
2518 #include <X11/Xlib.h>
2520 #define XFree(data) free(data)
2524 bitmap_to_lisp_data(Lisp_Object name, int *xhot, int *yhot,
2525 int ok_if_data_invalid)
2530 const char *filename_ext;
2532 LISP_STRING_TO_EXTERNAL(name, filename_ext, Qfile_name);
2533 result = read_bitmap_data_from_file(filename_ext, &w, &h,
2534 (unsigned char **)((void*)&data),
2537 if (result == BitmapSuccess) {
2539 int len = (w + 7) / 8 * h;
2541 retval = list3(make_int(w), make_int(h),
2542 make_ext_string(data, len, Qbinary));
2548 case BitmapOpenFailed:
2550 /* should never happen */
2551 signal_double_file_error("Opening bitmap file",
2552 "no such file or directory",
2555 case BitmapFileInvalid:
2557 if (ok_if_data_invalid)
2559 signal_double_file_error("Reading bitmap file",
2560 "invalid data in file", name);
2562 case BitmapNoMemory:
2564 signal_double_file_error("Reading bitmap file",
2565 "out of memory", name);
2569 signal_double_file_error_2("Reading bitmap file",
2570 "unknown error code",
2571 make_int(result), name);
2575 return Qnil; /* not reached */
2579 xbm_mask_file_munging(Lisp_Object alist, Lisp_Object file,
2580 Lisp_Object mask_file, Lisp_Object console_type)
2582 /* This is unclean but it's fairly standard -- a number of the
2583 bitmaps in /usr/include/X11/bitmaps use it -- so we support
2586 /* don't override explicitly specified mask data. */
2587 && NILP(assq_no_quit(Q_mask_data, alist))
2589 mask_file = MAYBE_LISP_CONTYPE_METH
2590 (decode_console_type(console_type, ERROR_ME),
2591 locate_pixmap_file, (concat2(file, build_string("Mask"))));
2592 if (NILP(mask_file))
2593 mask_file = MAYBE_LISP_CONTYPE_METH
2594 (decode_console_type(console_type, ERROR_ME),
2596 (concat2(file, build_string("msk"))));
2599 if (!NILP(mask_file)) {
2600 Lisp_Object mask_data = bitmap_to_lisp_data(mask_file, 0, 0, 0);
2601 alist = remassq_no_quit(Q_mask_file, alist);
2602 /* there can't be a :mask-data at this point. */
2603 alist = Fcons(Fcons(Q_mask_file, mask_file),
2604 Fcons(Fcons(Q_mask_data, mask_data), alist));
2610 /* Normalize method for XBM's. */
2613 xbm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2615 Lisp_Object file = Qnil, mask_file = Qnil;
2616 struct gcpro gcpro1, gcpro2, gcpro3;
2617 Lisp_Object alist = Qnil;
2619 GCPRO3(file, mask_file, alist);
2621 /* Now, convert any file data into inline data for both the regular
2622 data and the mask data. At the end of this, `data' will contain
2623 the inline data (if any) or Qnil, and `file' will contain
2624 the name this data was derived from (if known) or Qnil.
2625 Likewise for `mask_file' and `mask_data'.
2627 Note that if we cannot generate any regular inline data, we
2630 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2632 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2636 if (CONSP(file)) /* failure locating filename */
2637 signal_double_file_error("Opening bitmap file",
2638 "no such file or directory",
2641 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2642 RETURN_UNGCPRO(inst);
2644 alist = tagged_vector_to_alist(inst);
2648 Lisp_Object data = bitmap_to_lisp_data(file, &xhot, &yhot, 0);
2649 alist = remassq_no_quit(Q_file, alist);
2650 /* there can't be a :data at this point. */
2651 alist = Fcons(Fcons(Q_file, file),
2652 Fcons(Fcons(Q_data, data), alist));
2654 if (xhot != -1 && NILP(assq_no_quit(Q_hotspot_x, alist)))
2655 alist = Fcons(Fcons(Q_hotspot_x, make_int(xhot)),
2657 if (yhot != -1 && NILP(assq_no_quit(Q_hotspot_y, alist)))
2658 alist = Fcons(Fcons(Q_hotspot_y, make_int(yhot)),
2662 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2665 Lisp_Object result = alist_to_tagged_vector(Qxbm, alist);
2667 RETURN_UNGCPRO(result);
2671 static int xbm_possible_dest_types(void)
2674 IMAGE_MONO_PIXMAP_MASK |
2675 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2681 /**********************************************************************
2683 **********************************************************************/
2685 static void xface_validate(Lisp_Object instantiator)
2687 file_or_data_must_be_present(instantiator);
2691 xface_normalize(Lisp_Object inst, Lisp_Object console_type,
2692 Lisp_Object dest_mask)
2694 /* This function can call lisp */
2695 Lisp_Object file = Qnil, mask_file = Qnil;
2696 struct gcpro gcpro1, gcpro2, gcpro3;
2697 Lisp_Object alist = Qnil;
2699 GCPRO3(file, mask_file, alist);
2701 /* Now, convert any file data into inline data for both the regular
2702 data and the mask data. At the end of this, `data' will contain
2703 the inline data (if any) or Qnil, and `file' will contain
2704 the name this data was derived from (if known) or Qnil.
2705 Likewise for `mask_file' and `mask_data'.
2707 Note that if we cannot generate any regular inline data, we
2710 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2712 mask_file = potential_pixmap_file_instantiator(inst, Q_mask_file,
2716 if (CONSP(file)) /* failure locating filename */
2717 signal_double_file_error("Opening bitmap file",
2718 "no such file or directory",
2721 if (NILP(file) && NILP(mask_file)) /* no conversion necessary */
2722 RETURN_UNGCPRO(inst);
2724 #ifdef HAVE_WINDOW_SYSTEM
2725 alist = tagged_vector_to_alist(inst);
2728 Lisp_Object data = make_string_from_file(file);
2729 alist = remassq_no_quit(Q_file, alist);
2730 /* there can't be a :data at this point. */
2731 alist = Fcons(Fcons(Q_file, file),
2732 Fcons(Fcons(Q_data, data), alist));
2735 alist = xbm_mask_file_munging(alist, file, mask_file, console_type);
2738 Lisp_Object result = alist_to_tagged_vector(Qxface, alist);
2740 RETURN_UNGCPRO(result);
2743 RETURN_UNGCPRO(Qnil);
2747 static int xface_possible_dest_types(void)
2750 IMAGE_MONO_PIXMAP_MASK |
2751 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2754 #endif /* HAVE_XFACE */
2758 /**********************************************************************
2760 **********************************************************************/
2763 /* Gtk has to be gratuitously different, eh? */
2764 Lisp_Object pixmap_to_lisp_data(Lisp_Object name, int ok_if_data_invalid)
2766 return (make_string_from_file(name));
2769 Lisp_Object pixmap_to_lisp_data(Lisp_Object name, int ok_if_data_invalid)
2775 LISP_STRING_TO_EXTERNAL(name, fname, Qfile_name);
2776 result = XpmReadFileToData(fname, &data);
2778 if (result == XpmSuccess) {
2779 Lisp_Object retval = Qnil;
2780 struct buffer *old_buffer = current_buffer;
2781 Lisp_Object temp_buffer =
2782 Fget_buffer_create(build_string(" *pixmap conversion*"));
2784 int height, width, ncolors;
2785 struct gcpro gcpro1, gcpro2, gcpro3;
2786 int speccount = specpdl_depth();
2788 GCPRO3(name, retval, temp_buffer);
2790 specbind(Qinhibit_quit, Qt);
2791 set_buffer_internal(XBUFFER(temp_buffer));
2792 Ferase_buffer(Qnil);
2794 buffer_insert_c_string(current_buffer, "/* XPM */\r");
2795 buffer_insert_c_string(current_buffer,
2796 "static char *pixmap[] = {\r");
2798 sscanf(data[0], "%d %d %d", &height, &width, &ncolors);
2799 for (elt = 0; elt <= width + ncolors; elt++) {
2800 buffer_insert_c_string(current_buffer, "\"");
2801 buffer_insert_c_string(current_buffer, data[elt]);
2803 if (elt < width + ncolors)
2804 buffer_insert_c_string(current_buffer, "\",\r");
2806 buffer_insert_c_string(current_buffer,
2810 retval = Fbuffer_substring(Qnil, Qnil, Qnil);
2813 set_buffer_internal(old_buffer);
2814 unbind_to(speccount, Qnil);
2816 RETURN_UNGCPRO(retval);
2820 case XpmFileInvalid:
2822 if (ok_if_data_invalid)
2824 signal_image_error("invalid XPM data in file", name);
2828 signal_double_file_error("Reading pixmap file",
2829 "out of memory", name);
2833 /* should never happen? */
2834 signal_double_file_error("Opening pixmap file",
2835 "no such file or directory",
2840 signal_double_file_error_2("Parsing pixmap file",
2841 "unknown error code",
2842 make_int(result), name);
2847 return Qnil; /* not reached */
2849 #endif /* !HAVE_GTK */
2851 static void check_valid_xpm_color_symbols(Lisp_Object data)
2855 for (rest = data; !NILP(rest); rest = XCDR(rest)) {
2857 !CONSP(XCAR(rest)) ||
2858 !STRINGP(XCAR(XCAR(rest))) ||
2859 (!STRINGP(XCDR(XCAR(rest))) &&
2860 !COLOR_SPECIFIERP(XCDR(XCAR(rest)))))
2861 signal_simple_error("Invalid color symbol alist", data);
2865 static void xpm_validate(Lisp_Object instantiator)
2867 file_or_data_must_be_present(instantiator);
2870 Lisp_Object Vxpm_color_symbols;
2872 Lisp_Object evaluate_xpm_color_symbols(void)
2874 Lisp_Object rest, results = Qnil;
2875 struct gcpro gcpro1, gcpro2;
2877 GCPRO2(rest, results);
2878 for (rest = Vxpm_color_symbols; !NILP(rest); rest = XCDR(rest)) {
2879 Lisp_Object name, value, cons;
2888 value = XCAR(value);
2889 value = Feval(value);
2892 if (!STRINGP(value) && !COLOR_SPECIFIERP(value))
2894 ("Result from xpm-color-symbols eval must be nil, string, or color",
2896 results = Fcons(Fcons(name, value), results);
2898 UNGCPRO; /* no more evaluation */
2903 xpm_normalize(Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
2905 Lisp_Object file = Qnil;
2906 Lisp_Object color_symbols;
2907 struct gcpro gcpro1, gcpro2;
2908 Lisp_Object alist = Qnil;
2910 GCPRO2(file, alist);
2912 /* Now, convert any file data into inline data. At the end of this,
2913 `data' will contain the inline data (if any) or Qnil, and
2914 `file' will contain the name this data was derived from (if
2917 Note that if we cannot generate any regular inline data, we
2920 file = potential_pixmap_file_instantiator(inst, Q_file, Q_data,
2923 if (CONSP(file)) /* failure locating filename */
2924 signal_double_file_error("Opening pixmap file",
2925 "no such file or directory",
2928 color_symbols = find_keyword_in_vector_or_given(inst, Q_color_symbols,
2931 if (NILP(file) && !UNBOUNDP(color_symbols))
2932 /* no conversion necessary */
2933 RETURN_UNGCPRO(inst);
2935 alist = tagged_vector_to_alist(inst);
2938 Lisp_Object data = pixmap_to_lisp_data(file, 0);
2939 alist = remassq_no_quit(Q_file, alist);
2940 /* there can't be a :data at this point. */
2941 alist = Fcons(Fcons(Q_file, file),
2942 Fcons(Fcons(Q_data, data), alist));
2945 if (UNBOUNDP(color_symbols)) {
2946 color_symbols = evaluate_xpm_color_symbols();
2947 alist = Fcons(Fcons(Q_color_symbols, color_symbols), alist);
2951 Lisp_Object result = alist_to_tagged_vector(Qxpm, alist);
2953 RETURN_UNGCPRO(result);
2957 static int xpm_possible_dest_types(void)
2960 IMAGE_MONO_PIXMAP_MASK |
2961 IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK;
2964 #endif /* HAVE_XPM */
2966 /****************************************************************************
2967 * Image Specifier Object *
2968 ****************************************************************************/
2970 DEFINE_SPECIFIER_TYPE(image);
2972 static void image_create(Lisp_Object obj)
2974 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2976 IMAGE_SPECIFIER_ALLOWED(image) = ~0; /* all are allowed */
2977 IMAGE_SPECIFIER_ATTACHEE(image) = Qnil;
2978 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = Qnil;
2981 static void image_mark(Lisp_Object obj)
2983 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
2985 mark_object(IMAGE_SPECIFIER_ATTACHEE(image));
2986 mark_object(IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image));
2989 static int instantiator_eq_equal(Lisp_Object obj1, Lisp_Object obj2)
2994 else if (CONSP(obj1) && CONSP(obj2)) {
2995 return instantiator_eq_equal(XCAR(obj1), XCAR(obj2))
2996 && instantiator_eq_equal(XCDR(obj1), XCDR(obj2));
3001 static hcode_t instantiator_eq_hash(Lisp_Object obj)
3004 /* no point in worrying about tail recursion, since we're not
3006 return HASH2(instantiator_eq_hash(XCAR(obj)),
3007 instantiator_eq_hash(XCDR(obj)));
3009 return LISP_HASH(obj);
3012 /* We need a special hash table for storing image instances. */
3013 Lisp_Object make_image_instance_cache_hash_table(void)
3015 return make_general_lisp_hash_table
3016 (instantiator_eq_hash, instantiator_eq_equal,
3017 30, -1.0, -1.0, HASH_TABLE_KEY_CAR_VALUE_WEAK);
3020 static Lisp_Object image_instantiate_cache_result(Lisp_Object locative)
3022 /* locative = (instance instantiator . subtable)
3024 So we are using the instantiator as the key and the instance as
3025 the value. Since the hashtable is key-weak this means that the
3026 image instance will stay around as long as the instantiator stays
3027 around. The instantiator is stored in the `image' slot of the
3028 glyph, so as long as the glyph is marked the instantiator will be
3029 as well and hence the cached image instance also. */
3030 Fputhash(XCAR(XCDR(locative)), XCAR(locative), XCDR(XCDR(locative)));
3031 free_cons(XCONS(XCDR(locative)));
3032 free_cons(XCONS(locative));
3036 /* Given a specification for an image, return an instance of
3037 the image which matches the given instantiator and which can be
3038 displayed in the given domain. */
3041 image_instantiate(Lisp_Object specifier, Lisp_Object matchspec,
3042 Lisp_Object domain, Lisp_Object instantiator,
3046 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3047 int dest_mask = XIMAGE_SPECIFIER_ALLOWED(specifier);
3048 int pointerp = dest_mask & image_instance_type_to_mask(IMAGE_POINTER);
3050 if (IMAGE_INSTANCEP(instantiator)) {
3051 /* make sure that the image instance's governing domain and type are
3053 Lisp_Object governing_domain =
3054 XIMAGE_INSTANCE_DOMAIN(instantiator);
3056 if ((DEVICEP(governing_domain)
3057 && EQ(governing_domain, DOMAIN_DEVICE(domain)))
3058 || (FRAMEP(governing_domain)
3059 && EQ(governing_domain, DOMAIN_FRAME(domain)))
3060 || (WINDOWP(governing_domain)
3061 && EQ(governing_domain, DOMAIN_WINDOW(domain)))) {
3063 image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE
3065 if (mask & dest_mask)
3066 return instantiator;
3069 ("Type of image instance not allowed here",
3072 signal_simple_error_2("Wrong domain for image instance",
3073 instantiator, domain);
3075 /* How ugly !! An image instanciator that uses a kludgy syntax to snarf in
3076 face properties. There's a design flaw here. -- didier */
3077 else if (VECTORP(instantiator)
3078 && EQ(INSTANTIATOR_TYPE(instantiator), Qinherit)) {
3079 assert(XVECTOR_LENGTH(instantiator) == 3);
3080 return (FACE_PROPERTY_INSTANCE
3081 (Fget_face(XVECTOR_DATA(instantiator)[2]),
3082 Qbackground_pixmap, domain, 1, depth));
3084 Lisp_Object instance = Qnil;
3085 Lisp_Object subtable = Qnil;
3086 /* #### Should this be GCPRO'd? */
3087 Lisp_Object hash_key = Qnil;
3088 Lisp_Object pointer_fg = Qnil;
3089 Lisp_Object pointer_bg = Qnil;
3090 Lisp_Object governing_domain =
3091 get_image_instantiator_governing_domain(instantiator,
3093 struct gcpro gcpro1;
3097 /* We have to put subwindow, widget and text image instances in
3098 a per-window cache so that we can see the same glyph in
3099 different windows. We use governing_domain to determine the type
3100 of image_instance that will be created. */
3103 pointer_fg = FACE_FOREGROUND(Vpointer_face, domain);
3104 pointer_bg = FACE_BACKGROUND(Vpointer_face, domain);
3105 hash_key = list4(glyph, INSTANTIATOR_TYPE(instantiator),
3106 pointer_fg, pointer_bg);
3108 /* We cannot simply key on the glyph since fallbacks could use
3109 the same glyph but have a totally different instantiator
3110 type. Thus we key on the glyph and the type (but not any
3111 other parts of the instantiator. */
3113 list2(glyph, INSTANTIATOR_TYPE(instantiator));
3115 /* First look in the device cache. */
3116 if (DEVICEP(governing_domain)) {
3117 subtable = Fgethash(make_int(dest_mask),
3118 XDEVICE(governing_domain)->
3119 image_instance_cache, Qunbound);
3120 if (UNBOUNDP(subtable)) {
3121 /* For the image instance cache, we do comparisons with
3122 EQ rather than with EQUAL, as we do for color and
3123 font names. The reasons are:
3125 1) pixmap data can be very long, and thus the hashing
3126 and comparing will take awhile.
3128 2) It's not so likely that we'll run into things that
3129 are EQUAL but not EQ (that can happen a lot with
3130 faces, because their specifiers are copied around);
3131 but pixmaps tend not to be in faces.
3133 However, if the image-instance could be a pointer, we
3134 have to use EQUAL because we massaged the
3135 instantiator into a cons3 also containing the
3136 foreground and background of the pointer face. */
3138 make_image_instance_cache_hash_table();
3140 Fputhash(make_int(dest_mask), subtable,
3141 XDEVICE(governing_domain)->
3142 image_instance_cache);
3143 instance = Qunbound;
3146 Fgethash(hash_key, subtable, Qunbound);
3148 } else if (WINDOWP(governing_domain)) {
3149 /* Subwindows have a per-window cache and have to be treated
3153 XWINDOW(governing_domain)->
3154 subwindow_instance_cache, Qunbound);
3156 abort(); /* We're not allowed anything else currently. */
3158 /* If we don't have an instance at this point then create
3160 if (UNBOUNDP(instance)) {
3161 Lisp_Object locative = noseeum_cons(Qnil,
3170 subwindow_instance_cache));
3171 int speccount = specpdl_depth();
3173 /* Make sure we cache the failures, too. Use an
3174 unwind-protect to catch such errors. If we fail, the
3175 unwind-protect records nil in the hash table. If we
3176 succeed, we change the car of the locative to the
3177 resulting instance, which gets recorded instead. */
3178 record_unwind_protect(image_instantiate_cache_result,
3181 instantiate_image_instantiator(governing_domain,
3182 domain, instantiator,
3187 /* We need a per-frame cache for redisplay. */
3188 cache_subwindow_instance_in_frame_maybe(instance);
3190 Fsetcar(locative, instance);
3191 #ifdef ERROR_CHECK_GLYPHS
3192 if (image_instance_type_to_mask
3193 (XIMAGE_INSTANCE_TYPE(instance))
3194 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3195 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3196 DOMAIN_FRAME(domain)));
3198 unbind_to(speccount, Qnil);
3199 #ifdef ERROR_CHECK_GLYPHS
3200 if (image_instance_type_to_mask
3201 (XIMAGE_INSTANCE_TYPE(instance))
3202 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3203 assert(EQ(Fgethash(hash_key,
3204 XWINDOW(governing_domain)
3205 ->subwindow_instance_cache,
3206 Qunbound), instance));
3208 } else if (NILP(instance))
3210 ("Can't instantiate image (probably cached)",
3212 /* We found an instance. However, because we are using the glyph
3213 as the hash key instead of the instantiator, the current
3214 instantiator may not be the same as the original. Thus we
3215 must update the instance based on the new
3216 instantiator. Preserving instance identity like this is
3217 important to stop excessive window system widget creation and
3218 deletion - and hence flashing. */
3220 /* #### This function should be able to cope with *all*
3221 changes to the instantiator, but currently only copes
3222 with the most used properties. This means that it is
3223 possible to make changes that don't get reflected in the
3225 update_image_instance(instance, instantiator);
3226 free_list(hash_key);
3229 #ifdef ERROR_CHECK_GLYPHS
3230 if (image_instance_type_to_mask(XIMAGE_INSTANCE_TYPE(instance))
3231 & (IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK))
3232 assert(EQ(XIMAGE_INSTANCE_FRAME(instance),
3233 DOMAIN_FRAME(domain)));
3235 ERROR_CHECK_IMAGE_INSTANCE(instance);
3236 RETURN_UNGCPRO(instance);
3240 return Qnil; /* not reached */
3243 /* Validate an image instantiator. */
3245 static void image_validate(Lisp_Object instantiator)
3247 if (IMAGE_INSTANCEP(instantiator) || STRINGP(instantiator))
3249 else if (VECTORP(instantiator)) {
3250 Lisp_Object *elt = XVECTOR_DATA(instantiator);
3251 int instantiator_len = XVECTOR_LENGTH(instantiator);
3252 struct image_instantiator_methods *meths;
3253 Lisp_Object already_seen = Qnil;
3254 struct gcpro gcpro1;
3257 if (instantiator_len < 1)
3258 signal_simple_error("Vector length must be at least 1",
3261 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3262 if (!(instantiator_len & 1))
3264 ("Must have alternating keyword/value pairs",
3267 GCPRO1(already_seen);
3269 for (i = 1; i < instantiator_len; i += 2) {
3270 Lisp_Object keyword = elt[i];
3271 Lisp_Object value = elt[i + 1];
3274 CHECK_SYMBOL(keyword);
3275 if (!SYMBOL_IS_KEYWORD(keyword))
3277 ("Symbol must begin with a colon", keyword);
3279 for (j = 0; j < Dynarr_length(meths->keywords); j++)
3282 Dynarr_at(meths->keywords, j).keyword))
3285 if (j == Dynarr_length(meths->keywords))
3286 signal_simple_error("Unrecognized keyword",
3289 if (!Dynarr_at(meths->keywords, j).multiple_p) {
3290 if (!NILP(memq_no_quit(keyword, already_seen)))
3292 ("Keyword may not appear more than once",
3294 already_seen = Fcons(keyword, already_seen);
3297 (Dynarr_at(meths->keywords, j).validate) (value);
3302 MAYBE_IIFORMAT_METH(meths, validate, (instantiator));
3304 signal_simple_error("Must be string or vector", instantiator);
3307 static void image_after_change(Lisp_Object specifier, Lisp_Object locale)
3309 Lisp_Object attachee =
3310 IMAGE_SPECIFIER_ATTACHEE(XIMAGE_SPECIFIER(specifier));
3311 Lisp_Object property =
3312 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(XIMAGE_SPECIFIER(specifier));
3313 if (FACEP(attachee)) {
3314 face_property_was_changed(attachee, property, locale);
3315 if (BUFFERP(locale))
3316 XBUFFER(locale)->buffer_local_face_property = 1;
3317 } else if (GLYPHP(attachee))
3318 glyph_property_was_changed(attachee, property, locale);
3322 set_image_attached_to(Lisp_Object obj, Lisp_Object face_or_glyph,
3323 Lisp_Object property)
3325 Lisp_Specifier *image = XIMAGE_SPECIFIER(obj);
3327 IMAGE_SPECIFIER_ATTACHEE(image) = face_or_glyph;
3328 IMAGE_SPECIFIER_ATTACHEE_PROPERTY(image) = property;
3332 image_going_to_add(Lisp_Object specifier, Lisp_Object locale,
3333 Lisp_Object tag_set, Lisp_Object instantiator)
3335 Lisp_Object possible_console_types = Qnil;
3337 Lisp_Object retlist = Qnil;
3338 struct gcpro gcpro1, gcpro2;
3340 LIST_LOOP(rest, Vconsole_type_list) {
3341 Lisp_Object contype = XCAR(rest);
3342 if (!NILP(memq_no_quit(contype, tag_set)))
3343 possible_console_types =
3344 Fcons(contype, possible_console_types);
3347 if (XINT(Flength(possible_console_types)) > 1)
3348 /* two conflicting console types specified */
3351 if (NILP(possible_console_types))
3352 possible_console_types = Vconsole_type_list;
3354 GCPRO2(retlist, possible_console_types);
3356 LIST_LOOP(rest, possible_console_types) {
3357 Lisp_Object contype = XCAR(rest);
3358 Lisp_Object newinst = call_with_suspended_errors
3359 ((lisp_fn_t) normalize_image_instantiator,
3360 Qnil, Qimage, ERROR_ME_NOT, 3, instantiator, contype,
3361 make_int(XIMAGE_SPECIFIER_ALLOWED(specifier)));
3363 if (!NILP(newinst)) {
3365 if (NILP(memq_no_quit(contype, tag_set)))
3366 newtag = Fcons(contype, tag_set);
3369 retlist = Fcons(Fcons(newtag, newinst), retlist);
3378 /* Copy an image instantiator. We can't use Fcopy_tree since widgets
3379 may contain circular references which would send Fcopy_tree into
3381 static Lisp_Object image_copy_vector_instantiator(Lisp_Object instantiator)
3384 struct image_instantiator_methods *meths;
3386 int instantiator_len;
3388 CHECK_VECTOR(instantiator);
3390 instantiator = Fcopy_sequence(instantiator);
3391 elt = XVECTOR_DATA(instantiator);
3392 instantiator_len = XVECTOR_LENGTH(instantiator);
3394 meths = decode_image_instantiator_format(elt[0], ERROR_ME);
3396 for (i = 1; i < instantiator_len; i += 2) {
3398 Lisp_Object keyword = elt[i];
3399 Lisp_Object value = elt[i + 1];
3401 /* Find the keyword entry. */
3402 for (j = 0; j < Dynarr_length(meths->keywords); j++) {
3403 if (EQ(keyword, Dynarr_at(meths->keywords, j).keyword))
3407 /* Only copy keyword values that should be copied. */
3408 if (Dynarr_at(meths->keywords, j).copy_p
3409 && (CONSP(value) || VECTORP(value))) {
3410 elt[i + 1] = Fcopy_tree(value, Qt);
3414 return instantiator;
3417 static Lisp_Object image_copy_instantiator(Lisp_Object arg)
3421 rest = arg = Fcopy_sequence(arg);
3422 while (CONSP(rest)) {
3423 Lisp_Object elt = XCAR(rest);
3425 XCAR(rest) = Fcopy_tree(elt, Qt);
3426 else if (VECTORP(elt))
3428 image_copy_vector_instantiator(elt);
3429 if (VECTORP(XCDR(rest))) /* hack for (a b . [c d]) */
3430 XCDR(rest) = Fcopy_tree(XCDR(rest), Qt);
3433 } else if (VECTORP(arg)) {
3434 arg = image_copy_vector_instantiator(arg);
3439 DEFUN("image-specifier-p", Fimage_specifier_p, 1, 1, 0, /*
3440 Return non-nil if OBJECT is an image specifier.
3441 See `make-image-specifier' for a description of image instantiators.
3445 return IMAGE_SPECIFIERP(object) ? Qt : Qnil;
3448 /****************************************************************************
3450 ****************************************************************************/
3452 static Lisp_Object mark_glyph(Lisp_Object obj)
3454 Lisp_Glyph *glyph = XGLYPH(obj);
3456 mark_object(glyph->image);
3457 mark_object(glyph->contrib_p);
3458 mark_object(glyph->baseline);
3459 mark_object(glyph->face);
3461 return glyph->plist;
3465 print_glyph(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
3467 Lisp_Glyph *glyph = XGLYPH(obj);
3469 error("printing unreadable object #<glyph 0x%x>",
3472 write_c_string("#<glyph (", printcharfun);
3473 print_internal(Fglyph_type(obj), printcharfun, 0);
3474 write_c_string(") ", printcharfun);
3475 print_internal(glyph->image, printcharfun, 1);
3476 write_fmt_str(printcharfun, "0x%x>", glyph->header.uid);
3479 /* Glyphs are equal if all of their display attributes are equal. We
3480 don't compare names or doc-strings, because that would make equal
3483 This isn't concerned with "unspecified" attributes, that's what
3484 #'glyph-differs-from-default-p is for. */
3485 static int glyph_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
3487 Lisp_Glyph *g1 = XGLYPH(obj1);
3488 Lisp_Glyph *g2 = XGLYPH(obj2);
3492 return (internal_equal(g1->image, g2->image, depth) &&
3493 internal_equal(g1->contrib_p, g2->contrib_p, depth) &&
3494 internal_equal(g1->baseline, g2->baseline, depth) &&
3495 internal_equal(g1->face, g2->face, depth) &&
3496 !plists_differ(g1->plist, g2->plist, 0, 0, depth + 1));
3499 static unsigned long glyph_hash(Lisp_Object obj, int depth)
3503 /* No need to hash all of the elements; that would take too long.
3504 Just hash the most common ones. */
3505 return HASH2(internal_hash(XGLYPH(obj)->image, depth),
3506 internal_hash(XGLYPH(obj)->face, depth));
3509 static Lisp_Object glyph_getprop(Lisp_Object obj, Lisp_Object prop)
3511 Lisp_Glyph *g = XGLYPH(obj);
3513 if (EQ(prop, Qimage))
3515 if (EQ(prop, Qcontrib_p))
3516 return g->contrib_p;
3517 if (EQ(prop, Qbaseline))
3519 if (EQ(prop, Qface))
3522 return external_plist_get(&g->plist, prop, 0, ERROR_ME);
3525 static int glyph_putprop(Lisp_Object obj, Lisp_Object prop, Lisp_Object value)
3527 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3530 if (EQ(prop, Qface)) {
3531 XGLYPH(obj)->face = Fget_face(value);
3535 external_plist_put(&XGLYPH(obj)->plist, prop, value, 0, ERROR_ME);
3539 static int glyph_remprop(Lisp_Object obj, Lisp_Object prop)
3541 if (EQ(prop, Qimage) || EQ(prop, Qcontrib_p) || EQ(prop, Qbaseline))
3544 if (EQ(prop, Qface)) {
3545 XGLYPH(obj)->face = Qnil;
3549 return external_remprop(&XGLYPH(obj)->plist, prop, 0, ERROR_ME);
3552 static Lisp_Object glyph_plist(Lisp_Object obj)
3554 Lisp_Glyph *glyph = XGLYPH(obj);
3555 Lisp_Object result = glyph->plist;
3557 result = cons3(Qface, glyph->face, result);
3558 result = cons3(Qbaseline, glyph->baseline, result);
3559 result = cons3(Qcontrib_p, glyph->contrib_p, result);
3560 result = cons3(Qimage, glyph->image, result);
3565 static const struct lrecord_description glyph_description[] = {
3566 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, image)},
3567 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, contrib_p)},
3568 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, baseline)},
3569 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, face)},
3570 {XD_LISP_OBJECT, offsetof(Lisp_Glyph, plist)},
3574 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS("glyph", glyph,
3575 mark_glyph, print_glyph, 0,
3576 glyph_equal, glyph_hash,
3577 glyph_description, glyph_getprop,
3578 glyph_putprop, glyph_remprop,
3579 glyph_plist, Lisp_Glyph);
3582 allocate_glyph(enum glyph_type type,
3583 void (*after_change) (Lisp_Object glyph, Lisp_Object property,
3584 Lisp_Object locale))
3586 /* This function can GC */
3587 Lisp_Object obj = Qnil;
3588 Lisp_Glyph *g = alloc_lcrecord_type(Lisp_Glyph, &lrecord_glyph);
3591 g->image = Fmake_specifier(Qimage); /* This function can GC */
3595 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3596 IMAGE_NOTHING_MASK | IMAGE_TEXT_MASK
3597 | IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
3598 | IMAGE_SUBWINDOW_MASK | IMAGE_WIDGET_MASK;
3601 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3602 IMAGE_NOTHING_MASK | IMAGE_POINTER_MASK;
3605 XIMAGE_SPECIFIER_ALLOWED(g->image) =
3606 IMAGE_NOTHING_MASK | IMAGE_MONO_PIXMAP_MASK
3607 | IMAGE_COLOR_PIXMAP_MASK;
3614 /* I think Fmake_specifier can GC. I think set_specifier_fallback can GC. */
3615 /* We're getting enough reports of odd behavior in this area it seems */
3616 /* best to GCPRO everything. */
3618 Lisp_Object tem1 = list1(Fcons(Qnil, Vthe_nothing_vector));
3619 Lisp_Object tem2 = list1(Fcons(Qnil, Qt));
3620 Lisp_Object tem3 = list1(Fcons(Qnil, Qnil));
3621 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3623 GCPRO4(obj, tem1, tem2, tem3);
3625 set_specifier_fallback(g->image, tem1);
3626 g->contrib_p = Fmake_specifier(Qboolean);
3627 set_specifier_fallback(g->contrib_p, tem2);
3628 /* #### should have a specifier for the following */
3629 g->baseline = Fmake_specifier(Qgeneric);
3630 set_specifier_fallback(g->baseline, tem3);
3633 g->after_change = after_change;
3636 set_image_attached_to(g->image, obj, Qimage);
3643 static enum glyph_type decode_glyph_type(Lisp_Object type, Error_behavior errb)
3646 return GLYPH_BUFFER;
3648 if (ERRB_EQ(errb, ERROR_ME))
3651 if (EQ(type, Qbuffer))
3652 return GLYPH_BUFFER;
3653 if (EQ(type, Qpointer))
3654 return GLYPH_POINTER;
3655 if (EQ(type, Qicon))
3658 maybe_signal_simple_error("Invalid glyph type", type, Qimage, errb);
3660 return GLYPH_UNKNOWN;
3663 static int valid_glyph_type_p(Lisp_Object type)
3665 return !NILP(memq_no_quit(type, Vglyph_type_list));
3668 DEFUN("valid-glyph-type-p", Fvalid_glyph_type_p, 1, 1, 0, /*
3669 Given a GLYPH-TYPE, return non-nil if it is valid.
3670 Valid types are `buffer', `pointer', and `icon'.
3674 return valid_glyph_type_p(glyph_type) ? Qt : Qnil;
3677 DEFUN("glyph-type-list", Fglyph_type_list, 0, 0, 0, /*
3678 Return a list of valid glyph types.
3682 return Fcopy_sequence(Vglyph_type_list);
3685 DEFUN("make-glyph-internal", Fmake_glyph_internal, 0, 1, 0, /*
3686 Create and return a new uninitialized glyph of type TYPE.
3688 TYPE specifies the type of the glyph; this should be one of `buffer',
3689 `pointer', or `icon', and defaults to `buffer'. The type of the glyph
3690 specifies in which contexts the glyph can be used, and controls the
3691 allowable image types into which the glyph's image can be
3694 `buffer' glyphs can be used as the begin-glyph or end-glyph of an
3695 extent, in the modeline, and in the toolbar. Their image can be
3696 instantiated as `nothing', `mono-pixmap', `color-pixmap', `text',
3699 `pointer' glyphs can be used to specify the mouse pointer. Their
3700 image can be instantiated as `pointer'.
3702 `icon' glyphs can be used to specify the icon used when a frame is
3703 iconified. Their image can be instantiated as `mono-pixmap' and
3708 enum glyph_type typeval = decode_glyph_type(type, ERROR_ME);
3709 return allocate_glyph(typeval, 0);
3712 DEFUN("glyphp", Fglyphp, 1, 1, 0, /*
3713 Return non-nil if OBJECT is a glyph.
3715 A glyph is an object used for pixmaps, widgets and the like. It is used
3716 in begin-glyphs and end-glyphs attached to extents, in marginal and textual
3717 annotations, in overlay arrows (overlay-arrow-* variables), in toolbar
3718 buttons, and the like. Much more detailed information can be found at
3719 `make-glyph'. Its image is described using an image specifier --
3720 see `make-image-specifier'. See also `make-image-instance' for further
3725 return GLYPHP(object) ? Qt : Qnil;
3728 DEFUN("glyph-type", Fglyph_type, 1, 1, 0, /*
3729 Return the type of the given glyph.
3730 The return value will be one of 'buffer, 'pointer, or 'icon.
3735 switch (XGLYPH_TYPE(glyph)) {
3749 glyph_image_instance(Lisp_Object glyph, Lisp_Object domain,
3750 Error_behavior errb, int no_quit)
3752 Lisp_Object specifier = GLYPH_IMAGE(XGLYPH(glyph));
3754 /* This can never return Qunbound. All glyphs have 'nothing as
3756 Lisp_Object image_instance = specifier_instance(specifier, Qunbound,
3757 domain, errb, no_quit,
3760 assert(!UNBOUNDP(image_instance));
3761 ERROR_CHECK_IMAGE_INSTANCE(image_instance);
3763 return image_instance;
3767 glyph_image_instance_maybe(Lisp_Object glyph_or_image, Lisp_Object window)
3769 Lisp_Object instance = glyph_or_image;
3771 if (GLYPHP(glyph_or_image))
3773 glyph_image_instance(glyph_or_image, window, ERROR_ME_NOT,
3779 /*****************************************************************************
3782 Return the width of the given GLYPH on the given WINDOW.
3783 Calculations are done based on recursively querying the geometry of
3784 the associated image instances.
3785 ****************************************************************************/
3786 unsigned short glyph_width(Lisp_Object glyph_or_image, Lisp_Object domain)
3788 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3790 if (!IMAGE_INSTANCEP(instance))
3793 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3794 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3795 IMAGE_UNSPECIFIED_GEOMETRY,
3796 IMAGE_UNCHANGED_GEOMETRY,
3797 IMAGE_UNCHANGED_GEOMETRY, domain);
3799 return XIMAGE_INSTANCE_WIDTH(instance);
3802 DEFUN("glyph-width", Fglyph_width, 1, 2, 0, /*
3803 Return the width of GLYPH on WINDOW.
3804 This may not be exact as it does not take into account all of the context
3805 that redisplay will.
3809 XSETWINDOW(window, decode_window(window));
3812 return make_int(glyph_width(glyph, window));
3815 unsigned short glyph_ascent(Lisp_Object glyph_or_image, Lisp_Object domain)
3817 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3819 if (!IMAGE_INSTANCEP(instance))
3822 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3823 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3824 IMAGE_UNSPECIFIED_GEOMETRY,
3825 IMAGE_UNCHANGED_GEOMETRY,
3826 IMAGE_UNCHANGED_GEOMETRY, domain);
3828 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3829 return XIMAGE_INSTANCE_TEXT_ASCENT(instance);
3831 return XIMAGE_INSTANCE_HEIGHT(instance);
3834 unsigned short glyph_descent(Lisp_Object glyph_or_image, Lisp_Object domain)
3836 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3838 if (!IMAGE_INSTANCEP(instance))
3841 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3842 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3843 IMAGE_UNSPECIFIED_GEOMETRY,
3844 IMAGE_UNCHANGED_GEOMETRY,
3845 IMAGE_UNCHANGED_GEOMETRY, domain);
3847 if (XIMAGE_INSTANCE_TYPE(instance) == IMAGE_TEXT)
3848 return XIMAGE_INSTANCE_TEXT_DESCENT(instance);
3853 /* strictly a convenience function. */
3854 unsigned short glyph_height(Lisp_Object glyph_or_image, Lisp_Object domain)
3856 Lisp_Object instance = glyph_image_instance_maybe(glyph_or_image,
3859 if (!IMAGE_INSTANCEP(instance))
3862 if (XIMAGE_INSTANCE_NEEDS_LAYOUT(instance))
3863 image_instance_layout(instance, IMAGE_UNSPECIFIED_GEOMETRY,
3864 IMAGE_UNSPECIFIED_GEOMETRY,
3865 IMAGE_UNCHANGED_GEOMETRY,
3866 IMAGE_UNCHANGED_GEOMETRY, domain);
3868 return XIMAGE_INSTANCE_HEIGHT(instance);
3871 DEFUN("glyph-ascent", Fglyph_ascent, 1, 2, 0, /*
3872 Return the ascent value of GLYPH on WINDOW.
3873 This may not be exact as it does not take into account all of the context
3874 that redisplay will.
3878 XSETWINDOW(window, decode_window(window));
3881 return make_int(glyph_ascent(glyph, window));
3884 DEFUN("glyph-descent", Fglyph_descent, 1, 2, 0, /*
3885 Return the descent value of GLYPH on WINDOW.
3886 This may not be exact as it does not take into account all of the context
3887 that redisplay will.
3891 XSETWINDOW(window, decode_window(window));
3894 return make_int(glyph_descent(glyph, window));
3897 /* This is redundant but I bet a lot of people expect it to exist. */
3898 DEFUN("glyph-height", Fglyph_height, 1, 2, 0, /*
3899 Return the height of GLYPH on WINDOW.
3900 This may not be exact as it does not take into account all of the context
3901 that redisplay will.
3905 XSETWINDOW(window, decode_window(window));
3908 return make_int(glyph_height(glyph, window));
3912 set_glyph_dirty_p(Lisp_Object glyph_or_image, Lisp_Object window, int dirty)
3914 Lisp_Object instance = glyph_or_image;
3916 if (!NILP(glyph_or_image)) {
3917 if (GLYPHP(glyph_or_image)) {
3918 instance = glyph_image_instance(glyph_or_image, window,
3920 XGLYPH_DIRTYP(glyph_or_image) = dirty;
3923 if (!IMAGE_INSTANCEP(instance))
3926 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3930 static void set_image_instance_dirty_p(Lisp_Object instance, int dirty)
3932 if (IMAGE_INSTANCEP(instance)) {
3933 XIMAGE_INSTANCE_DIRTYP(instance) = dirty;
3934 /* Now cascade up the hierarchy. */
3935 set_image_instance_dirty_p(XIMAGE_INSTANCE_PARENT(instance),
3937 } else if (GLYPHP(instance)) {
3938 XGLYPH_DIRTYP(instance) = dirty;
3942 /* #### do we need to cache this info to speed things up? */
3944 Lisp_Object glyph_baseline(Lisp_Object glyph, Lisp_Object domain)
3949 Lisp_Object retval =
3950 specifier_instance_no_quit(GLYPH_BASELINE(XGLYPH(glyph)),
3951 /* #### look into ERROR_ME_NOT */
3952 Qunbound, domain, ERROR_ME_NOT,
3954 if (!NILP(retval) && !INTP(retval))
3956 else if (INTP(retval)) {
3957 if (XINT(retval) < 0)
3959 if (XINT(retval) > 100)
3960 retval = make_int(100);
3966 Lisp_Object glyph_face(Lisp_Object glyph, Lisp_Object domain)
3968 /* #### Domain parameter not currently used but it will be */
3969 return GLYPHP(glyph) ? GLYPH_FACE(XGLYPH(glyph)) : Qnil;
3972 int glyph_contrib_p(Lisp_Object glyph, Lisp_Object domain)
3977 return !NILP(specifier_instance_no_quit
3978 (GLYPH_CONTRIB_P(XGLYPH(glyph)), Qunbound, domain,
3979 /* #### look into ERROR_ME_NOT */
3980 ERROR_ME_NOT, 0, Qzero));
3984 glyph_property_was_changed(Lisp_Object glyph, Lisp_Object property,
3987 if (XGLYPH(glyph)->after_change)
3988 (XGLYPH(glyph)->after_change) (glyph, property, locale);
3992 glyph_query_geometry(Lisp_Object glyph_or_image, int *width, int *height,
3993 enum image_instance_geometry disp, Lisp_Object domain)
3995 Lisp_Object instance = glyph_or_image;
3997 if (GLYPHP(glyph_or_image))
3999 glyph_image_instance(glyph_or_image, domain, ERROR_ME_NOT,
4002 image_instance_query_geometry(instance, width, height, disp, domain);
4006 glyph_do_layout(Lisp_Object glyph_or_image, int width, int height,
4007 int xoffset, int yoffset, 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_layout(instance, width, height, xoffset, yoffset,
4020 /*****************************************************************************
4021 * glyph cachel functions *
4022 *****************************************************************************/
4024 /* #### All of this is 95% copied from face cachels. Consider
4027 Why do we need glyph_cachels? Simply because a glyph_cachel captures
4028 per-window information about a particular glyph. A glyph itself is
4029 not created in any particular context, so if we were to rely on a
4030 glyph to tell us about its dirtiness we would not be able to reset
4031 the dirty flag after redisplaying it as it may exist in other
4032 contexts. When we have redisplayed we need to know which glyphs to
4033 reset the dirty flags on - the glyph_cachels give us a nice list we
4034 can iterate through doing this. */
4035 void mark_glyph_cachels(glyph_cachel_dynarr * elements)
4042 for (elt = 0; elt < Dynarr_length(elements); elt++) {
4043 struct glyph_cachel *cachel = Dynarr_atp(elements, elt);
4044 mark_object(cachel->glyph);
4049 update_glyph_cachel_data(struct window *w, Lisp_Object glyph,
4050 struct glyph_cachel *cachel)
4052 if (!cachel->updated || NILP(cachel->glyph) || !EQ(cachel->glyph, glyph)
4053 || XGLYPH_DIRTYP(cachel->glyph)
4054 || XFRAME(WINDOW_FRAME(w))->faces_changed) {
4055 Lisp_Object window, instance;
4057 XSETWINDOW(window, w);
4059 cachel->glyph = glyph;
4060 /* Speed things up slightly by grabbing the glyph instantiation
4061 and passing it to the size functions. */
4062 instance = glyph_image_instance(glyph, window, ERROR_ME_NOT, 1);
4064 if (!IMAGE_INSTANCEP(instance))
4067 /* Mark text instance of the glyph dirty if faces have changed,
4068 because its geometry might have changed. */
4069 invalidate_glyph_geometry_maybe(instance, w);
4071 /* #### Do the following 2 lines buy us anything? --kkm */
4072 XGLYPH_DIRTYP(glyph) = XIMAGE_INSTANCE_DIRTYP(instance);
4073 cachel->dirty = XGLYPH_DIRTYP(glyph);
4074 cachel->width = glyph_width(instance, window);
4075 cachel->ascent = glyph_ascent(instance, window);
4076 cachel->descent = glyph_descent(instance, window);
4079 cachel->updated = 1;
4082 static void add_glyph_cachel(struct window *w, Lisp_Object glyph)
4084 struct glyph_cachel new_cachel;
4087 new_cachel.glyph = Qnil;
4089 update_glyph_cachel_data(w, glyph, &new_cachel);
4090 Dynarr_add(w->glyph_cachels, new_cachel);
4093 glyph_index get_glyph_cachel_index(struct window *w, Lisp_Object glyph)
4100 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4101 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4103 if (EQ(cachel->glyph, glyph) && !NILP(glyph)) {
4104 update_glyph_cachel_data(w, glyph, cachel);
4109 /* If we didn't find the glyph, add it and then return its index. */
4110 add_glyph_cachel(w, glyph);
4114 void reset_glyph_cachels(struct window *w)
4116 Dynarr_reset(w->glyph_cachels);
4117 get_glyph_cachel_index(w, Vcontinuation_glyph);
4118 get_glyph_cachel_index(w, Vtruncation_glyph);
4119 get_glyph_cachel_index(w, Vhscroll_glyph);
4120 get_glyph_cachel_index(w, Vcontrol_arrow_glyph);
4121 get_glyph_cachel_index(w, Voctal_escape_glyph);
4122 get_glyph_cachel_index(w, Vinvisible_text_glyph);
4125 void mark_glyph_cachels_as_not_updated(struct window *w)
4129 /* We need to have a dirty flag to tell if the glyph has changed.
4130 We can check to see if each glyph variable is actually a
4131 completely different glyph, though. */
4132 #define FROB(glyph_obj, gindex) \
4133 update_glyph_cachel_data (w, glyph_obj, \
4134 Dynarr_atp (w->glyph_cachels, gindex))
4136 FROB(Vcontinuation_glyph, CONT_GLYPH_INDEX);
4137 FROB(Vtruncation_glyph, TRUN_GLYPH_INDEX);
4138 FROB(Vhscroll_glyph, HSCROLL_GLYPH_INDEX);
4139 FROB(Vcontrol_arrow_glyph, CONTROL_GLYPH_INDEX);
4140 FROB(Voctal_escape_glyph, OCT_ESC_GLYPH_INDEX);
4141 FROB(Vinvisible_text_glyph, INVIS_GLYPH_INDEX);
4144 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4145 Dynarr_atp(w->glyph_cachels, elt)->updated = 0;
4149 /* Unset the dirty bit on all the glyph cachels that have it. */
4150 void mark_glyph_cachels_as_clean(struct window *w)
4154 XSETWINDOW(window, w);
4155 for (elt = 0; elt < Dynarr_length(w->glyph_cachels); elt++) {
4156 struct glyph_cachel *cachel = Dynarr_atp(w->glyph_cachels, elt);
4158 set_glyph_dirty_p(cachel->glyph, window, 0);
4162 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
4165 compute_glyph_cachel_usage(glyph_cachel_dynarr * glyph_cachels,
4166 struct overhead_stats *ovstats)
4171 total += Dynarr_memory_usage(glyph_cachels, ovstats);
4176 #endif /* MEMORY_USAGE_STATS */
4178 /*****************************************************************************
4179 * subwindow cachel functions *
4180 *****************************************************************************/
4181 /* Subwindows are curious in that you have to physically unmap them to
4182 not display them. It is problematic deciding what to do in
4183 redisplay. We have two caches - a per-window instance cache that
4184 keeps track of subwindows on a window, these are linked to their
4185 instantiator in the hashtable and when the instantiator goes away
4186 we want the instance to go away also. However we also have a
4187 per-frame instance cache that we use to determine if a subwindow is
4188 obscuring an area that we want to clear. We need to be able to flip
4189 through this quickly so a hashtable is not suitable hence the
4190 subwindow_cachels. This is a weak list so unreference instances
4191 will get deleted properly. */
4193 /* redisplay in general assumes that drawing something will erase
4194 what was there before. unfortunately this does not apply to
4195 subwindows that need to be specifically unmapped in order to
4196 disappear. we take a brute force approach - on the basis that its
4197 cheap - and unmap all subwindows in a display line */
4199 /* Put new instances in the frame subwindow cache. This is less costly than
4200 doing it every time something gets mapped, and deleted instances will be
4201 removed automatically. */
4202 static void cache_subwindow_instance_in_frame_maybe(Lisp_Object instance)
4204 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(instance);
4205 if (!NILP(DOMAIN_FRAME(IMAGE_INSTANCE_DOMAIN(ii)))) {
4206 struct frame *f = DOMAIN_XFRAME(IMAGE_INSTANCE_DOMAIN(ii));
4207 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4209 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f)));
4213 /* Unmap and finalize all subwindow instances in the frame cache. This
4214 is necessary because GC will not guarantee the order things get
4215 deleted in and moreover, frame finalization deletes the window
4216 system windows before deleting SXEmacs windows, and hence
4219 unmap_subwindow_instance_cache_mapper(Lisp_Object key, Lisp_Object value,
4222 /* value can be nil; we cache failures as well as successes */
4224 struct frame *f = XFRAME(XIMAGE_INSTANCE_FRAME(value));
4225 unmap_subwindow(value);
4227 /* In case GC doesn't catch up fast enough, remove from the frame
4228 cache also. Otherwise code that checks the sanity of the instance
4230 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))
4231 = delq_no_quit(value,
4232 XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE
4234 finalize_image_instance(XIMAGE_INSTANCE(value), 0);
4240 static void finalize_all_subwindow_instances(struct window *w)
4243 finalize_all_subwindow_instances(XWINDOW(w->next));
4244 if (!NILP(w->vchild))
4245 finalize_all_subwindow_instances(XWINDOW(w->vchild));
4246 if (!NILP(w->hchild))
4247 finalize_all_subwindow_instances(XWINDOW(w->hchild));
4249 elisp_maphash(unmap_subwindow_instance_cache_mapper,
4250 w->subwindow_instance_cache, (void *)1);
4253 void free_frame_subwindow_instances(struct frame *f)
4255 /* Make sure all instances are finalized. We have to do this via the
4256 instance cache since some instances may be extant but not
4257 displayed (and hence not in the frame cache). */
4258 finalize_all_subwindow_instances(XWINDOW(f->root_window));
4261 /* Unmap all instances in the frame cache. */
4262 void reset_frame_subwindow_instance_cache(struct frame *f)
4266 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4267 Lisp_Object value = XCAR(rest);
4268 unmap_subwindow(value);
4272 /*****************************************************************************
4273 * subwindow exposure ignorance *
4274 *****************************************************************************/
4275 /* when we unmap subwindows the associated window system will generate
4276 expose events. This we do not want as redisplay already copes with
4277 the repainting necessary. Worse, we can get in an endless cycle of
4278 redisplay if we are not careful. Thus we keep a per-frame list of
4279 expose events that are going to come and ignore them as
4282 struct expose_ignore_blocktype {
4283 Blocktype_declare(struct expose_ignore);
4284 } *the_expose_ignore_blocktype;
4287 check_for_ignored_expose(struct frame *f, int x, int y, int width, int height)
4289 struct expose_ignore *ei, *prev;
4290 /* the ignore list is FIFO so we should generally get a match with
4291 the first element in the list */
4292 for (ei = f->subwindow_exposures, prev = 0; ei; ei = ei->next) {
4293 /* Checking for exact matches just isn't good enough as we
4294 might get exposures for partially obscured subwindows, thus
4295 we have to check for overlaps. Being conservative, we will
4296 check for exposures wholly contained by the subwindow - this
4297 might give us what we want. */
4298 if (ei->x <= (unsigned)x && ei->y <= (unsigned)y
4299 && ei->x + ei->width >= (unsigned)(x + width)
4300 && ei->y + ei->height >= (unsigned)(y + height)) {
4301 #ifdef DEBUG_WIDGETS
4303 ("ignored %d+%d, %dx%d for exposure %d+%d, %dx%d\n",
4304 x, y, width, height, ei->x, ei->y, ei->width,
4308 f->subwindow_exposures = ei->next;
4310 prev->next = ei->next;
4312 if (ei == f->subwindow_exposures_tail)
4313 f->subwindow_exposures_tail = prev;
4315 Blocktype_free(the_expose_ignore_blocktype, ei);
4324 register_ignored_expose(struct frame *f, int x, int y, int width, int height)
4326 if (!hold_ignored_expose_registration) {
4327 struct expose_ignore *ei;
4329 ei = Blocktype_alloc(the_expose_ignore_blocktype);
4335 ei->height = height;
4337 /* we have to add the exposure to the end of the list, since we
4338 want to check the oldest events first. for speed we keep a record
4339 of the end so that we can add right to it. */
4340 if (f->subwindow_exposures_tail) {
4341 f->subwindow_exposures_tail->next = ei;
4343 if (!f->subwindow_exposures) {
4344 f->subwindow_exposures = ei;
4346 f->subwindow_exposures_tail = ei;
4350 /****************************************************************************
4351 find_matching_subwindow
4353 See if there is a subwindow that completely encloses the requested
4355 ****************************************************************************/
4356 int find_matching_subwindow(struct frame *f, int x, int y, int width,
4361 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4362 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(XCAR(rest));
4364 if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii)
4366 IMAGE_INSTANCE_DISPLAY_X(ii) <= (unsigned)x
4368 IMAGE_INSTANCE_DISPLAY_Y(ii) <= (unsigned)y
4369 && IMAGE_INSTANCE_DISPLAY_X(ii)
4370 + IMAGE_INSTANCE_DISPLAY_WIDTH(ii) >= (unsigned)(x + width)
4371 && IMAGE_INSTANCE_DISPLAY_Y(ii)
4372 + IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) >=
4373 (unsigned)(y + height)) {
4380 /*****************************************************************************
4381 * subwindow functions *
4382 *****************************************************************************/
4384 /* Update the displayed characteristics of a subwindow. This function
4385 should generally only get called if the subwindow is actually
4387 void redisplay_subwindow(Lisp_Object subwindow)
4389 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4390 int count = specpdl_depth();
4392 /* The update method is allowed to call eval. Since it is quite
4393 common for this function to get called from somewhere in
4394 redisplay we need to make sure that quits are ignored. Otherwise
4395 Fsignal will abort. */
4396 specbind(Qinhibit_quit, Qt);
4398 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4400 if (WIDGET_IMAGE_INSTANCEP(subwindow)) {
4401 if (image_instance_changed(subwindow))
4402 redisplay_widget(subwindow);
4403 /* Reset the changed flags. */
4404 IMAGE_INSTANCE_WIDGET_FACE_CHANGED(ii) = 0;
4405 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii) = 0;
4406 IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii) = 0;
4407 IMAGE_INSTANCE_TEXT_CHANGED(ii) = 0;
4408 } else if (IMAGE_INSTANCE_TYPE(ii) == IMAGE_SUBWINDOW
4409 && !NILP(IMAGE_INSTANCE_FRAME(ii))) {
4410 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4411 redisplay_subwindow, (ii));
4414 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 0;
4415 /* This function is typically called by redisplay just before
4416 outputting the information to the screen. Thus we record a hash
4417 of the output to determine whether on-screen is the same as
4418 recorded structure. This approach has limitations in there is a
4419 good chance that hash values will be different for the same
4420 visual appearance. However, we would rather that then the other
4421 way round - it simply means that we will get more displays than
4422 we might need. We can get better hashing by making the depth
4423 negative - currently it will recurse down 7 levels. */
4424 IMAGE_INSTANCE_DISPLAY_HASH(ii) = internal_hash(subwindow,
4425 IMAGE_INSTANCE_HASH_DEPTH);
4427 unbind_to(count, Qnil);
4430 /* Determine whether an image_instance has changed structurally and
4431 hence needs redisplaying in some way.
4433 #### This should just look at the instantiator differences when we
4434 get rid of the stored items altogether. In fact we should probably
4435 store the new instantiator as well as the old - as we do with
4436 gui_items currently - and then pick-up the new on the next
4437 redisplay. This would obviate the need for any of this trickery
4439 int image_instance_changed(Lisp_Object subwindow)
4441 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4443 if (internal_hash(subwindow, IMAGE_INSTANCE_HASH_DEPTH) !=
4444 IMAGE_INSTANCE_DISPLAY_HASH(ii))
4446 /* #### I think there is probably a bug here. This gets called for
4447 layouts - and yet the pending items are always nil for
4448 layouts. We are saved by layout optimization, but I'm undecided
4449 as to what the correct fix is. */
4450 else if (WIDGET_IMAGE_INSTANCEP(subwindow)
4451 && (!internal_equal(IMAGE_INSTANCE_WIDGET_ITEMS(ii),
4452 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii), 0)
4453 || !NILP(IMAGE_INSTANCE_LAYOUT_CHILDREN(ii))
4454 || IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii)))
4460 /* Update all the subwindows on a frame. */
4461 void update_widget_instances(Lisp_Object frame)
4466 /* Its possible for the preceding callback to have deleted the
4467 frame, so cope with this. */
4468 if (!FRAMEP(frame) || !FRAME_LIVE_P(XFRAME(frame)))
4474 /* If we get called we know something has changed. */
4475 LIST_LOOP(rest, XWEAK_LIST_LIST(FRAME_SUBWINDOW_CACHE(f))) {
4476 Lisp_Object widget = XCAR(rest);
4478 if (XIMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(widget)
4479 && image_instance_changed(widget)) {
4480 set_image_instance_dirty_p(widget, 1);
4481 MARK_FRAME_GLYPHS_CHANGED(f);
4486 /* remove a subwindow from its frame */
4487 void unmap_subwindow(Lisp_Object subwindow)
4489 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4492 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4494 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4495 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK))
4496 || !IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii))
4499 #ifdef DEBUG_WIDGETS
4500 stderr_out("unmapping subwindow %p\n", IMAGE_INSTANCE_SUBWINDOW_ID(ii));
4502 f = XFRAME(IMAGE_INSTANCE_FRAME(ii));
4504 /* make sure we don't get expose events */
4505 register_ignored_expose(f, IMAGE_INSTANCE_DISPLAY_X(ii),
4506 IMAGE_INSTANCE_DISPLAY_Y(ii),
4507 IMAGE_INSTANCE_DISPLAY_WIDTH(ii),
4508 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii));
4509 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4511 MAYBE_DEVMETH(XDEVICE(IMAGE_INSTANCE_DEVICE(ii)),
4512 unmap_subwindow, (ii));
4515 /* show a subwindow in its frame */
4516 void map_subwindow(Lisp_Object subwindow, int x, int y,
4517 struct display_glyph_area *dga)
4519 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(subwindow);
4521 ERROR_CHECK_IMAGE_INSTANCE(subwindow);
4523 if (!(image_instance_type_to_mask(IMAGE_INSTANCE_TYPE(ii))
4524 & (IMAGE_WIDGET_MASK | IMAGE_SUBWINDOW_MASK)))
4527 #ifdef DEBUG_WIDGETS
4528 stderr_out("mapping subwindow %p, %dx%d@%d+%d\n",
4529 IMAGE_INSTANCE_SUBWINDOW_ID(ii),
4530 dga->width, dga->height, x, y);
4532 (void)XFRAME(IMAGE_INSTANCE_FRAME(ii));
4533 IMAGE_INSTANCE_DISPLAY_X(ii) = x;
4534 IMAGE_INSTANCE_DISPLAY_Y(ii) = y;
4535 IMAGE_INSTANCE_DISPLAY_WIDTH(ii) = dga->width;
4536 IMAGE_INSTANCE_DISPLAY_HEIGHT(ii) = dga->height;
4538 MAYBE_DEVMETH(DOMAIN_XDEVICE(ii->domain),
4539 map_subwindow, (ii, x, y, dga));
4540 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 1;
4543 static int subwindow_possible_dest_types(void)
4545 return IMAGE_SUBWINDOW_MASK;
4548 int subwindow_governing_domain(void)
4550 return GOVERNING_DOMAIN_WINDOW;
4553 /* Partially instantiate a subwindow. */
4555 subwindow_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
4556 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
4557 int dest_mask, Lisp_Object domain)
4559 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
4560 Lisp_Object device = image_instance_device(image_instance);
4561 Lisp_Object frame = DOMAIN_FRAME(domain);
4562 Lisp_Object width = find_keyword_in_vector(instantiator, Q_pixel_width);
4563 Lisp_Object height =
4564 find_keyword_in_vector(instantiator, Q_pixel_height);
4567 signal_simple_error("No selected frame", device);
4569 if (!(dest_mask & IMAGE_SUBWINDOW_MASK))
4570 incompatible_image_types(instantiator, dest_mask,
4571 IMAGE_SUBWINDOW_MASK);
4574 IMAGE_INSTANCE_SUBWINDOW_ID(ii) = 0;
4575 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(ii) = 0;
4579 if (XINT(width) > 1)
4581 IMAGE_INSTANCE_WIDTH(ii) = w;
4582 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP(ii) = 0;
4587 if (XINT(height) > 1)
4589 IMAGE_INSTANCE_HEIGHT(ii) = h;
4590 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP(ii) = 0;
4594 #ifdef HAVE_X_WINDOWS
4595 extern void x_subwindow_query_geometry(Lisp_Object image_instance,
4596 int *width, int *height);
4599 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4600 int *height, enum image_instance_geometry disp,
4603 if (IMAGE_INSTANCE_INITIALIZED(XIMAGE_INSTANCE(image_instance)))
4605 /* Query real size of subwindow */
4606 x_subwindow_query_geometry(image_instance, width, height);
4608 /* Set them in case of initial layout instantiation */
4616 /* This is just a backup in case no-one has assigned a suitable geometry.
4617 #### It should really query the enclose window for geometry. */
4619 subwindow_query_geometry(Lisp_Object image_instance, int *width,
4620 int *height, enum image_instance_geometry disp,
4628 #endif /* HAVE_X_WINDOWS */
4630 DEFUN("subwindowp", Fsubwindowp, 1, 1, 0, /*
4631 Return non-nil if OBJECT is a subwindow.
4635 CHECK_IMAGE_INSTANCE(object);
4636 return (XIMAGE_INSTANCE_TYPE(object) == IMAGE_SUBWINDOW) ? Qt : Qnil;
4639 DEFUN("image-instance-subwindow-id", Fimage_instance_subwindow_id, 1, 1, 0, /*
4640 Return the window id of SUBWINDOW as a number.
4644 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4645 return make_int((EMACS_INT) XIMAGE_INSTANCE_SUBWINDOW_ID(subwindow));
4648 DEFUN("resize-subwindow", Fresize_subwindow, 1, 3, 0, /*
4649 Resize SUBWINDOW to WIDTH x HEIGHT.
4650 If a value is nil that parameter is not changed.
4652 (subwindow, width, height))
4655 Lisp_Image_Instance *ii;
4657 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4658 ii = XIMAGE_INSTANCE(subwindow);
4661 neww = IMAGE_INSTANCE_WIDTH(ii);
4666 newh = IMAGE_INSTANCE_HEIGHT(ii);
4668 newh = XINT(height);
4670 /* The actual resizing gets done asynchronously by
4671 update_subwindow. */
4672 IMAGE_INSTANCE_HEIGHT(ii) = newh;
4673 IMAGE_INSTANCE_WIDTH(ii) = neww;
4674 IMAGE_INSTANCE_SIZE_CHANGED(ii) = 1;
4679 DEFUN("force-subwindow-map", Fforce_subwindow_map, 1, 1, 0, /*
4680 Generate a Map event for SUBWINDOW.
4684 CHECK_SUBWINDOW_IMAGE_INSTANCE(subwindow);
4686 map_subwindow(subwindow, 0, 0);
4691 /*****************************************************************************
4693 *****************************************************************************/
4695 /* Get the display tables for use currently on window W with face
4696 FACE. #### This will have to be redone. */
4699 get_display_tables(struct window *w, face_index findex,
4700 Lisp_Object * face_table, Lisp_Object * window_table)
4703 tem = WINDOW_FACE_CACHEL_DISPLAY_TABLE(w, findex);
4707 tem = noseeum_cons(tem, Qnil);
4709 tem = w->display_table;
4713 tem = noseeum_cons(tem, Qnil);
4714 *window_table = tem;
4718 display_table_entry(Emchar ch, Lisp_Object face_table, Lisp_Object window_table)
4722 /* Loop over FACE_TABLE, and then over WINDOW_TABLE. */
4723 for (tail = face_table; 1; tail = XCDR(tail)) {
4726 if (!NILP(window_table)) {
4727 tail = window_table;
4728 window_table = Qnil;
4734 if (VECTORP(table)) {
4735 if (ch < XVECTOR_LENGTH(table)
4736 && !NILP(XVECTOR_DATA(table)[ch]))
4737 return XVECTOR_DATA(table)[ch];
4740 } else if (CHAR_TABLEP(table)
4741 && XCHAR_TABLE_TYPE(table) == CHAR_TABLE_TYPE_CHAR) {
4742 return get_char_table(ch, XCHAR_TABLE(table));
4743 } else if (CHAR_TABLEP(table)
4744 && XCHAR_TABLE_TYPE(table) ==
4745 CHAR_TABLE_TYPE_GENERIC) {
4747 get_char_table(ch, XCHAR_TABLE(table));
4752 } else if (RANGE_TABLEP(table)) {
4754 Fget_range_table(make_char(ch), table, Qnil);
4764 /*****************************************************************************
4765 * timeouts for animated glyphs *
4766 *****************************************************************************/
4767 static Lisp_Object Qglyph_animated_timeout_handler;
4769 DEFUN("glyph-animated-timeout-handler", Fglyph_animated_timeout_handler, 1, 1, 0, /*
4770 Callback function for updating animated images.
4775 CHECK_WEAK_LIST(arg);
4777 if (!NILP(XWEAK_LIST_LIST(arg)) && !NILP(XCAR(XWEAK_LIST_LIST(arg)))) {
4778 Lisp_Object value = XCAR(XWEAK_LIST_LIST(arg));
4780 if (IMAGE_INSTANCEP(value)) {
4781 Lisp_Image_Instance *ii = XIMAGE_INSTANCE(value);
4783 if (COLOR_PIXMAP_IMAGE_INSTANCEP(value)
4785 IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii) > 1
4786 && !disable_animated_pixmaps) {
4788 /* Increment the index of the image slice we are
4789 currently viewing. */
4790 IMAGE_INSTANCE_PIXMAP_SLICE(ii) =
4791 (IMAGE_INSTANCE_PIXMAP_SLICE(ii) + 1)
4792 % IMAGE_INSTANCE_PIXMAP_MAXSLICE(ii);
4793 /* We might need to kick redisplay at this point
4794 - but we also might not. */
4795 tmp = image_instance_device(value);
4796 MARK_DEVICE_FRAMES_GLYPHS_CHANGED(XDEVICE(tmp));
4797 /* Cascade dirtiness so that we can have an
4798 animated glyph in a layout for instance. */
4799 set_image_instance_dirty_p(value, 1);
4806 Lisp_Object add_glyph_animated_timeout(EMACS_INT tickms, Lisp_Object image)
4808 Lisp_Object ret = Qnil;
4810 if (tickms > 0 && IMAGE_INSTANCEP(image)) {
4811 double ms = ((double)tickms) / 1000.0;
4812 struct gcpro gcpro1;
4813 Lisp_Object holder = make_weak_list(WEAK_LIST_SIMPLE);
4816 XWEAK_LIST_LIST(holder) = Fcons(image, Qnil);
4818 ret = Fadd_timeout(make_float(ms),
4819 Qglyph_animated_timeout_handler,
4820 holder, make_float(ms));
4827 void disable_glyph_animated_timeout(int i)
4832 Fdisable_timeout(id);
4835 /*****************************************************************************
4837 *****************************************************************************/
4839 void syms_of_glyphs(void)
4841 INIT_LRECORD_IMPLEMENTATION(glyph);
4842 INIT_LRECORD_IMPLEMENTATION(image_instance);
4844 /* image instantiators */
4846 DEFSUBR(Fimage_instantiator_format_list);
4847 DEFSUBR(Fvalid_image_instantiator_format_p);
4848 DEFSUBR(Fset_console_type_image_conversion_list);
4849 DEFSUBR(Fconsole_type_image_conversion_list);
4852 DEFKEYWORD(Q_pixel_height);
4853 DEFKEYWORD(Q_pixel_width);
4856 DEFKEYWORD(Q_color_symbols);
4859 DEFKEYWORD(Q_mask_file);
4860 DEFKEYWORD(Q_mask_data);
4861 DEFKEYWORD(Q_hotspot_x);
4862 DEFKEYWORD(Q_hotspot_y);
4863 DEFKEYWORD(Q_foreground);
4864 DEFKEYWORD(Q_background);
4866 /* image specifiers */
4868 DEFSUBR(Fimage_specifier_p);
4869 /* Qimage in general.c */
4871 /* image instances */
4873 defsymbol(&Qimage_instancep, "image-instance-p");
4875 DEFSYMBOL(Qnothing_image_instance_p);
4876 DEFSYMBOL(Qtext_image_instance_p);
4877 DEFSYMBOL(Qmono_pixmap_image_instance_p);
4878 DEFSYMBOL(Qcolor_pixmap_image_instance_p);
4879 DEFSYMBOL(Qpointer_image_instance_p);
4880 DEFSYMBOL(Qwidget_image_instance_p);
4881 DEFSYMBOL(Qsubwindow_image_instance_p);
4883 DEFSUBR(Fmake_image_instance);
4884 DEFSUBR(Fimage_instance_p);
4885 DEFSUBR(Fimage_instance_type);
4886 DEFSUBR(Fvalid_image_instance_type_p);
4887 DEFSUBR(Fimage_instance_type_list);
4888 DEFSUBR(Fimage_instance_name);
4889 DEFSUBR(Fimage_instance_domain);
4890 DEFSUBR(Fimage_instance_string);
4891 DEFSUBR(Fimage_instance_file_name);
4892 DEFSUBR(Fimage_instance_mask_file_name);
4893 DEFSUBR(Fimage_instance_depth);
4894 DEFSUBR(Fimage_instance_height);
4895 DEFSUBR(Fimage_instance_width);
4896 DEFSUBR(Fimage_instance_hotspot_x);
4897 DEFSUBR(Fimage_instance_hotspot_y);
4898 DEFSUBR(Fimage_instance_foreground);
4899 DEFSUBR(Fimage_instance_background);
4900 DEFSUBR(Fimage_instance_property);
4901 DEFSUBR(Fcolorize_image_instance);
4903 DEFSUBR(Fsubwindowp);
4904 DEFSUBR(Fimage_instance_subwindow_id);
4905 DEFSUBR(Fresize_subwindow);
4906 DEFSUBR(Fforce_subwindow_map);
4908 /* Qnothing defined as part of the "nothing" image-instantiator
4910 /* Qtext defined in general.c */
4911 DEFSYMBOL(Qmono_pixmap);
4912 DEFSYMBOL(Qcolor_pixmap);
4913 /* Qpointer defined in general.c */
4918 DEFSYMBOL(Qcontrib_p);
4919 DEFSYMBOL(Qbaseline);
4921 DEFSYMBOL(Qbuffer_glyph_p);
4922 DEFSYMBOL(Qpointer_glyph_p);
4923 DEFSYMBOL(Qicon_glyph_p);
4925 DEFSYMBOL(Qconst_glyph_variable);
4927 DEFSUBR(Fglyph_type);
4928 DEFSUBR(Fvalid_glyph_type_p);
4929 DEFSUBR(Fglyph_type_list);
4931 DEFSUBR(Fmake_glyph_internal);
4932 DEFSUBR(Fglyph_width);
4933 DEFSUBR(Fglyph_ascent);
4934 DEFSUBR(Fglyph_descent);
4935 DEFSUBR(Fglyph_height);
4936 DEFSUBR(Fset_instantiator_property);
4938 /* Qbuffer defined in general.c. */
4939 /* Qpointer defined above */
4941 /* Unfortunately, timeout handlers must be lisp functions. This is
4942 for animated glyphs. */
4943 DEFSYMBOL(Qglyph_animated_timeout_handler);
4944 DEFSUBR(Fglyph_animated_timeout_handler);
4947 DEFERROR_STANDARD(Qimage_conversion_error, Qio_error);
4950 static const struct lrecord_description image_specifier_description[] = {
4952 specifier_data_offset + offsetof(struct image_specifier, attachee)},
4954 specifier_data_offset + offsetof(struct image_specifier,
4955 attachee_property)},
4959 void specifier_type_create_image(void)
4961 /* image specifiers */
4963 INITIALIZE_SPECIFIER_TYPE_WITH_DATA(image, "image", "imagep");
4965 SPECIFIER_HAS_METHOD(image, create);
4966 SPECIFIER_HAS_METHOD(image, mark);
4967 SPECIFIER_HAS_METHOD(image, instantiate);
4968 SPECIFIER_HAS_METHOD(image, validate);
4969 SPECIFIER_HAS_METHOD(image, after_change);
4970 SPECIFIER_HAS_METHOD(image, going_to_add);
4971 SPECIFIER_HAS_METHOD(image, copy_instantiator);
4974 void reinit_specifier_type_create_image(void)
4976 REINITIALIZE_SPECIFIER_TYPE(image);
4979 static const struct lrecord_description iike_description_1[] = {
4980 {XD_LISP_OBJECT, offsetof(ii_keyword_entry, keyword)},
4984 static const struct struct_description iike_description = {
4985 sizeof(ii_keyword_entry),
4989 static const struct lrecord_description iiked_description_1[] = {
4990 XD_DYNARR_DESC(ii_keyword_entry_dynarr, &iike_description),
4994 static const struct struct_description iiked_description = {
4995 sizeof(ii_keyword_entry_dynarr),
4999 static const struct lrecord_description iife_description_1[] = {
5000 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, symbol)},
5001 {XD_LISP_OBJECT, offsetof(image_instantiator_format_entry, device)},
5002 {XD_STRUCT_PTR, offsetof(image_instantiator_format_entry, meths), 1,
5007 static const struct struct_description iife_description = {
5008 sizeof(image_instantiator_format_entry),
5012 static const struct lrecord_description iifed_description_1[] = {
5013 XD_DYNARR_DESC(image_instantiator_format_entry_dynarr,
5018 static const struct struct_description iifed_description = {
5019 sizeof(image_instantiator_format_entry_dynarr),
5023 static const struct lrecord_description iim_description_1[] = {
5024 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, symbol)},
5025 {XD_LISP_OBJECT, offsetof(struct image_instantiator_methods, device)},
5026 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, keywords),
5027 1, &iiked_description},
5028 {XD_STRUCT_PTR, offsetof(struct image_instantiator_methods, consoles),
5029 1, &cted_description},
5033 const struct struct_description iim_description = {
5034 sizeof(struct image_instantiator_methods),
5038 void image_instantiator_format_create(void)
5040 /* image instantiators */
5042 the_image_instantiator_format_entry_dynarr =
5043 Dynarr_new(image_instantiator_format_entry);
5045 Vimage_instantiator_format_list = Qnil;
5046 staticpro(&Vimage_instantiator_format_list);
5048 dump_add_root_struct_ptr(&the_image_instantiator_format_entry_dynarr,
5049 &iifed_description);
5051 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(nothing, "nothing");
5053 IIFORMAT_HAS_METHOD(nothing, possible_dest_types);
5054 IIFORMAT_HAS_METHOD(nothing, instantiate);
5056 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(inherit, "inherit");
5058 IIFORMAT_HAS_METHOD(inherit, validate);
5059 IIFORMAT_HAS_METHOD(inherit, normalize);
5060 IIFORMAT_HAS_METHOD(inherit, possible_dest_types);
5061 IIFORMAT_HAS_METHOD(inherit, instantiate);
5063 IIFORMAT_VALID_KEYWORD(inherit, Q_face, check_valid_face);
5065 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(string, "string");
5067 IIFORMAT_HAS_METHOD(string, validate);
5068 IIFORMAT_HAS_SHARED_METHOD(string, governing_domain, subwindow);
5069 IIFORMAT_HAS_METHOD(string, possible_dest_types);
5070 IIFORMAT_HAS_METHOD(string, instantiate);
5072 IIFORMAT_VALID_KEYWORD(string, Q_data, check_valid_string);
5073 /* Do this so we can set strings. */
5074 /* #### Andy, what is this? This is a bogus format and should not be
5075 visible to the user. */
5076 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(text, "text");
5077 IIFORMAT_HAS_METHOD(text, update);
5078 IIFORMAT_HAS_METHOD(text, query_geometry);
5080 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(formatted_string,
5081 "formatted-string");
5083 IIFORMAT_HAS_METHOD(formatted_string, validate);
5084 IIFORMAT_HAS_METHOD(formatted_string, possible_dest_types);
5085 IIFORMAT_HAS_METHOD(formatted_string, instantiate);
5086 IIFORMAT_VALID_KEYWORD(formatted_string, Q_data, check_valid_string);
5088 /* Do this so pointers have geometry. */
5089 /* #### Andy, what is this? This is a bogus format and should not be
5090 visible to the user. */
5091 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(pointer, "pointer");
5092 IIFORMAT_HAS_SHARED_METHOD(pointer, query_geometry, subwindow);
5095 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(subwindow, "subwindow");
5096 IIFORMAT_HAS_METHOD(subwindow, possible_dest_types);
5097 IIFORMAT_HAS_METHOD(subwindow, governing_domain);
5098 IIFORMAT_HAS_METHOD(subwindow, instantiate);
5099 IIFORMAT_HAS_METHOD(subwindow, query_geometry);
5100 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_width, check_valid_int);
5101 IIFORMAT_VALID_KEYWORD(subwindow, Q_pixel_height, check_valid_int);
5103 #ifdef HAVE_WINDOW_SYSTEM
5104 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xbm, "xbm");
5106 IIFORMAT_HAS_METHOD(xbm, validate);
5107 IIFORMAT_HAS_METHOD(xbm, normalize);
5108 IIFORMAT_HAS_METHOD(xbm, possible_dest_types);
5110 IIFORMAT_VALID_KEYWORD(xbm, Q_data, check_valid_xbm_inline);
5111 IIFORMAT_VALID_KEYWORD(xbm, Q_file, check_valid_string);
5112 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_data, check_valid_xbm_inline);
5113 IIFORMAT_VALID_KEYWORD(xbm, Q_mask_file, check_valid_string);
5114 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_x, check_valid_int);
5115 IIFORMAT_VALID_KEYWORD(xbm, Q_hotspot_y, check_valid_int);
5116 IIFORMAT_VALID_KEYWORD(xbm, Q_foreground, check_valid_string);
5117 IIFORMAT_VALID_KEYWORD(xbm, Q_background, check_valid_string);
5118 #endif /* HAVE_WINDOW_SYSTEM */
5121 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xface, "xface");
5123 IIFORMAT_HAS_METHOD(xface, validate);
5124 IIFORMAT_HAS_METHOD(xface, normalize);
5125 IIFORMAT_HAS_METHOD(xface, possible_dest_types);
5127 IIFORMAT_VALID_KEYWORD(xface, Q_data, check_valid_string);
5128 IIFORMAT_VALID_KEYWORD(xface, Q_file, check_valid_string);
5129 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_x, check_valid_int);
5130 IIFORMAT_VALID_KEYWORD(xface, Q_hotspot_y, check_valid_int);
5131 IIFORMAT_VALID_KEYWORD(xface, Q_foreground, check_valid_string);
5132 IIFORMAT_VALID_KEYWORD(xface, Q_background, check_valid_string);
5136 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(xpm, "xpm");
5138 IIFORMAT_HAS_METHOD(xpm, validate);
5139 IIFORMAT_HAS_METHOD(xpm, normalize);
5140 IIFORMAT_HAS_METHOD(xpm, possible_dest_types);
5142 IIFORMAT_VALID_KEYWORD(xpm, Q_data, check_valid_string);
5143 IIFORMAT_VALID_KEYWORD(xpm, Q_file, check_valid_string);
5144 IIFORMAT_VALID_KEYWORD(xpm, Q_color_symbols,
5145 check_valid_xpm_color_symbols);
5146 #endif /* HAVE_XPM */
5149 void reinit_vars_of_glyphs(void)
5151 the_expose_ignore_blocktype =
5152 Blocktype_new(struct expose_ignore_blocktype);
5154 hold_ignored_expose_registration = 0;
5157 void vars_of_glyphs(void)
5159 reinit_vars_of_glyphs();
5161 Vthe_nothing_vector = vector1(Qnothing);
5162 staticpro(&Vthe_nothing_vector);
5164 /* image instances */
5166 Vimage_instance_type_list = Fcons(Qnothing,
5167 list6(Qtext, Qmono_pixmap,
5168 Qcolor_pixmap, Qpointer,
5169 Qsubwindow, Qwidget));
5170 staticpro(&Vimage_instance_type_list);
5174 Vglyph_type_list = list3(Qbuffer, Qpointer, Qicon);
5175 staticpro(&Vglyph_type_list);
5177 /* The octal-escape glyph, control-arrow-glyph and
5178 invisible-text-glyph are completely initialized in glyphs.el */
5180 DEFVAR_LISP("octal-escape-glyph", &Voctal_escape_glyph /*
5181 What to prefix character codes displayed in octal with.
5183 Voctal_escape_glyph =
5184 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5186 DEFVAR_LISP("control-arrow-glyph", &Vcontrol_arrow_glyph /*
5187 What to use as an arrow for control characters.
5189 Vcontrol_arrow_glyph = allocate_glyph(GLYPH_BUFFER,
5190 redisplay_glyph_changed);
5192 DEFVAR_LISP("invisible-text-glyph", &Vinvisible_text_glyph /*
5193 What to use to indicate the presence of invisible text.
5194 This is the glyph that is displayed when an ellipsis is called for
5195 \(see `selective-display-ellipses' and `buffer-invisibility-spec').
5196 Normally this is three dots ("...").
5198 Vinvisible_text_glyph = allocate_glyph(GLYPH_BUFFER,
5199 redisplay_glyph_changed);
5201 /* Partially initialized in glyphs.el */
5202 DEFVAR_LISP("hscroll-glyph", &Vhscroll_glyph /*
5203 What to display at the beginning of horizontally scrolled lines.
5205 Vhscroll_glyph = allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5206 #ifdef HAVE_WINDOW_SYSTEM
5212 DEFVAR_LISP("xpm-color-symbols", &Vxpm_color_symbols /*
5213 Definitions of logical color-names used when reading XPM files.
5214 Elements of this list should be of the form (COLOR-NAME FORM-TO-EVALUATE).
5215 The COLOR-NAME should be a string, which is the name of the color to define;
5216 the FORM should evaluate to a `color' specifier object, or a string to be
5217 passed to `make-color-instance'. If a loaded XPM file references a symbolic
5218 color called COLOR-NAME, it will display as the computed color instead.
5220 The default value of this variable defines the logical color names
5221 \"foreground\" and \"background\" to be the colors of the `default' face.
5223 Vxpm_color_symbols = Qnil; /* initialized in x-faces.el */
5224 #endif /* HAVE_XPM */
5229 DEFVAR_BOOL("disable-animated-pixmaps", &disable_animated_pixmaps /*
5230 Whether animated pixmaps should be animated.
5233 disable_animated_pixmaps = 0;
5236 void specifier_vars_of_glyphs(void)
5238 /* #### Can we GC here? The set_specifier_* calls definitely need */
5240 /* display tables */
5242 DEFVAR_SPECIFIER("current-display-table", &Vcurrent_display_table /*
5243 *The display table currently in use.
5244 This is a specifier; use `set-specifier' to change it.
5246 Display tables are used to control how characters are displayed. Each
5247 time that redisplay processes a character, it is looked up in all the
5248 display tables that apply (obtained by calling `specifier-instance' on
5249 `current-display-table' and any overriding display tables specified in
5250 currently active faces). The first entry found that matches the
5251 character determines how the character is displayed. If there is no
5252 matching entry, the default display method is used. (Non-control
5253 characters are displayed as themselves and control characters are
5254 displayed according to the buffer-local variable `ctl-arrow'. Control
5255 characters are further affected by `control-arrow-glyph' and
5256 `octal-escape-glyph'.)
5258 Each instantiator in this specifier and the display-table specifiers
5259 in faces is a display table or a list of such tables. If a list, each
5260 table will be searched in turn for an entry matching a particular
5261 character. Each display table is one of
5263 -- a vector, specifying values for characters starting at 0
5264 -- a char table, either of type `char' or `generic'
5267 Each entry in a display table should be one of
5269 -- nil (this entry is ignored and the search continues)
5270 -- a character (use this character; if it happens to be the same as
5271 the original character, default processing happens, otherwise
5272 redisplay attempts to display this character directly;
5273 #### At some point recursive display-table lookup will be
5275 -- a string (display each character in the string directly;
5276 #### At some point recursive display-table lookup will be
5278 -- a glyph (display the glyph;
5279 #### At some point recursive display-table lookup will be
5280 implemented when a string glyph is being processed.)
5281 -- a cons of the form (format "STRING") where STRING is a printf-like
5282 spec used to process the character. #### Unfortunately no
5283 formatting directives other than %% are implemented.
5284 -- a vector (each element of the vector is processed recursively;
5285 in such a case, nil elements in the vector are simply ignored)
5287 #### At some point in the near future, display tables are likely to
5288 be expanded to include other features, such as referencing characters
5289 in particular fonts and allowing the character search to continue
5290 all the way up the chain of specifier instantiators. These features
5291 are necessary to properly display Unicode characters.
5293 Vcurrent_display_table = Fmake_specifier(Qdisplay_table);
5294 set_specifier_fallback(Vcurrent_display_table,
5295 list1(Fcons(Qnil, Qnil)));
5296 set_specifier_caching(Vcurrent_display_table,
5297 offsetof(struct window, display_table),
5298 some_window_value_changed, 0, 0, 0);
5301 void complex_vars_of_glyphs(void)
5303 /* Partially initialized in glyphs-x.c, glyphs.el */
5304 DEFVAR_LISP("truncation-glyph", &Vtruncation_glyph /*
5305 What to display at the end of truncated lines.
5308 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5310 /* Partially initialized in glyphs-x.c, glyphs.el */
5311 DEFVAR_LISP("continuation-glyph", &Vcontinuation_glyph /*
5312 What to display at the end of wrapped lines.
5314 Vcontinuation_glyph =
5315 allocate_glyph(GLYPH_BUFFER, redisplay_glyph_changed);
5317 /* Partially initialized in glyphs-x.c, glyphs.el */
5318 DEFVAR_LISP("sxemacs-logo", &Vsxemacs_logo /*
5319 The glyph used to display the SXEmacs logo at startup.
5321 Vsxemacs_logo = allocate_glyph(GLYPH_BUFFER, 0);