Mercurial > hg > xemacs-beta
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 } |