comparison src/glyphs.c @ 428:3ecd8885ac67 r21-2-22

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