XEmacs 21.2.38 (Peisino)
[chise/xemacs-chise.git.1] / src / glyphs-x.c
1 /* X-specific Lisp objects.
2    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3    Copyright (C) 1995 Board of Trustees, University of Illinois.
4    Copyright (C) 1995 Tinker Systems
5    Copyright (C) 1995, 1996 Ben Wing
6    Copyright (C) 1995 Sun Microsystems
7    Copyright (C) 1999, 2000 Andy Piper
8
9 This file is part of XEmacs.
10
11 XEmacs is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2, or (at your option) any
14 later version.
15
16 XEmacs is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 for more details.
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 /* 7-8-00 This file is more or less Mule-ized in my Mule workspace. */
28
29 /* Original author: Jamie Zawinski for 19.8
30    font-truename stuff added by Jamie Zawinski for 19.10
31    subwindow support added by Chuck Thompson
32    additional XPM support added by Chuck Thompson
33    initial X-Face support added by Stig
34    rewritten/restructured by Ben Wing for 19.12/19.13
35    GIF/JPEG support added by Ben Wing for 19.14
36    PNG support added by Bill Perry for 19.14
37    Improved GIF/JPEG support added by Bill Perry for 19.14
38    Cleanup/simplification of error handling by Ben Wing for 19.14
39    Pointer/icon overhaul, more restructuring by Ben Wing for 19.14
40    GIF support changed to external GIFlib 3.1 by Jareth Hein for 21.0
41    Many changes for color work and optimizations by Jareth Hein for 21.0
42    Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0
43    TIFF code by Jareth Hein for 21.0
44    GIF/JPEG/PNG/TIFF code moved to new glyph-eimage.c by Andy Piper for 21.0
45    Subwindow and Widget support by Andy Piper for 21.2
46
47    TODO:
48    Support the GrayScale, StaticColor and StaticGray visual classes.
49    Convert images.el to C and stick it in here?
50  */
51
52 #include <config.h>
53 #include "lisp.h"
54 #include "lstream.h"
55 #include "console-x.h"
56 #include "glyphs-x.h"
57 #include "objects-x.h"
58 #ifdef HAVE_WIDGETS
59 #include "gui-x.h"
60 #endif
61 #include "xmu.h"
62
63 #include "buffer.h"
64 #include "window.h"
65 #include "frame.h"
66 #include "insdel.h"
67 #include "opaque.h"
68 #include "gui.h"
69 #include "faces.h"
70
71 #include "imgproc.h"
72
73 #include "sysfile.h"
74
75 #include <setjmp.h>
76
77 #ifdef FILE_CODING
78 #include "file-coding.h"
79 #endif
80
81 #ifdef LWLIB_WIDGETS_MOTIF
82 #include <Xm/Xm.h>
83 #endif
84 #include <X11/IntrinsicP.h>
85
86 #if INTBITS == 32
87 # define FOUR_BYTE_TYPE unsigned int
88 #elif LONGBITS == 32
89 # define FOUR_BYTE_TYPE unsigned long
90 #elif SHORTBITS == 32
91 # define FOUR_BYTE_TYPE unsigned short
92 #else
93 #error What kind of strange-ass system are we running on?
94 #endif
95
96 #define LISP_DEVICE_TO_X_SCREEN(dev) XDefaultScreenOfDisplay (DEVICE_X_DISPLAY (XDEVICE (dev)))
97
98 DECLARE_IMAGE_INSTANTIATOR_FORMAT (nothing);
99 DECLARE_IMAGE_INSTANTIATOR_FORMAT (string);
100 DECLARE_IMAGE_INSTANTIATOR_FORMAT (formatted_string);
101 DECLARE_IMAGE_INSTANTIATOR_FORMAT (inherit);
102 #ifdef HAVE_JPEG
103 DECLARE_IMAGE_INSTANTIATOR_FORMAT (jpeg);
104 #endif
105 #ifdef HAVE_TIFF
106 DECLARE_IMAGE_INSTANTIATOR_FORMAT (tiff);
107 #endif
108 #ifdef HAVE_PNG
109 DECLARE_IMAGE_INSTANTIATOR_FORMAT (png);
110 #endif
111 #ifdef HAVE_GIF
112 DECLARE_IMAGE_INSTANTIATOR_FORMAT (gif);
113 #endif
114 #ifdef HAVE_XPM
115 DEFINE_DEVICE_IIFORMAT (x, xpm);
116 #endif
117 DEFINE_DEVICE_IIFORMAT (x, xbm);
118 DEFINE_DEVICE_IIFORMAT (x, subwindow);
119 #ifdef HAVE_XFACE
120 DEFINE_DEVICE_IIFORMAT (x, xface);
121 #endif
122
123 DEFINE_IMAGE_INSTANTIATOR_FORMAT (cursor_font);
124 Lisp_Object Qcursor_font;
125
126 DEFINE_IMAGE_INSTANTIATOR_FORMAT (font);
127
128 DEFINE_IMAGE_INSTANTIATOR_FORMAT (autodetect);
129
130 #ifdef HAVE_WIDGETS
131 DECLARE_IMAGE_INSTANTIATOR_FORMAT (layout);
132 DEFINE_DEVICE_IIFORMAT (x, widget);
133 DEFINE_DEVICE_IIFORMAT (x, native_layout);
134 DEFINE_DEVICE_IIFORMAT (x, button);
135 DEFINE_DEVICE_IIFORMAT (x, progress_gauge);
136 DEFINE_DEVICE_IIFORMAT (x, edit_field);
137 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
138 DEFINE_DEVICE_IIFORMAT (x, combo_box);
139 #endif
140 DEFINE_DEVICE_IIFORMAT (x, tab_control);
141 DEFINE_DEVICE_IIFORMAT (x, label);
142 #endif
143
144 static void cursor_font_instantiate (Lisp_Object image_instance,
145                                      Lisp_Object instantiator,
146                                      Lisp_Object pointer_fg,
147                                      Lisp_Object pointer_bg,
148                                      int dest_mask,
149                                      Lisp_Object domain);
150
151 #ifdef HAVE_WIDGETS
152 static void
153 update_widget_face (widget_value* wv,
154                     Lisp_Image_Instance* ii, Lisp_Object domain);
155 static void
156 update_tab_widget_face (widget_value* wv,
157                         Lisp_Image_Instance* ii, Lisp_Object domain);
158 #endif
159
160 #include "bitmaps.h"
161
162 \f
163 /************************************************************************/
164 /*                      image instance methods                          */
165 /************************************************************************/
166
167 /************************************************************************/
168 /* convert from a series of RGB triples to an XImage formated for the   */
169 /* proper display                                                       */
170 /************************************************************************/
171 static XImage *
172 convert_EImage_to_XImage (Lisp_Object device, int width, int height,
173                           unsigned char *pic, unsigned long **pixtbl,
174                           int *npixels)
175 {
176   Display *dpy;
177   Colormap cmap;
178   Visual *vis;
179   XImage *outimg;
180   int depth, bitmap_pad, bits_per_pixel, byte_cnt, i, j;
181   int rd,gr,bl,q;
182   unsigned char *data, *ip, *dp;
183   quant_table *qtable = 0;
184   union {
185     FOUR_BYTE_TYPE val;
186     char cp[4];
187   } conv;
188
189   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
190   cmap = DEVICE_X_COLORMAP (XDEVICE(device));
191   vis = DEVICE_X_VISUAL (XDEVICE(device));
192   depth = DEVICE_X_DEPTH(XDEVICE(device));
193
194   if (vis->class == GrayScale || vis->class == StaticColor ||
195       vis->class == StaticGray)
196     {
197       /* #### Implement me!!! */
198       return NULL;
199     }
200
201   if (vis->class == PseudoColor)
202     {
203       /* Quantize the image and get a histogram while we're at it.
204          Do this first to save memory */
205       qtable = build_EImage_quantable(pic, width, height, 256);
206       if (qtable == NULL) return NULL;
207     }
208
209   bitmap_pad = ((depth > 16) ? 32 :
210                 (depth >  8) ? 16 :
211                 8);
212
213   outimg = XCreateImage (dpy, vis,
214                          depth, ZPixmap, 0, 0, width, height,
215                          bitmap_pad, 0);
216   if (!outimg) return NULL;
217
218   bits_per_pixel = outimg->bits_per_pixel;
219   byte_cnt = bits_per_pixel >> 3;
220
221   data = (unsigned char *) xmalloc (outimg->bytes_per_line * height);
222   if (!data)
223     {
224       XDestroyImage (outimg);
225       return NULL;
226     }
227   outimg->data = (char *) data;
228
229   if (vis->class == PseudoColor)
230     {
231       unsigned long pixarray[256];
232       int pixcount, n;
233       /* use our quantize table to allocate the colors */
234       pixcount = 32;
235       *pixtbl = xnew_array (unsigned long, pixcount);
236       *npixels = 0;
237
238       /* #### should implement a sort by popularity to assure proper allocation */
239       n = *npixels;
240       for (i = 0; i < qtable->num_active_colors; i++)
241         {
242           XColor color;
243           int res;
244
245           color.red = qtable->rm[i] ? qtable->rm[i] << 8 : 0;
246           color.green = qtable->gm[i] ? qtable->gm[i] << 8 : 0;
247           color.blue = qtable->bm[i] ? qtable->bm[i] << 8 : 0;
248           color.flags = DoRed | DoGreen | DoBlue;
249           res = allocate_nearest_color (dpy, cmap, vis, &color);
250           if (res > 0 && res < 3)
251             {
252               DO_REALLOC(*pixtbl, pixcount, n+1, unsigned long);
253               (*pixtbl)[n] = color.pixel;
254               n++;
255             }
256           pixarray[i] = color.pixel;
257         }
258       *npixels = n;
259       ip = pic;
260       for (i = 0; i < height; i++)
261         {
262           dp = data + (i * outimg->bytes_per_line);
263           for (j = 0; j < width; j++)
264             {
265               rd = *ip++;
266               gr = *ip++;
267               bl = *ip++;
268               conv.val = pixarray[QUANT_GET_COLOR(qtable,rd,gr,bl)];
269 #ifdef WORDS_BIGENDIAN
270               if (outimg->byte_order == MSBFirst)
271                 for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q];
272               else
273                 for (q = 3; q >= 4-byte_cnt; q--) *dp++ = conv.cp[q];
274 #else
275               if (outimg->byte_order == MSBFirst)
276                 for (q = byte_cnt-1; q >= 0; q--) *dp++ = conv.cp[q];
277               else
278                 for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q];
279 #endif
280             }
281         }
282       xfree(qtable);
283     } else {
284       unsigned long rshift,gshift,bshift,rbits,gbits,bbits,junk;
285       junk = vis->red_mask;
286       rshift = 0;
287       while ((junk & 0x1) == 0)
288         {
289           junk = junk >> 1;
290           rshift ++;
291         }
292       rbits = 0;
293       while (junk != 0)
294         {
295           junk = junk >> 1;
296           rbits++;
297         }
298       junk = vis->green_mask;
299       gshift = 0;
300       while ((junk & 0x1) == 0)
301         {
302           junk = junk >> 1;
303           gshift ++;
304         }
305       gbits = 0;
306       while (junk != 0)
307         {
308           junk = junk >> 1;
309           gbits++;
310         }
311       junk = vis->blue_mask;
312       bshift = 0;
313       while ((junk & 0x1) == 0)
314         {
315           junk = junk >> 1;
316           bshift ++;
317         }
318       bbits = 0;
319       while (junk != 0)
320         {
321           junk = junk >> 1;
322           bbits++;
323         }
324       ip = pic;
325       for (i = 0; i < height; i++)
326         {
327           dp = data + (i * outimg->bytes_per_line);
328           for (j = 0; j < width; j++)
329             {
330               if (rbits > 8)
331                 rd = *ip++ << (rbits - 8);
332               else
333                 rd = *ip++ >> (8 - rbits);
334               if (gbits > 8)
335                 gr = *ip++ << (gbits - 8);
336               else
337                 gr = *ip++ >> (8 - gbits);
338               if (bbits > 8)
339                 bl = *ip++ << (bbits - 8);
340               else
341                 bl = *ip++ >> (8 - bbits);
342
343               conv.val = (rd << rshift) | (gr << gshift) | (bl << bshift);
344 #ifdef WORDS_BIGENDIAN
345               if (outimg->byte_order == MSBFirst)
346                 for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q];
347               else
348                 for (q = 3; q >= 4-byte_cnt; q--) *dp++ = conv.cp[q];
349 #else
350               if (outimg->byte_order == MSBFirst)
351                 for (q = byte_cnt-1; q >= 0; q--) *dp++ = conv.cp[q];
352               else
353                 for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q];
354 #endif
355             }
356         }
357     }
358   return outimg;
359 }
360
361
362
363 static void
364 x_print_image_instance (Lisp_Image_Instance *p,
365                         Lisp_Object printcharfun,
366                         int escapeflag)
367 {
368   char buf[100];
369
370   switch (IMAGE_INSTANCE_TYPE (p))
371     {
372     case IMAGE_MONO_PIXMAP:
373     case IMAGE_COLOR_PIXMAP:
374     case IMAGE_POINTER:
375       sprintf (buf, " (0x%lx", (unsigned long) IMAGE_INSTANCE_X_PIXMAP (p));
376       write_c_string (buf, printcharfun);
377       if (IMAGE_INSTANCE_X_MASK (p))
378         {
379           sprintf (buf, "/0x%lx", (unsigned long) IMAGE_INSTANCE_X_MASK (p));
380           write_c_string (buf, printcharfun);
381         }
382       write_c_string (")", printcharfun);
383       break;
384     default:
385       break;
386     }
387 }
388
389 #ifdef DEBUG_WIDGETS
390 extern int debug_widget_instances;
391 #endif
392
393 static void
394 x_finalize_image_instance (Lisp_Image_Instance *p)
395 {
396   if (!p->data)
397     return;
398
399   if (DEVICE_LIVE_P (XDEVICE (IMAGE_INSTANCE_DEVICE (p))))
400     {
401       Display *dpy = DEVICE_X_DISPLAY
402         (XDEVICE (IMAGE_INSTANCE_DEVICE (p)));
403       if (0)
404         ;
405 #ifdef HAVE_WIDGETS
406       else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_WIDGET)
407         {
408           if (IMAGE_INSTANCE_SUBWINDOW_ID (p))
409             {
410 #ifdef DEBUG_WIDGETS
411               debug_widget_instances--;
412               stderr_out ("widget destroyed, %d left\n", debug_widget_instances);
413 #endif
414               lw_destroy_widget (IMAGE_INSTANCE_X_WIDGET_ID (p));
415               lw_destroy_widget (IMAGE_INSTANCE_X_CLIPWIDGET (p));
416
417               /* We can release the callbacks again. */
418               ungcpro_popup_callbacks (IMAGE_INSTANCE_X_WIDGET_LWID (p));
419
420               IMAGE_INSTANCE_X_WIDGET_ID (p) = 0;
421               IMAGE_INSTANCE_X_CLIPWIDGET (p) = 0;
422             }
423         }
424 #endif
425       else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
426         {
427           if (IMAGE_INSTANCE_SUBWINDOW_ID (p))
428             XDestroyWindow (dpy, IMAGE_INSTANCE_X_SUBWINDOW_ID (p));
429           IMAGE_INSTANCE_SUBWINDOW_ID (p) = 0;
430         }
431       else
432         {
433           int i;
434           if (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p))
435             disable_glyph_animated_timeout (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p));
436
437           if (IMAGE_INSTANCE_X_MASK (p) &&
438               IMAGE_INSTANCE_X_MASK (p) != IMAGE_INSTANCE_X_PIXMAP (p))
439             XFreePixmap (dpy, IMAGE_INSTANCE_X_MASK (p));
440           IMAGE_INSTANCE_PIXMAP_MASK (p) = 0;
441
442           if (IMAGE_INSTANCE_X_PIXMAP_SLICES (p))
443             {
444               for (i = 0; i < IMAGE_INSTANCE_PIXMAP_MAXSLICE (p); i++)
445                 if (IMAGE_INSTANCE_X_PIXMAP_SLICE (p,i))
446                   {
447                     XFreePixmap (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE (p,i));
448                     IMAGE_INSTANCE_X_PIXMAP_SLICE (p, i) = 0;
449                   }
450               xfree (IMAGE_INSTANCE_X_PIXMAP_SLICES (p));
451               IMAGE_INSTANCE_X_PIXMAP_SLICES (p) = 0;
452             }
453
454           if (IMAGE_INSTANCE_X_CURSOR (p))
455             {
456               XFreeCursor (dpy, IMAGE_INSTANCE_X_CURSOR (p));
457               IMAGE_INSTANCE_X_CURSOR (p) = 0;
458             }
459
460           if (IMAGE_INSTANCE_X_NPIXELS (p) != 0)
461             {
462               XFreeColors (dpy,
463                            IMAGE_INSTANCE_X_COLORMAP (p),
464                            IMAGE_INSTANCE_X_PIXELS (p),
465                            IMAGE_INSTANCE_X_NPIXELS (p), 0);
466               IMAGE_INSTANCE_X_NPIXELS (p) = 0;
467             }
468         }
469     }
470   /* You can sometimes have pixels without a live device. I forget
471      why, but that's why we free them here if we have a pixmap type
472      image instance. It probably means that we might also get a memory
473      leak with widgets. */
474   if (IMAGE_INSTANCE_TYPE (p) != IMAGE_WIDGET
475       && IMAGE_INSTANCE_TYPE (p) != IMAGE_SUBWINDOW
476       && IMAGE_INSTANCE_X_PIXELS (p))
477     {
478       xfree (IMAGE_INSTANCE_X_PIXELS (p));
479       IMAGE_INSTANCE_X_PIXELS (p) = 0;
480     }
481
482   xfree (p->data);
483   p->data = 0;
484 }
485
486 static int
487 x_image_instance_equal (Lisp_Image_Instance *p1,
488                         Lisp_Image_Instance *p2, int depth)
489 {
490   switch (IMAGE_INSTANCE_TYPE (p1))
491     {
492     case IMAGE_MONO_PIXMAP:
493     case IMAGE_COLOR_PIXMAP:
494     case IMAGE_POINTER:
495       if (IMAGE_INSTANCE_X_COLORMAP (p1) != IMAGE_INSTANCE_X_COLORMAP (p2) ||
496           IMAGE_INSTANCE_X_NPIXELS (p1) != IMAGE_INSTANCE_X_NPIXELS (p2))
497         return 0;
498       break;
499     default:
500       break;
501     }
502
503   return 1;
504 }
505
506 static unsigned long
507 x_image_instance_hash (Lisp_Image_Instance *p, int depth)
508 {
509   switch (IMAGE_INSTANCE_TYPE (p))
510     {
511     case IMAGE_MONO_PIXMAP:
512     case IMAGE_COLOR_PIXMAP:
513     case IMAGE_POINTER:
514       return IMAGE_INSTANCE_X_NPIXELS (p);
515     default:
516       return 0;
517     }
518 }
519
520 /* Set all the slots in an image instance structure to reasonable
521    default values.  This is used somewhere within an instantiate
522    method.  It is assumed that the device slot within the image
523    instance is already set -- this is the case when instantiate
524    methods are called. */
525
526 static void
527 x_initialize_pixmap_image_instance (Lisp_Image_Instance *ii,
528                                     int slices,
529                                     enum image_instance_type type)
530 {
531   ii->data = xnew_and_zero (struct x_image_instance_data);
532   IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii) = slices;
533   IMAGE_INSTANCE_X_PIXMAP_SLICES (ii) =
534     xnew_array_and_zero (Pixmap, slices);
535   IMAGE_INSTANCE_TYPE (ii) = type;
536   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = Qnil;
537   IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (ii) = Qnil;
538   IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = Qnil;
539   IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = Qnil;
540   IMAGE_INSTANCE_PIXMAP_FG (ii) = Qnil;
541   IMAGE_INSTANCE_PIXMAP_BG (ii) = Qnil;
542 }
543
544 \f
545 /************************************************************************/
546 /*                        pixmap file functions                         */
547 /************************************************************************/
548
549 /* Where bitmaps are; initialized from resource database */
550 Lisp_Object Vx_bitmap_file_path;
551
552 #ifndef BITMAPDIR
553 #define BITMAPDIR "/usr/include/X11/bitmaps"
554 #endif
555
556 #define USE_XBMLANGPATH
557
558 /* Given a pixmap filename, look through all of the "standard" places
559    where the file might be located.  Return a full pathname if found;
560    otherwise, return Qnil. */
561
562 static Lisp_Object
563 x_locate_pixmap_file (Lisp_Object name)
564 {
565   /* This function can GC if IN_REDISPLAY is false */
566   Display *display;
567
568   /* Check non-absolute pathnames with a directory component relative to
569      the search path; that's the way Xt does it. */
570   /* #### Unix-specific */
571   if (XSTRING_BYTE (name, 0) == '/' ||
572       (XSTRING_BYTE (name, 0) == '.' &&
573        (XSTRING_BYTE (name, 1) == '/' ||
574         (XSTRING_BYTE (name, 1) == '.' &&
575          (XSTRING_BYTE (name, 2) == '/')))))
576     {
577       if (!NILP (Ffile_readable_p (name)))
578         return Fexpand_file_name (name, Qnil);
579       else
580         return Qnil;
581     }
582
583   if (NILP (Vdefault_x_device))
584     /* This may occur during initialization. */
585     return Qnil;
586   else
587     /* We only check the bitmapFilePath resource on the original X device. */
588     display = DEVICE_X_DISPLAY (XDEVICE (Vdefault_x_device));
589
590 #ifdef USE_XBMLANGPATH
591   {
592     char *path = egetenv ("XBMLANGPATH");
593     SubstitutionRec subs[1];
594     subs[0].match = 'B';
595     subs[0].substitution = (char *) XSTRING_DATA (name);
596     /* #### Motif uses a big hairy default if $XBMLANGPATH isn't set.
597        We don't.  If you want it used, set it. */
598     if (path &&
599         (path = XtResolvePathname (display, "bitmaps", 0, 0, path,
600                                    subs, XtNumber (subs), 0)))
601       {
602         name = build_string (path);
603         XtFree (path);
604         return (name);
605       }
606   }
607 #endif
608
609   if (NILP (Vx_bitmap_file_path))
610     {
611       char *type = 0;
612       XrmValue value;
613       if (XrmGetResource (XtDatabase (display),
614                           "bitmapFilePath", "BitmapFilePath", &type, &value)
615           && !strcmp (type, "String"))
616         Vx_bitmap_file_path = decode_env_path (0, (char *) value.addr);
617       Vx_bitmap_file_path = nconc2 (Vx_bitmap_file_path,
618                                     (decode_path (BITMAPDIR)));
619     }
620
621   {
622     Lisp_Object found;
623     if (locate_file (Vx_bitmap_file_path, name, Qnil, &found, R_OK) < 0)
624       {
625         Lisp_Object temp = list1 (Vdata_directory);
626         struct gcpro gcpro1;
627
628         GCPRO1 (temp);
629         locate_file (temp, name, Qnil, &found, R_OK);
630         UNGCPRO;
631       }
632
633     return found;
634   }
635 }
636
637 static Lisp_Object
638 locate_pixmap_file (Lisp_Object name)
639 {
640   return x_locate_pixmap_file (name);
641 }
642
643 #if 0
644 static void
645 write_lisp_string_to_temp_file (Lisp_Object string, char *filename_out)
646 {
647   Lisp_Object instream, outstream;
648   Lstream *istr, *ostr;
649   char tempbuf[1024]; /* some random amount */
650   int fubar = 0;
651   FILE *tmpfil;
652   static Extbyte_dynarr *conversion_out_dynarr;
653   Bytecount bstart, bend;
654   struct gcpro gcpro1, gcpro2;
655 #ifdef FILE_CODING
656   Lisp_Object conv_out_stream;
657   Lstream *costr;
658   struct gcpro gcpro3;
659 #endif
660
661   /* This function can GC */
662   if (!conversion_out_dynarr)
663     conversion_out_dynarr = Dynarr_new (Extbyte);
664   else
665     Dynarr_reset (conversion_out_dynarr);
666
667   /* Create the temporary file ... */
668   sprintf (filename_out, "/tmp/emacs%d.XXXXXX", (int) getpid ());
669   mktemp (filename_out);
670   tmpfil = fopen (filename_out, "w");
671   if (!tmpfil)
672     {
673       if (tmpfil)
674         {
675           int old_errno = errno;
676           fclose (tmpfil);
677           unlink (filename_out);
678           errno = old_errno;
679         }
680       report_file_error ("Creating temp file",
681                          list1 (build_string (filename_out)));
682     }
683
684   CHECK_STRING (string);
685   get_string_range_byte (string, Qnil, Qnil, &bstart, &bend,
686                          GB_HISTORICAL_STRING_BEHAVIOR);
687   instream = make_lisp_string_input_stream (string, bstart, bend);
688   istr = XLSTREAM (instream);
689   /* setup the out stream */
690   outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr);
691   ostr = XLSTREAM (outstream);
692 #ifdef FILE_CODING
693   /* setup the conversion stream */
694   conv_out_stream = make_encoding_output_stream (ostr, Fget_coding_system(Qbinary));
695   costr = XLSTREAM (conv_out_stream);
696   GCPRO3 (instream, outstream, conv_out_stream);
697 #else
698   GCPRO2 (instream, outstream);
699 #endif
700
701   /* Get the data while doing the conversion */
702   while (1)
703     {
704       ssize_t size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
705       if (!size_in_bytes)
706         break;
707       /* It does seem the flushes are necessary... */
708 #ifdef FILE_CODING
709       Lstream_write (costr, tempbuf, size_in_bytes);
710       Lstream_flush (costr);
711 #else
712       Lstream_write (ostr, tempbuf, size_in_bytes);
713 #endif
714       Lstream_flush (ostr);
715       if (fwrite ((unsigned char *)Dynarr_atp(conversion_out_dynarr, 0),
716                   Dynarr_length(conversion_out_dynarr), 1, tmpfil) != 1)
717         {
718           fubar = 1;
719           break;
720         }
721       /* reset the dynarr */
722       Lstream_rewind(ostr);
723     }
724
725   if (fclose (tmpfil) != 0)
726     fubar = 1;
727   Lstream_close (istr);
728 #ifdef FILE_CODING
729   Lstream_close (costr);
730 #endif
731   Lstream_close (ostr);
732
733   UNGCPRO;
734   Lstream_delete (istr);
735   Lstream_delete (ostr);
736 #ifdef FILE_CODING
737   Lstream_delete (costr);
738 #endif
739
740   if (fubar)
741     report_file_error ("Writing temp file",
742                        list1 (build_string (filename_out)));
743 }
744 #endif /* 0 */
745
746 \f
747 /************************************************************************/
748 /*                           cursor functions                           */
749 /************************************************************************/
750
751 /* Check that this server supports cursors of size WIDTH * HEIGHT.  If
752    not, signal an error.  INSTANTIATOR is only used in the error
753    message. */
754
755 static void
756 check_pointer_sizes (Screen *xs, unsigned int width, unsigned int height,
757                      Lisp_Object instantiator)
758 {
759   unsigned int best_width, best_height;
760   if (! XQueryBestCursor (DisplayOfScreen (xs), RootWindowOfScreen (xs),
761                           width, height, &best_width, &best_height))
762     /* this means that an X error of some sort occurred (we trap
763        these so they're not fatal). */
764     signal_simple_error ("XQueryBestCursor() failed?", instantiator);
765
766   if (width > best_width || height > best_height)
767     error_with_frob (instantiator,
768                      "pointer too large (%dx%d): "
769                      "server requires %dx%d or smaller",
770                      width, height, best_width, best_height);
771 }
772
773
774 static void
775 generate_cursor_fg_bg (Lisp_Object device, Lisp_Object *foreground,
776                        Lisp_Object *background, XColor *xfg, XColor *xbg)
777 {
778   if (!NILP (*foreground) && !COLOR_INSTANCEP (*foreground))
779     *foreground =
780       Fmake_color_instance (*foreground, device,
781                             encode_error_behavior_flag (ERROR_ME));
782   if (COLOR_INSTANCEP (*foreground))
783     *xfg = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (*foreground));
784   else
785     {
786       xfg->pixel = 0;
787       xfg->red = xfg->green = xfg->blue = 0;
788     }
789
790   if (!NILP (*background) && !COLOR_INSTANCEP (*background))
791     *background =
792       Fmake_color_instance (*background, device,
793                             encode_error_behavior_flag (ERROR_ME));
794   if (COLOR_INSTANCEP (*background))
795     *xbg = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (*background));
796   else
797     {
798       xbg->pixel = 0;
799       xbg->red = xbg->green = xbg->blue = ~0;
800     }
801 }
802
803 static void
804 maybe_recolor_cursor (Lisp_Object image_instance, Lisp_Object foreground,
805                       Lisp_Object background)
806 {
807   Lisp_Object device = XIMAGE_INSTANCE_DEVICE (image_instance);
808   XColor xfg, xbg;
809
810   generate_cursor_fg_bg (device, &foreground, &background, &xfg, &xbg);
811   if (!NILP (foreground) || !NILP (background))
812     {
813       XRecolorCursor (DEVICE_X_DISPLAY (XDEVICE (device)),
814                       XIMAGE_INSTANCE_X_CURSOR (image_instance),
815                       &xfg, &xbg);
816       XIMAGE_INSTANCE_PIXMAP_FG (image_instance) = foreground;
817       XIMAGE_INSTANCE_PIXMAP_BG (image_instance) = background;
818     }
819 }
820
821 \f
822 /************************************************************************/
823 /*                        color pixmap functions                        */
824 /************************************************************************/
825
826 /* Initialize an image instance from an XImage.
827
828    DEST_MASK specifies the mask of allowed image types.
829
830    PIXELS and NPIXELS specify an array of pixels that are used in
831    the image.  These need to be kept around for the duration of the
832    image.  When the image instance is freed, XFreeColors() will
833    automatically be called on all the pixels specified here; thus,
834    you should have allocated the pixels yourself using XAllocColor()
835    or the like.  The array passed in is used directly without
836    being copied, so it should be heap data created with xmalloc().
837    It will be freed using xfree() when the image instance is
838    destroyed.
839
840    If this fails, signal an error.  INSTANTIATOR is only used
841    in the error message.
842
843    #### This should be able to handle conversion into `pointer'.
844    Use the same code as for `xpm'. */
845
846 static void
847 init_image_instance_from_x_image (Lisp_Image_Instance *ii,
848                                   XImage *ximage,
849                                   int dest_mask,
850                                   Colormap cmap,
851                                   unsigned long *pixels,
852                                   int npixels,
853                                   int slices,
854                                   Lisp_Object instantiator)
855 {
856   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
857   Display *dpy;
858   GC gc;
859   Drawable d;
860   Pixmap pixmap;
861
862   if (!DEVICE_X_P (XDEVICE (device)))
863     signal_simple_error ("Not an X device", device);
864
865   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
866   d = XtWindow(DEVICE_XT_APP_SHELL (XDEVICE (device)));
867
868   if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
869     incompatible_image_types (instantiator, dest_mask,
870                               IMAGE_COLOR_PIXMAP_MASK);
871
872   pixmap = XCreatePixmap (dpy, d, ximage->width,
873                           ximage->height, ximage->depth);
874   if (!pixmap)
875     signal_simple_error ("Unable to create pixmap", instantiator);
876
877   gc = XCreateGC (dpy, pixmap, 0, NULL);
878   if (!gc)
879     {
880       XFreePixmap (dpy, pixmap);
881       signal_simple_error ("Unable to create GC", instantiator);
882     }
883
884   XPutImage (dpy, pixmap, gc, ximage, 0, 0, 0, 0,
885              ximage->width, ximage->height);
886
887   XFreeGC (dpy, gc);
888
889   x_initialize_pixmap_image_instance (ii, slices, IMAGE_COLOR_PIXMAP);
890
891   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
892     find_keyword_in_vector (instantiator, Q_file);
893
894   /* Fixup a set of pixmaps. */
895   IMAGE_INSTANCE_X_PIXMAP (ii) = pixmap;
896
897   IMAGE_INSTANCE_PIXMAP_MASK (ii) = 0;
898   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = ximage->width;
899   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = ximage->height;
900   IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = ximage->depth;
901   IMAGE_INSTANCE_X_COLORMAP (ii) = cmap;
902   IMAGE_INSTANCE_X_PIXELS (ii) = pixels;
903   IMAGE_INSTANCE_X_NPIXELS (ii) = npixels;
904 }
905
906 static void
907 image_instance_add_x_image (Lisp_Image_Instance *ii,
908                             XImage *ximage,
909                             int slice,
910                             Lisp_Object instantiator)
911 {
912   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
913   Display *dpy;
914   GC gc;
915   Drawable d;
916   Pixmap pixmap;
917
918   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
919   d = XtWindow(DEVICE_XT_APP_SHELL (XDEVICE (device)));
920
921   pixmap = XCreatePixmap (dpy, d, ximage->width,
922                           ximage->height, ximage->depth);
923   if (!pixmap)
924     signal_simple_error ("Unable to create pixmap", instantiator);
925
926   gc = XCreateGC (dpy, pixmap, 0, NULL);
927   if (!gc)
928     {
929       XFreePixmap (dpy, pixmap);
930       signal_simple_error ("Unable to create GC", instantiator);
931     }
932
933   XPutImage (dpy, pixmap, gc, ximage, 0, 0, 0, 0,
934              ximage->width, ximage->height);
935
936   XFreeGC (dpy, gc);
937
938   IMAGE_INSTANCE_X_PIXMAP_SLICE (ii, slice) = pixmap;
939 }
940
941 static void
942 x_init_image_instance_from_eimage (Lisp_Image_Instance *ii,
943                                    int width, int height,
944                                    int slices,
945                                    unsigned char *eimage,
946                                    int dest_mask,
947                                    Lisp_Object instantiator,
948                                    Lisp_Object domain)
949 {
950   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
951   Colormap cmap = DEVICE_X_COLORMAP (XDEVICE(device));
952   unsigned long *pixtbl = NULL;
953   int npixels = 0;
954   int slice;
955   XImage* ximage;
956
957   for (slice = 0; slice < slices; slice++)
958     {
959       ximage = convert_EImage_to_XImage (device, width, height,
960                                          eimage + (width * height * 3 * slice),
961                                          &pixtbl, &npixels);
962       if (!ximage)
963         {
964           if (pixtbl) xfree (pixtbl);
965           signal_image_error("EImage to XImage conversion failed", instantiator);
966         }
967
968       /* Now create the pixmap and set up the image instance */
969       if (slice == 0)
970         init_image_instance_from_x_image (ii, ximage, dest_mask,
971                                           cmap, pixtbl, npixels, slices,
972                                           instantiator);
973       else
974         image_instance_add_x_image (ii, ximage, slice, instantiator);
975
976       if (ximage)
977         {
978           if (ximage->data)
979             {
980               xfree (ximage->data);
981               ximage->data = 0;
982             }
983           XDestroyImage (ximage);
984           ximage = 0;
985         }
986     }
987 }
988
989 int read_bitmap_data_from_file (const char *filename, unsigned int *width,
990                                 unsigned int *height, unsigned char **datap,
991                                 int *x_hot, int *y_hot)
992 {
993   return XmuReadBitmapDataFromFile (filename, width, height,
994                                     datap, x_hot, y_hot);
995 }
996
997 /* Given inline data for a mono pixmap, create and return the
998    corresponding X object. */
999
1000 static Pixmap
1001 pixmap_from_xbm_inline (Lisp_Object device, int width, int height,
1002                         /* Note that data is in ext-format! */
1003                         const char *bits)
1004 {
1005   return XCreatePixmapFromBitmapData
1006     (DEVICE_X_DISPLAY (XDEVICE (device)),
1007      XtWindow (DEVICE_XT_APP_SHELL (XDEVICE (device))),
1008      (char *) bits, width, height,
1009      1, 0, 1);
1010 }
1011
1012 /* Given inline data for a mono pixmap, initialize the given
1013    image instance accordingly. */
1014
1015 static void
1016 init_image_instance_from_xbm_inline (Lisp_Image_Instance *ii,
1017                                      int width, int height,
1018                                      /* Note that data is in ext-format! */
1019                                      const char *bits,
1020                                      Lisp_Object instantiator,
1021                                      Lisp_Object pointer_fg,
1022                                      Lisp_Object pointer_bg,
1023                                      int dest_mask,
1024                                      Pixmap mask,
1025                                      Lisp_Object mask_filename)
1026 {
1027   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1028   Lisp_Object foreground = find_keyword_in_vector (instantiator, Q_foreground);
1029   Lisp_Object background = find_keyword_in_vector (instantiator, Q_background);
1030   Display *dpy;
1031   Screen *scr;
1032   Drawable draw;
1033   enum image_instance_type type;
1034
1035   if (!DEVICE_X_P (XDEVICE (device)))
1036     signal_simple_error ("Not an X device", device);
1037
1038   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
1039   draw = XtWindow(DEVICE_XT_APP_SHELL (XDEVICE (device)));
1040   scr = DefaultScreenOfDisplay (dpy);
1041
1042   if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) &&
1043       (dest_mask & IMAGE_COLOR_PIXMAP_MASK))
1044     {
1045       if (!NILP (foreground) || !NILP (background))
1046         type = IMAGE_COLOR_PIXMAP;
1047       else
1048         type = IMAGE_MONO_PIXMAP;
1049     }
1050   else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1051     type = IMAGE_MONO_PIXMAP;
1052   else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1053     type = IMAGE_COLOR_PIXMAP;
1054   else if (dest_mask & IMAGE_POINTER_MASK)
1055     type = IMAGE_POINTER;
1056   else
1057     incompatible_image_types (instantiator, dest_mask,
1058                               IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
1059                               | IMAGE_POINTER_MASK);
1060
1061   x_initialize_pixmap_image_instance (ii, 1, type);
1062   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = width;
1063   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = height;
1064   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
1065     find_keyword_in_vector (instantiator, Q_file);
1066
1067   switch (type)
1068     {
1069     case IMAGE_MONO_PIXMAP:
1070       {
1071         IMAGE_INSTANCE_X_PIXMAP (ii) =
1072           pixmap_from_xbm_inline (device, width, height, (Extbyte *) bits);
1073       }
1074       break;
1075
1076     case IMAGE_COLOR_PIXMAP:
1077       {
1078         Dimension d = DEVICE_X_DEPTH (XDEVICE(device));
1079         unsigned long fg = BlackPixelOfScreen (scr);
1080         unsigned long bg = WhitePixelOfScreen (scr);
1081
1082         if (!NILP (foreground) && !COLOR_INSTANCEP (foreground))
1083           foreground =
1084             Fmake_color_instance (foreground, device,
1085                                   encode_error_behavior_flag (ERROR_ME));
1086
1087         if (COLOR_INSTANCEP (foreground))
1088           fg = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (foreground)).pixel;
1089
1090         if (!NILP (background) && !COLOR_INSTANCEP (background))
1091           background =
1092             Fmake_color_instance (background, device,
1093                                   encode_error_behavior_flag (ERROR_ME));
1094
1095         if (COLOR_INSTANCEP (background))
1096           bg = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (background)).pixel;
1097
1098         /* We used to duplicate the pixels using XAllocColor(), to protect
1099            against their getting freed.  Just as easy to just store the
1100            color instances here and GC-protect them, so this doesn't
1101            happen. */
1102         IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
1103         IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
1104         IMAGE_INSTANCE_X_PIXMAP (ii) =
1105           XCreatePixmapFromBitmapData (dpy, draw,
1106                                        (char *) bits, width, height,
1107                                        fg, bg, d);
1108         IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = d;
1109       }
1110       break;
1111
1112     case IMAGE_POINTER:
1113     {
1114         XColor fg_color, bg_color;
1115         Pixmap source;
1116
1117         check_pointer_sizes (scr, width, height, instantiator);
1118
1119         source =
1120           XCreatePixmapFromBitmapData (dpy, draw,
1121                                        (char *) bits, width, height,
1122                                        1, 0, 1);
1123
1124         if (NILP (foreground))
1125           foreground = pointer_fg;
1126         if (NILP (background))
1127           background = pointer_bg;
1128         generate_cursor_fg_bg (device, &foreground, &background,
1129                                &fg_color, &bg_color);
1130
1131         IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
1132         IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
1133         IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) =
1134           find_keyword_in_vector (instantiator, Q_hotspot_x);
1135         IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) =
1136           find_keyword_in_vector (instantiator, Q_hotspot_y);
1137         IMAGE_INSTANCE_X_CURSOR (ii) =
1138           XCreatePixmapCursor
1139             (dpy, source, mask, &fg_color, &bg_color,
1140              !NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)) ?
1141              XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)) : 0,
1142              !NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)) ?
1143              XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)) : 0);
1144       }
1145       break;
1146
1147     default:
1148       abort ();
1149     }
1150 }
1151
1152 static void
1153 xbm_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator,
1154                    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1155                    int dest_mask, int width, int height,
1156                    /* Note that data is in ext-format! */
1157                    const char *bits)
1158 {
1159   Lisp_Object mask_data = find_keyword_in_vector (instantiator, Q_mask_data);
1160   Lisp_Object mask_file = find_keyword_in_vector (instantiator, Q_mask_file);
1161   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1162   Pixmap mask = 0;
1163
1164   if (!NILP (mask_data))
1165     {
1166       const char *ext_data;
1167
1168       LISP_STRING_TO_EXTERNAL (XCAR (XCDR (XCDR (mask_data))), ext_data, Qbinary);
1169       mask = pixmap_from_xbm_inline (IMAGE_INSTANCE_DEVICE (ii),
1170                                      XINT (XCAR (mask_data)),
1171                                      XINT (XCAR (XCDR (mask_data))),
1172                                      ext_data);
1173     }
1174
1175   init_image_instance_from_xbm_inline (ii, width, height, bits,
1176                                        instantiator, pointer_fg, pointer_bg,
1177                                        dest_mask, mask, mask_file);
1178 }
1179
1180 /* Instantiate method for XBM's. */
1181
1182 static void
1183 x_xbm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1184                    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1185                    int dest_mask, Lisp_Object domain)
1186 {
1187   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1188   const char *ext_data;
1189
1190   assert (!NILP (data));
1191
1192   LISP_STRING_TO_EXTERNAL (XCAR (XCDR (XCDR (data))), ext_data, Qbinary);
1193
1194   xbm_instantiate_1 (image_instance, instantiator, pointer_fg,
1195                      pointer_bg, dest_mask, XINT (XCAR (data)),
1196                      XINT (XCAR (XCDR (data))), ext_data);
1197 }
1198
1199 \f
1200 #ifdef HAVE_XPM
1201
1202 /**********************************************************************
1203  *                             XPM                                    *
1204  **********************************************************************/
1205  /* xpm 3.2g and better has XpmCreatePixmapFromBuffer()...
1206     There was no version number in xpm.h before 3.3, but this should do.
1207   */
1208 #if (XpmVersion >= 3) || defined(XpmExactColors)
1209 # define XPM_DOES_BUFFERS
1210 #endif
1211
1212 #ifndef XPM_DOES_BUFFERS
1213 Your version of XPM is too old.  You cannot compile with it.
1214 Upgrade to version 3.2g or better or compile with --with-xpm=no.
1215 #endif /* !XPM_DOES_BUFFERS */
1216
1217 static XpmColorSymbol *
1218 extract_xpm_color_names (XpmAttributes *xpmattrs, Lisp_Object device,
1219                          Lisp_Object domain,
1220                          Lisp_Object color_symbol_alist)
1221 {
1222   /* This function can GC */
1223   Display *dpy =  DEVICE_X_DISPLAY (XDEVICE(device));
1224   Colormap cmap = DEVICE_X_COLORMAP (XDEVICE(device));
1225   XColor color;
1226   Lisp_Object rest;
1227   Lisp_Object results = Qnil;
1228   int i;
1229   XpmColorSymbol *symbols;
1230   struct gcpro gcpro1, gcpro2;
1231
1232   GCPRO2 (results, device);
1233
1234   /* We built up results to be (("name" . #<color>) ...) so that if an
1235      error happens we don't lose any malloc()ed data, or more importantly,
1236      leave any pixels allocated in the server. */
1237   i = 0;
1238   LIST_LOOP (rest, color_symbol_alist)
1239     {
1240       Lisp_Object cons = XCAR (rest);
1241       Lisp_Object name = XCAR (cons);
1242       Lisp_Object value = XCDR (cons);
1243       if (NILP (value))
1244         continue;
1245       if (STRINGP (value))
1246         value =
1247           Fmake_color_instance
1248             (value, device, encode_error_behavior_flag (ERROR_ME_NOT));
1249       else
1250         {
1251           assert (COLOR_SPECIFIERP (value));
1252           value = Fspecifier_instance (value, domain, Qnil, Qnil);
1253         }
1254       if (NILP (value))
1255         continue;
1256       results = noseeum_cons (noseeum_cons (name, value), results);
1257       i++;
1258     }
1259   UNGCPRO;                      /* no more evaluation */
1260
1261   if (i == 0) return 0;
1262
1263   symbols = xnew_array (XpmColorSymbol, i);
1264   xpmattrs->valuemask |= XpmColorSymbols;
1265   xpmattrs->colorsymbols = symbols;
1266   xpmattrs->numsymbols = i;
1267
1268   while (--i >= 0)
1269     {
1270       Lisp_Object cons = XCAR (results);
1271       color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (XCDR (cons)));
1272       /* Duplicate the pixel value so that we still have a lock on it if
1273          the pixel we were passed is later freed. */
1274       if (! XAllocColor (dpy, cmap, &color))
1275         abort ();  /* it must be allocable since we're just duplicating it */
1276
1277       symbols [i].name = (char *) XSTRING_DATA (XCAR (cons));
1278       symbols [i].pixel = color.pixel;
1279       symbols [i].value = 0;
1280       free_cons (XCONS (cons));
1281       cons = results;
1282       results = XCDR (results);
1283       free_cons (XCONS (cons));
1284     }
1285   return symbols;
1286 }
1287
1288 static void
1289 xpm_free (XpmAttributes *xpmattrs)
1290 {
1291   /* Could conceivably lose if XpmXXX returned an error without first
1292      initializing this structure, if we didn't know that initializing it
1293      to all zeros was ok (and also that it's ok to call XpmFreeAttributes()
1294      multiple times, since it zeros slots as it frees them...) */
1295   XpmFreeAttributes (xpmattrs);
1296 }
1297
1298 static void
1299 x_xpm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1300                    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1301                    int dest_mask, Lisp_Object domain)
1302 {
1303   /* This function can GC */
1304   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1305   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1306   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1307   Display *dpy;
1308   Screen *xs;
1309   Colormap cmap;
1310   int depth;
1311   Visual *visual;
1312   Pixmap pixmap;
1313   Pixmap mask = 0;
1314   XpmAttributes xpmattrs;
1315   int result;
1316   XpmColorSymbol *color_symbols;
1317   Lisp_Object color_symbol_alist = find_keyword_in_vector (instantiator,
1318                                                            Q_color_symbols);
1319   enum image_instance_type type;
1320   int force_mono;
1321   unsigned int w, h;
1322
1323   if (!DEVICE_X_P (XDEVICE (device)))
1324     signal_simple_error ("Not an X device", device);
1325
1326   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
1327   xs = DefaultScreenOfDisplay (dpy);
1328
1329   if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1330     type = IMAGE_COLOR_PIXMAP;
1331   else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1332     type = IMAGE_MONO_PIXMAP;
1333   else if (dest_mask & IMAGE_POINTER_MASK)
1334     type = IMAGE_POINTER;
1335   else
1336     incompatible_image_types (instantiator, dest_mask,
1337                               IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
1338                               | IMAGE_POINTER_MASK);
1339   force_mono = (type != IMAGE_COLOR_PIXMAP);
1340
1341 #if 1
1342   /* Although I haven't found it documented yet, it appears that pointers are
1343      always colored via the default window colormap... Sigh. */
1344   if (type == IMAGE_POINTER)
1345     {
1346       cmap = DefaultColormap(dpy, DefaultScreen(dpy));
1347       depth = DefaultDepthOfScreen (xs);
1348       visual = DefaultVisualOfScreen (xs);
1349     }
1350   else
1351     {
1352       cmap = DEVICE_X_COLORMAP (XDEVICE(device));
1353       depth = DEVICE_X_DEPTH (XDEVICE(device));
1354       visual = DEVICE_X_VISUAL (XDEVICE(device));
1355     }
1356 #else
1357   cmap = DEVICE_X_COLORMAP (XDEVICE(device));
1358   depth = DEVICE_X_DEPTH (XDEVICE(device));
1359   visual = DEVICE_X_VISUAL (XDEVICE(device));
1360 #endif
1361
1362   x_initialize_pixmap_image_instance (ii, 1, type);
1363
1364   assert (!NILP (data));
1365
1366  retry:
1367
1368   xzero (xpmattrs); /* want XpmInitAttributes() */
1369   xpmattrs.valuemask = XpmReturnPixels;
1370   if (force_mono)
1371     {
1372       /* Without this, we get a 1-bit version of the color image, which
1373          isn't quite right.  With this, we get the mono image, which might
1374          be very different looking. */
1375       xpmattrs.valuemask |= XpmColorKey;
1376       xpmattrs.color_key = XPM_MONO;
1377       xpmattrs.depth = 1;
1378       xpmattrs.valuemask |= XpmDepth;
1379     }
1380   else
1381     {
1382       xpmattrs.closeness = 65535;
1383       xpmattrs.valuemask |= XpmCloseness;
1384       xpmattrs.depth = depth;
1385       xpmattrs.valuemask |= XpmDepth;
1386       xpmattrs.visual = visual;
1387       xpmattrs.valuemask |= XpmVisual;
1388       xpmattrs.colormap = cmap;
1389       xpmattrs.valuemask |= XpmColormap;
1390     }
1391
1392   color_symbols = extract_xpm_color_names (&xpmattrs, device, domain,
1393                                            color_symbol_alist);
1394
1395   result = XpmCreatePixmapFromBuffer (dpy,
1396                                       XtWindow(DEVICE_XT_APP_SHELL (XDEVICE(device))),
1397                                       (char *) XSTRING_DATA (data),
1398                                       &pixmap, &mask, &xpmattrs);
1399
1400   if (color_symbols)
1401     {
1402       xfree (color_symbols);
1403       xpmattrs.colorsymbols = 0; /* in case XpmFreeAttr is too smart... */
1404       xpmattrs.numsymbols = 0;
1405     }
1406
1407   switch (result)
1408     {
1409     case XpmSuccess:
1410       break;
1411     case XpmFileInvalid:
1412       {
1413         xpm_free (&xpmattrs);
1414         signal_image_error ("invalid XPM data", data);
1415       }
1416     case XpmColorFailed:
1417     case XpmColorError:
1418       {
1419         xpm_free (&xpmattrs);
1420         if (force_mono)
1421           {
1422             /* second time; blow out. */
1423             signal_double_file_error ("Reading pixmap data",
1424                                       "color allocation failed",
1425                                       data);
1426           }
1427         else
1428           {
1429             if (! (dest_mask & IMAGE_MONO_PIXMAP_MASK))
1430               {
1431                 /* second time; blow out. */
1432                 signal_double_file_error ("Reading pixmap data",
1433                                           "color allocation failed",
1434                                           data);
1435               }
1436             force_mono = 1;
1437             IMAGE_INSTANCE_TYPE (ii) = IMAGE_MONO_PIXMAP;
1438             goto retry;
1439           }
1440       }
1441     case XpmNoMemory:
1442       {
1443         xpm_free (&xpmattrs);
1444         signal_double_file_error ("Parsing pixmap data",
1445                                   "out of memory", data);
1446       }
1447     default:
1448       {
1449         xpm_free (&xpmattrs);
1450         signal_double_file_error_2 ("Parsing pixmap data",
1451                                     "unknown error code",
1452                                     make_int (result), data);
1453       }
1454     }
1455
1456   w = xpmattrs.width;
1457   h = xpmattrs.height;
1458
1459   {
1460     int npixels = xpmattrs.npixels;
1461     Pixel *pixels;
1462
1463     if (npixels != 0)
1464       {
1465         pixels = xnew_array (Pixel, npixels);
1466         memcpy (pixels, xpmattrs.pixels, npixels * sizeof (Pixel));
1467       }
1468     else
1469       pixels = NULL;
1470
1471     IMAGE_INSTANCE_X_PIXMAP (ii) = pixmap;
1472     IMAGE_INSTANCE_PIXMAP_MASK (ii) = (void*)mask;
1473     IMAGE_INSTANCE_X_COLORMAP (ii) = cmap;
1474     IMAGE_INSTANCE_X_PIXELS (ii) = pixels;
1475     IMAGE_INSTANCE_X_NPIXELS (ii) = npixels;
1476     IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = w;
1477     IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = h;
1478     IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
1479       find_keyword_in_vector (instantiator, Q_file);
1480   }
1481
1482   switch (type)
1483     {
1484     case IMAGE_MONO_PIXMAP:
1485       break;
1486
1487     case IMAGE_COLOR_PIXMAP:
1488       {
1489         IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = depth;
1490       }
1491       break;
1492
1493     case IMAGE_POINTER:
1494       {
1495         int npixels = xpmattrs.npixels;
1496         Pixel *pixels = xpmattrs.pixels;
1497         XColor fg, bg;
1498         int i;
1499         int xhot = 0, yhot = 0;
1500
1501         if (xpmattrs.valuemask & XpmHotspot)
1502           {
1503             xhot = xpmattrs.x_hotspot;
1504             XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), xpmattrs.x_hotspot);
1505           }
1506         if (xpmattrs.valuemask & XpmHotspot)
1507           {
1508             yhot = xpmattrs.y_hotspot;
1509             XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), xpmattrs.y_hotspot);
1510           }
1511         check_pointer_sizes (xs, w, h, instantiator);
1512
1513         /* If the loaded pixmap has colors allocated (meaning it came from an
1514            XPM file), then use those as the default colors for the cursor we
1515            create.  Otherwise, default to pointer_fg and pointer_bg.
1516            */
1517         if (npixels >= 2)
1518           {
1519             /* With an XBM file, it's obvious which bit is foreground
1520                and which is background, or rather, it's implicit: in
1521                an XBM file, a 1 bit is foreground, and a 0 bit is
1522                background.
1523
1524                XCreatePixmapCursor() assumes this property of the
1525                pixmap it is called with as well; the `foreground'
1526                color argument is used for the 1 bits.
1527
1528                With an XPM file, it's tricker, since the elements of
1529                the pixmap don't represent FG and BG, but are actual
1530                pixel values.  So we need to figure out which of those
1531                pixels is the foreground color and which is the
1532                background.  We do it by comparing RGB and assuming
1533                that the darker color is the foreground.  This works
1534                with the result of xbmtopbm|ppmtoxpm, at least.
1535
1536                It might be nice if there was some way to tag the
1537                colors in the XPM file with whether they are the
1538                foreground - perhaps with logical color names somehow?
1539
1540                Once we have decided which color is the foreground, we
1541                need to ensure that that color corresponds to a `1' bit
1542                in the Pixmap.  The XPM library wrote into the (1-bit)
1543                pixmap with XPutPixel, which will ignore all but the
1544                least significant bit.
1545
1546                This means that a 1 bit in the image corresponds to
1547                `fg' only if `fg.pixel' is odd.
1548
1549                (This also means that the image will be all the same
1550                color if both `fg' and `bg' are odd or even, but we can
1551                safely assume that that won't happen if the XPM file is
1552                sensible I think.)
1553
1554                The desired result is that the image use `1' to
1555                represent the foreground color, and `0' to represent
1556                the background color.  So, we may need to invert the
1557                image to accomplish this; we invert if fg is
1558                odd. (Remember that WhitePixel and BlackPixel are not
1559                necessarily 1 and 0 respectively, though I think it
1560                might be safe to assume that one of them is always 1
1561                and the other is always 0.  We also pretty much need to
1562                assume that one is even and the other is odd.)
1563                */
1564
1565             fg.pixel = pixels[0];       /* pick a pixel at random. */
1566             bg.pixel = fg.pixel;
1567             for (i = 1; i < npixels; i++) /* Look for an "other" pixel value.*/
1568               {
1569                 bg.pixel = pixels[i];
1570                 if (fg.pixel != bg.pixel)
1571                   break;
1572               }
1573
1574             /* If (fg.pixel == bg.pixel) then probably something has
1575                gone wrong, but I don't think signalling an error would
1576                be appropriate. */
1577
1578             XQueryColor (dpy, cmap, &fg);
1579             XQueryColor (dpy, cmap, &bg);
1580
1581             /* If the foreground is lighter than the background, swap them.
1582                (This occurs semi-randomly, depending on the ordering of the
1583                color list in the XPM file.)
1584                */
1585             {
1586               unsigned short fg_total = ((fg.red / 3) + (fg.green / 3)
1587                                          + (fg.blue / 3));
1588               unsigned short bg_total = ((bg.red / 3) + (bg.green / 3)
1589                                          + (bg.blue / 3));
1590               if (fg_total > bg_total)
1591                 {
1592                   XColor swap;
1593                   swap = fg;
1594                   fg = bg;
1595                   bg = swap;
1596                 }
1597             }
1598
1599             /* If the fg pixel corresponds to a `0' in the bitmap, invert it.
1600                (This occurs (only?) on servers with Black=0, White=1.)
1601                */
1602             if ((fg.pixel & 1) == 0)
1603               {
1604                 XGCValues gcv;
1605                 GC gc;
1606                 gcv.function = GXxor;
1607                 gcv.foreground = 1;
1608                 gc = XCreateGC (dpy, pixmap, (GCFunction | GCForeground),
1609                                 &gcv);
1610                 XFillRectangle (dpy, pixmap, gc, 0, 0, w, h);
1611                 XFreeGC (dpy, gc);
1612               }
1613           }
1614         else
1615           {
1616             generate_cursor_fg_bg (device, &pointer_fg, &pointer_bg,
1617                                    &fg, &bg);
1618             IMAGE_INSTANCE_PIXMAP_FG (ii) = pointer_fg;
1619             IMAGE_INSTANCE_PIXMAP_BG (ii) = pointer_bg;
1620           }
1621
1622         IMAGE_INSTANCE_X_CURSOR (ii) =
1623           XCreatePixmapCursor
1624             (dpy, pixmap, mask, &fg, &bg, xhot, yhot);
1625       }
1626
1627       break;
1628
1629     default:
1630       abort ();
1631     }
1632
1633   xpm_free (&xpmattrs); /* after we've read pixels and hotspot */
1634 }
1635
1636 #endif /* HAVE_XPM */
1637
1638 \f
1639 #ifdef HAVE_XFACE
1640
1641 /**********************************************************************
1642  *                             X-Face                                 *
1643  **********************************************************************/
1644 #if defined(EXTERN)
1645 /* This is about to get redefined! */
1646 #undef EXTERN
1647 #endif
1648 /* We have to define SYSV32 so that compface.h includes string.h
1649    instead of strings.h. */
1650 #define SYSV32
1651 #ifdef __cplusplus
1652 extern "C" {
1653 #endif
1654 #include <compface.h>
1655 #ifdef __cplusplus
1656 }
1657 #endif
1658 /* JMP_BUF cannot be used here because if it doesn't get defined
1659    to jmp_buf we end up with a conflicting type error with the
1660    definition in compface.h */
1661 extern jmp_buf comp_env;
1662 #undef SYSV32
1663
1664 static void
1665 x_xface_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1666                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1667                      int dest_mask, Lisp_Object domain)
1668 {
1669   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1670   int i, stattis;
1671   char *bits, *bp;
1672   const char *p;
1673   const char * volatile emsg = 0;
1674   const char * volatile dstring;
1675
1676   assert (!NILP (data));
1677
1678   LISP_STRING_TO_EXTERNAL (data, dstring, Qbinary);
1679
1680   if ((p = strchr (dstring, ':')))
1681     {
1682       dstring = p + 1;
1683     }
1684
1685   /* Must use setjmp not SETJMP because we used jmp_buf above not JMP_BUF */
1686   if (!(stattis = setjmp (comp_env)))
1687     {
1688       UnCompAll ((char *) dstring);
1689       UnGenFace ();
1690     }
1691
1692   switch (stattis)
1693     {
1694     case -2:
1695       emsg = "uncompface: internal error";
1696       break;
1697     case -1:
1698       emsg = "uncompface: insufficient or invalid data";
1699       break;
1700     case 1:
1701       emsg = "uncompface: excess data ignored";
1702       break;
1703     }
1704
1705   if (emsg)
1706     signal_simple_error_2 (emsg, data, Qimage);
1707
1708   bp = bits = (char *) alloca (PIXELS / 8);
1709
1710   /* the compface library exports char F[], which uses a single byte per
1711      pixel to represent a 48x48 bitmap.  Yuck. */
1712   for (i = 0, p = F; i < (PIXELS / 8); ++i)
1713     {
1714       int n, b;
1715       /* reverse the bit order of each byte... */
1716       for (b = n = 0; b < 8; ++b)
1717         {
1718           n |= ((*p++) << b);
1719         }
1720       *bp++ = (char) n;
1721     }
1722
1723   xbm_instantiate_1 (image_instance, instantiator, pointer_fg,
1724                      pointer_bg, dest_mask, 48, 48, bits);
1725 }
1726
1727 #endif /* HAVE_XFACE */
1728
1729 \f
1730 /**********************************************************************
1731  *                       Autodetect                                      *
1732  **********************************************************************/
1733
1734 static void
1735 autodetect_validate (Lisp_Object instantiator)
1736 {
1737   data_must_be_present (instantiator);
1738 }
1739
1740 static Lisp_Object
1741 autodetect_normalize (Lisp_Object instantiator,
1742                       Lisp_Object console_type,
1743                       Lisp_Object dest_mask)
1744 {
1745   Lisp_Object file = find_keyword_in_vector (instantiator, Q_data);
1746   Lisp_Object filename = Qnil;
1747   Lisp_Object data = Qnil;
1748   struct gcpro gcpro1, gcpro2, gcpro3;
1749   Lisp_Object alist = Qnil;
1750
1751   GCPRO3 (filename, data, alist);
1752
1753   if (NILP (file)) /* no conversion necessary */
1754     RETURN_UNGCPRO (instantiator);
1755
1756   alist = tagged_vector_to_alist (instantiator);
1757
1758   filename = locate_pixmap_file (file);
1759   if (!NILP (filename))
1760     {
1761       int xhot, yhot;
1762       /* #### Apparently some versions of XpmReadFileToData, which is
1763          called by pixmap_to_lisp_data, don't return an error value
1764          if the given file is not a valid XPM file.  Instead, they
1765          just seg fault.  It is definitely caused by passing a
1766          bitmap.  To try and avoid this we check for bitmaps first.  */
1767
1768       data = bitmap_to_lisp_data (filename, &xhot, &yhot, 1);
1769
1770       if (!EQ (data, Qt))
1771         {
1772           alist = remassq_no_quit (Q_data, alist);
1773           alist = Fcons (Fcons (Q_file, filename),
1774                          Fcons (Fcons (Q_data, data), alist));
1775           if (xhot != -1)
1776             alist = Fcons (Fcons (Q_hotspot_x, make_int (xhot)),
1777                            alist);
1778           if (yhot != -1)
1779             alist = Fcons (Fcons (Q_hotspot_y, make_int (yhot)),
1780                            alist);
1781
1782           alist = xbm_mask_file_munging (alist, filename, Qnil, console_type);
1783
1784           {
1785             Lisp_Object result = alist_to_tagged_vector (Qxbm, alist);
1786             free_alist (alist);
1787             RETURN_UNGCPRO (result);
1788           }
1789         }
1790
1791 #ifdef HAVE_XPM
1792       data = pixmap_to_lisp_data (filename, 1);
1793
1794       if (!EQ (data, Qt))
1795         {
1796           alist = remassq_no_quit (Q_data, alist);
1797           alist = Fcons (Fcons (Q_file, filename),
1798                          Fcons (Fcons (Q_data, data), alist));
1799           alist = Fcons (Fcons (Q_color_symbols,
1800                                 evaluate_xpm_color_symbols ()),
1801                          alist);
1802           {
1803             Lisp_Object result = alist_to_tagged_vector (Qxpm, alist);
1804             free_alist (alist);
1805             RETURN_UNGCPRO (result);
1806           }
1807         }
1808 #endif
1809     }
1810
1811   /* If we couldn't convert it, just put it back as it is.
1812      We might try to further frob it later as a cursor-font
1813      specification. (We can't do that now because we don't know
1814      what dest-types it's going to be instantiated into.) */
1815   {
1816     Lisp_Object result = alist_to_tagged_vector (Qautodetect, alist);
1817     free_alist (alist);
1818     RETURN_UNGCPRO (result);
1819   }
1820 }
1821
1822 static int
1823 autodetect_possible_dest_types (void)
1824 {
1825   return
1826     IMAGE_MONO_PIXMAP_MASK  |
1827     IMAGE_COLOR_PIXMAP_MASK |
1828     IMAGE_POINTER_MASK      |
1829     IMAGE_TEXT_MASK;
1830 }
1831
1832 static void
1833 autodetect_instantiate (Lisp_Object image_instance,
1834                         Lisp_Object instantiator,
1835                         Lisp_Object pointer_fg,
1836                         Lisp_Object pointer_bg,
1837                         int dest_mask, Lisp_Object domain)
1838 {
1839   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1840   struct gcpro gcpro1, gcpro2, gcpro3;
1841   Lisp_Object alist = Qnil;
1842   Lisp_Object result = Qnil;
1843   int is_cursor_font = 0;
1844
1845   GCPRO3 (data, alist, result);
1846
1847   alist = tagged_vector_to_alist (instantiator);
1848   if (dest_mask & IMAGE_POINTER_MASK)
1849     {
1850       const char *name_ext;
1851       LISP_STRING_TO_EXTERNAL (data, name_ext, Qfile_name);
1852       if (XmuCursorNameToIndex (name_ext) != -1)
1853         {
1854           result = alist_to_tagged_vector (Qcursor_font, alist);
1855           is_cursor_font = 1;
1856         }
1857     }
1858
1859   if (!is_cursor_font)
1860     result = alist_to_tagged_vector (Qstring, alist);
1861   free_alist (alist);
1862
1863   if (is_cursor_font)
1864     cursor_font_instantiate (image_instance, result, pointer_fg,
1865                              pointer_bg, dest_mask, domain);
1866   else
1867     string_instantiate (image_instance, result, pointer_fg,
1868                         pointer_bg, dest_mask, domain);
1869
1870   UNGCPRO;
1871 }
1872
1873 \f
1874 /**********************************************************************
1875  *                              Font                                  *
1876  **********************************************************************/
1877
1878 static void
1879 font_validate (Lisp_Object instantiator)
1880 {
1881   data_must_be_present (instantiator);
1882 }
1883
1884 /* XmuCvtStringToCursor is bogus in the following ways:
1885
1886    - When it can't convert the given string to a real cursor, it will
1887      sometimes return a "success" value, after triggering a BadPixmap
1888      error.  It then gives you a cursor that will itself generate BadCursor
1889      errors.  So we install this error handler to catch/notice the X error
1890      and take that as meaning "couldn't convert."
1891
1892    - When you tell it to find a cursor file that doesn't exist, it prints
1893      an error message on stderr.  You can't make it not do that.
1894
1895    - Also, using Xmu means we can't properly hack Lisp_Image_Instance
1896      objects, or XPM files, or $XBMLANGPATH.
1897  */
1898
1899 /* Duplicate the behavior of XmuCvtStringToCursor() to bypass its bogusness. */
1900
1901 static int XLoadFont_got_error;
1902
1903 static int
1904 XLoadFont_error_handler (Display *dpy, XErrorEvent *xerror)
1905 {
1906   XLoadFont_got_error = 1;
1907   return 0;
1908 }
1909
1910 static Font
1911 safe_XLoadFont (Display *dpy, char *name)
1912 {
1913   Font font;
1914   int (*old_handler) (Display *, XErrorEvent *);
1915   XLoadFont_got_error = 0;
1916   XSync (dpy, 0);
1917   old_handler = XSetErrorHandler (XLoadFont_error_handler);
1918   font = XLoadFont (dpy, name);
1919   XSync (dpy, 0);
1920   XSetErrorHandler (old_handler);
1921   if (XLoadFont_got_error) return 0;
1922   return font;
1923 }
1924
1925 static int
1926 font_possible_dest_types (void)
1927 {
1928   return IMAGE_POINTER_MASK;
1929 }
1930
1931 static void
1932 font_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1933                   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1934                   int dest_mask, Lisp_Object domain)
1935 {
1936   /* This function can GC */
1937   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1938   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1939   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1940   Display *dpy;
1941   XColor fg, bg;
1942   Font source, mask;
1943   char source_name[MAXPATHLEN], mask_name[MAXPATHLEN], dummy;
1944   int source_char, mask_char;
1945   int count;
1946   Lisp_Object foreground, background;
1947
1948   if (!DEVICE_X_P (XDEVICE (device)))
1949     signal_simple_error ("Not an X device", device);
1950
1951   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
1952
1953   if (!STRINGP (data) ||
1954       strncmp ("FONT ", (char *) XSTRING_DATA (data), 5))
1955     signal_simple_error ("Invalid font-glyph instantiator",
1956                          instantiator);
1957
1958   if (!(dest_mask & IMAGE_POINTER_MASK))
1959     incompatible_image_types (instantiator, dest_mask, IMAGE_POINTER_MASK);
1960
1961   foreground = find_keyword_in_vector (instantiator, Q_foreground);
1962   if (NILP (foreground))
1963     foreground = pointer_fg;
1964   background = find_keyword_in_vector (instantiator, Q_background);
1965   if (NILP (background))
1966     background = pointer_bg;
1967
1968   generate_cursor_fg_bg (device, &foreground, &background, &fg, &bg);
1969
1970   count = sscanf ((char *) XSTRING_DATA (data),
1971                   "FONT %s %d %s %d %c",
1972                   source_name, &source_char,
1973                   mask_name, &mask_char, &dummy);
1974   /* Allow "%s %d %d" as well... */
1975   if (count == 3 && (1 == sscanf (mask_name, "%d %c", &mask_char, &dummy)))
1976     count = 4, mask_name[0] = 0;
1977
1978   if (count != 2 && count != 4)
1979     signal_simple_error ("invalid cursor specification", data);
1980   source = safe_XLoadFont (dpy, source_name);
1981   if (! source)
1982     signal_simple_error_2 ("couldn't load font",
1983                            build_string (source_name),
1984                            data);
1985   if (count == 2)
1986     mask = 0;
1987   else if (!mask_name[0])
1988     mask = source;
1989   else
1990     {
1991       mask = safe_XLoadFont (dpy, mask_name);
1992       if (!mask)
1993         /* continuable */
1994         Fsignal (Qerror, list3 (build_string ("couldn't load font"),
1995                                 build_string (mask_name), data));
1996     }
1997   if (!mask)
1998     mask_char = 0;
1999
2000   /* #### call XQueryTextExtents() and check_pointer_sizes() here. */
2001
2002   x_initialize_pixmap_image_instance (ii, 1, IMAGE_POINTER);
2003   IMAGE_INSTANCE_X_CURSOR (ii) =
2004     XCreateGlyphCursor (dpy, source, mask, source_char, mask_char,
2005                         &fg, &bg);
2006   XIMAGE_INSTANCE_PIXMAP_FG (image_instance) = foreground;
2007   XIMAGE_INSTANCE_PIXMAP_BG (image_instance) = background;
2008   XUnloadFont (dpy, source);
2009   if (mask && mask != source) XUnloadFont (dpy, mask);
2010 }
2011
2012 \f
2013 /**********************************************************************
2014  *                           Cursor-Font                              *
2015  **********************************************************************/
2016
2017 static void
2018 cursor_font_validate (Lisp_Object instantiator)
2019 {
2020   data_must_be_present (instantiator);
2021 }
2022
2023 static int
2024 cursor_font_possible_dest_types (void)
2025 {
2026   return IMAGE_POINTER_MASK;
2027 }
2028
2029 static void
2030 cursor_font_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2031                          Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2032                          int dest_mask, Lisp_Object domain)
2033 {
2034   /* This function can GC */
2035   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
2036   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2037   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
2038   Display *dpy;
2039   int i;
2040   const char *name_ext;
2041   Lisp_Object foreground, background;
2042
2043   if (!DEVICE_X_P (XDEVICE (device)))
2044     signal_simple_error ("Not an X device", device);
2045
2046   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
2047
2048   if (!(dest_mask & IMAGE_POINTER_MASK))
2049     incompatible_image_types (instantiator, dest_mask, IMAGE_POINTER_MASK);
2050
2051   LISP_STRING_TO_EXTERNAL (data, name_ext, Qfile_name);
2052   if ((i = XmuCursorNameToIndex (name_ext)) == -1)
2053     signal_simple_error ("Unrecognized cursor-font name", data);
2054
2055   x_initialize_pixmap_image_instance (ii, 1, IMAGE_POINTER);
2056   IMAGE_INSTANCE_X_CURSOR (ii) = XCreateFontCursor (dpy, i);
2057   foreground = find_keyword_in_vector (instantiator, Q_foreground);
2058   if (NILP (foreground))
2059     foreground = pointer_fg;
2060   background = find_keyword_in_vector (instantiator, Q_background);
2061   if (NILP (background))
2062     background = pointer_bg;
2063   maybe_recolor_cursor (image_instance, foreground, background);
2064 }
2065
2066 static int
2067 x_colorize_image_instance (Lisp_Object image_instance,
2068                            Lisp_Object foreground, Lisp_Object background)
2069 {
2070   Lisp_Image_Instance *p;
2071
2072   p = XIMAGE_INSTANCE (image_instance);
2073
2074   switch (IMAGE_INSTANCE_TYPE (p))
2075     {
2076     case IMAGE_MONO_PIXMAP:
2077       IMAGE_INSTANCE_TYPE (p) = IMAGE_COLOR_PIXMAP;
2078       /* Make sure there aren't two pointers to the same mask, causing
2079          it to get freed twice. */
2080       IMAGE_INSTANCE_PIXMAP_MASK (p) = 0;
2081       break;
2082
2083     default:
2084       return 0;
2085     }
2086
2087   {
2088     Display *dpy = DEVICE_X_DISPLAY (XDEVICE (IMAGE_INSTANCE_DEVICE (p)));
2089     Drawable draw = XtWindow(DEVICE_XT_APP_SHELL (XDEVICE (IMAGE_INSTANCE_DEVICE (p))));
2090     Dimension d = DEVICE_X_DEPTH (XDEVICE (IMAGE_INSTANCE_DEVICE (p)));
2091     Pixmap new = XCreatePixmap (dpy, draw,
2092                                 IMAGE_INSTANCE_PIXMAP_WIDTH (p),
2093                                 IMAGE_INSTANCE_PIXMAP_HEIGHT (p), d);
2094     XColor color;
2095     XGCValues gcv;
2096     GC gc;
2097     color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (foreground));
2098     gcv.foreground = color.pixel;
2099     color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (background));
2100     gcv.background = color.pixel;
2101     gc = XCreateGC (dpy, new, GCBackground|GCForeground, &gcv);
2102     XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), new, gc, 0, 0,
2103                 IMAGE_INSTANCE_PIXMAP_WIDTH (p),
2104                 IMAGE_INSTANCE_PIXMAP_HEIGHT (p),
2105                 0, 0, 1);
2106     XFreeGC (dpy, gc);
2107     IMAGE_INSTANCE_X_PIXMAP (p) = new;
2108     IMAGE_INSTANCE_PIXMAP_DEPTH (p) = d;
2109     IMAGE_INSTANCE_PIXMAP_FG (p) = foreground;
2110     IMAGE_INSTANCE_PIXMAP_BG (p) = background;
2111     return 1;
2112   }
2113 }
2114
2115 \f
2116 /************************************************************************/
2117 /*                      subwindow and widget support                      */
2118 /************************************************************************/
2119
2120 /* unmap the image if it is a widget. This is used by redisplay via
2121    redisplay_unmap_subwindows */
2122 static void
2123 x_unmap_subwindow (Lisp_Image_Instance *p)
2124 {
2125   if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
2126     {
2127       XUnmapWindow
2128         (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2129          IMAGE_INSTANCE_X_CLIPWINDOW (p));
2130     }
2131   else                          /* must be a widget */
2132     {
2133       XtUnmapWidget (IMAGE_INSTANCE_X_CLIPWIDGET (p));
2134     }
2135 }
2136
2137 /* map the subwindow. This is used by redisplay via
2138    redisplay_output_subwindow */
2139 static void
2140 x_map_subwindow (Lisp_Image_Instance *p, int x, int y,
2141                  struct display_glyph_area* dga)
2142 {
2143   if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
2144     {
2145       Window subwindow = IMAGE_INSTANCE_X_SUBWINDOW_ID (p);
2146       XMoveResizeWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2147                          IMAGE_INSTANCE_X_CLIPWINDOW (p),
2148                          x, y, dga->width, dga->height);
2149       XMoveWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2150                    subwindow, -dga->xoffset, -dga->yoffset);
2151       if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (p))
2152         XMapWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2153                     IMAGE_INSTANCE_X_CLIPWINDOW (p));
2154     }
2155   else                          /* must be a widget */
2156     {
2157       XtConfigureWidget (IMAGE_INSTANCE_X_CLIPWIDGET (p),
2158                          x + IMAGE_INSTANCE_X_WIDGET_XOFFSET (p),
2159                          y + IMAGE_INSTANCE_X_WIDGET_YOFFSET (p),
2160                          dga->width, dga->height, 0);
2161       XtMoveWidget (IMAGE_INSTANCE_X_WIDGET_ID (p),
2162                     -dga->xoffset, -dga->yoffset);
2163       if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (p))
2164         XtMapWidget (IMAGE_INSTANCE_X_CLIPWIDGET (p));
2165     }
2166 }
2167
2168 /* when you click on a widget you may activate another widget this
2169    needs to be checked and all appropriate widgets updated */
2170 static void
2171 x_redisplay_subwindow (Lisp_Image_Instance *p)
2172 {
2173   /* Update the subwindow size if necessary. */
2174   if (IMAGE_INSTANCE_SIZE_CHANGED (p))
2175     {
2176       XResizeWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2177                      IMAGE_INSTANCE_X_SUBWINDOW_ID (p),
2178                      IMAGE_INSTANCE_WIDTH (p),
2179                      IMAGE_INSTANCE_HEIGHT (p));
2180     }
2181 }
2182
2183 /* Update all attributes that have changed. Lwlib actually does most
2184    of this for us. */
2185 static void
2186 x_redisplay_widget (Lisp_Image_Instance *p)
2187 {
2188   /* This function can GC if IN_REDISPLAY is false. */
2189 #ifdef HAVE_WIDGETS
2190   widget_value* wv = 0;
2191
2192   /* First get the items if they have changed since this is a
2193      structural change. As such it will nuke all added values so we
2194      need to update most other things after the items have changed.*/
2195   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
2196     {
2197       Lisp_Object image_instance;
2198
2199       XSETIMAGE_INSTANCE (image_instance, p);
2200       wv = gui_items_to_widget_values
2201         (image_instance, IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (p),
2202          /* #### this is not right; we need to keep track of which widgets
2203             want accelerators and which don't */ 0);
2204       wv->change = STRUCTURAL_CHANGE;
2205     }
2206   else
2207     {
2208       /* Assume the lotus position, breath deeply and chant to
2209          yourself lwlibsux, lwlibsux ... lw_get_all_values returns a
2210          reference to the real values rather than a copy thus any
2211          changes we make to the values we get back will look like they
2212          have already been applied. If we rebuild the widget tree then
2213          we may lose properties. */
2214       wv = copy_widget_value_tree (lw_get_all_values 
2215                                    (IMAGE_INSTANCE_X_WIDGET_LWID (p)),
2216                                    NO_CHANGE);
2217     }
2218
2219   /* Possibly update the colors and font */
2220   if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p)
2221       ||
2222       XFRAME (IMAGE_INSTANCE_FRAME (p))->faces_changed
2223       ||
2224       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
2225     {
2226       update_widget_face (wv, p, IMAGE_INSTANCE_FRAME (p));
2227     }
2228
2229   /* Possibly update the text. */
2230   if (IMAGE_INSTANCE_TEXT_CHANGED (p))
2231     {
2232       char* str;
2233       Lisp_Object val = IMAGE_INSTANCE_WIDGET_TEXT (p);
2234       LISP_STRING_TO_EXTERNAL (val, str, Qnative);
2235       wv->value = str;
2236     }
2237
2238   /* Possibly update the size. */
2239   if (IMAGE_INSTANCE_SIZE_CHANGED (p)
2240       ||
2241       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p)
2242       ||
2243       IMAGE_INSTANCE_TEXT_CHANGED (p))
2244     {
2245       assert (IMAGE_INSTANCE_X_WIDGET_ID (p) &&
2246               IMAGE_INSTANCE_X_CLIPWIDGET (p)) ;
2247
2248       if (IMAGE_INSTANCE_X_WIDGET_ID (p)->core.being_destroyed
2249           || !XtIsManaged(IMAGE_INSTANCE_X_WIDGET_ID (p)))
2250         {
2251           Lisp_Object sw;
2252           XSETIMAGE_INSTANCE (sw, p);
2253           signal_simple_error ("XEmacs bug: subwindow is deleted", sw);
2254         }
2255
2256       lw_add_widget_value_arg (wv, XtNwidth,
2257                                (Dimension)IMAGE_INSTANCE_WIDTH (p));
2258       lw_add_widget_value_arg (wv, XtNheight,
2259                                (Dimension)IMAGE_INSTANCE_HEIGHT (p));
2260     }
2261
2262   /* now modify the widget */
2263   lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (p),
2264                          wv, True);
2265   free_widget_value_tree (wv);
2266 #endif
2267 }
2268
2269 /* instantiate and x type subwindow */
2270 static void
2271 x_subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2272                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2273                         int dest_mask, Lisp_Object domain)
2274 {
2275   /* This function can GC */
2276   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2277   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
2278   Lisp_Object frame = DOMAIN_FRAME (domain);
2279   struct frame* f = XFRAME (frame);
2280   Display *dpy;
2281   Screen *xs;
2282   Window pw, win;
2283   XSetWindowAttributes xswa;
2284   Mask valueMask = 0;
2285   unsigned int w = IMAGE_INSTANCE_WIDTH (ii),
2286     h = IMAGE_INSTANCE_HEIGHT (ii);
2287
2288   if (!DEVICE_X_P (XDEVICE (device)))
2289     signal_simple_error ("Not an X device", device);
2290
2291   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
2292   xs = DefaultScreenOfDisplay (dpy);
2293
2294   IMAGE_INSTANCE_TYPE (ii) = IMAGE_SUBWINDOW;
2295
2296   pw = XtWindow (FRAME_X_TEXT_WIDGET (f));
2297
2298   ii->data = xnew_and_zero (struct x_subwindow_data);
2299
2300   IMAGE_INSTANCE_X_SUBWINDOW_PARENT (ii) = pw;
2301   IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (ii) = DisplayOfScreen (xs);
2302
2303   xswa.backing_store = Always;
2304   valueMask |= CWBackingStore;
2305   xswa.colormap = DefaultColormapOfScreen (xs);
2306   valueMask |= CWColormap;
2307
2308   /* Create a window for clipping */
2309   IMAGE_INSTANCE_X_CLIPWINDOW (ii) =
2310     XCreateWindow (dpy, pw, 0, 0, w, h, 0, CopyFromParent,
2311                    InputOutput, CopyFromParent, valueMask,
2312                    &xswa);
2313
2314   /* Now put the subwindow inside the clip window. */
2315   win = XCreateWindow (dpy, IMAGE_INSTANCE_X_CLIPWINDOW (ii),
2316                        0, 0, w, h, 0, CopyFromParent,
2317                        InputOutput, CopyFromParent, valueMask,
2318                        &xswa);
2319
2320   IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void*)win;
2321 }
2322
2323 #if 0
2324 /* #### Should this function exist? If there's any doubt I'm not implementing it --andyp */
2325 DEFUN ("change-subwindow-property", Fchange_subwindow_property, 3, 3, 0, /*
2326 For the given SUBWINDOW, set PROPERTY to DATA, which is a string.
2327 Subwindows are not currently implemented.
2328 */
2329        (subwindow, property, data))
2330 {
2331   Atom property_atom;
2332   Lisp_Subwindow *sw;
2333   Display *dpy;
2334
2335   CHECK_SUBWINDOW (subwindow);
2336   CHECK_STRING (property);
2337   CHECK_STRING (data);
2338
2339   sw = XSUBWINDOW (subwindow);
2340   dpy = DisplayOfScreen (LISP_DEVICE_TO_X_SCREEN
2341                          (FRAME_DEVICE (XFRAME (sw->frame))));
2342
2343   property_atom = XInternAtom (dpy, (char *) XSTRING_DATA (property), False);
2344   XChangeProperty (dpy, sw->subwindow, property_atom, XA_STRING, 8,
2345                    PropModeReplace,
2346                    XSTRING_DATA   (data),
2347                    XSTRING_LENGTH (data));
2348
2349   return property;
2350 }
2351 #endif
2352
2353 \f
2354 #ifdef HAVE_WIDGETS
2355
2356 /************************************************************************/
2357 /*                            widgets                            */
2358 /************************************************************************/
2359
2360 static void
2361 update_widget_face (widget_value* wv, Lisp_Image_Instance *ii,
2362                     Lisp_Object domain)
2363 {
2364 #ifdef LWLIB_WIDGETS_MOTIF
2365   XmFontList fontList;
2366 #endif
2367   /* Update the foreground. */
2368   Lisp_Object pixel = FACE_FOREGROUND
2369     (IMAGE_INSTANCE_WIDGET_FACE (ii),
2370      domain);
2371   XColor fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel)), bcolor;
2372   lw_add_widget_value_arg (wv, XtNforeground, fcolor.pixel);
2373
2374   /* Update the background. */
2375   pixel = FACE_BACKGROUND (IMAGE_INSTANCE_WIDGET_FACE (ii),
2376                            domain);
2377   bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2378   lw_add_widget_value_arg (wv, XtNbackground, bcolor.pixel);
2379
2380 #ifdef LWLIB_WIDGETS_MOTIF
2381   fontList = XmFontListCreate
2382     (FONT_INSTANCE_X_FONT
2383      (XFONT_INSTANCE (query_string_font
2384                       (IMAGE_INSTANCE_WIDGET_TEXT (ii),
2385                        IMAGE_INSTANCE_WIDGET_FACE (ii),
2386                        domain))),  XmSTRING_DEFAULT_CHARSET);
2387   lw_add_widget_value_arg (wv, XmNfontList, (XtArgVal)fontList);
2388 #endif
2389   lw_add_widget_value_arg
2390     (wv, XtNfont, (XtArgVal)FONT_INSTANCE_X_FONT
2391      (XFONT_INSTANCE (query_string_font
2392                       (IMAGE_INSTANCE_WIDGET_TEXT (ii),
2393                        IMAGE_INSTANCE_WIDGET_FACE (ii),
2394                        domain))));
2395   wv->change = VISIBLE_CHANGE;
2396   /* #### Megahack - but its just getting too complicated to do this
2397      in the right place. */
2398   if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qtab_control))
2399     update_tab_widget_face (wv, ii, domain);
2400 }
2401
2402 static void
2403 update_tab_widget_face (widget_value* wv, Lisp_Image_Instance *ii,
2404                         Lisp_Object domain)
2405 {
2406   if (wv->contents)
2407     {
2408       widget_value* val = wv->contents, *cur;
2409
2410       /* Give each child label the correct foreground color. */
2411       Lisp_Object pixel = FACE_FOREGROUND
2412         (IMAGE_INSTANCE_WIDGET_FACE (ii),
2413          domain);
2414       XColor fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2415       lw_add_widget_value_arg (val, XtNtabForeground, fcolor.pixel);
2416       wv->change = VISIBLE_CHANGE;
2417       val->change = VISIBLE_CHANGE;
2418
2419       for (cur = val->next; cur; cur = cur->next)
2420         {
2421           cur->change = VISIBLE_CHANGE;
2422           if (cur->value)
2423             {
2424               lw_copy_widget_value_args (val, cur);
2425             }
2426         }
2427     }
2428 }
2429
2430 static void
2431 x_widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2432                       Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2433                       int dest_mask, Lisp_Object domain,
2434                       const char* type, widget_value* wv)
2435 {
2436   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2437   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii), pixel;
2438   struct device* d = XDEVICE (device);
2439   Lisp_Object frame = DOMAIN_FRAME (domain);
2440   struct frame* f = XFRAME (frame);
2441   char* nm=0;
2442   Widget wid;
2443   Arg al [32];
2444   int ac = 0;
2445   int id = new_lwlib_id ();
2446   widget_value* clip_wv;
2447   XColor fcolor, bcolor;
2448
2449   if (!DEVICE_X_P (d))
2450     signal_simple_error ("Not an X device", device);
2451
2452   /* have to set the type this late in case there is no device
2453      instantiation for a widget. But we can go ahead and do it without
2454      checking because there is always a generic instantiator. */
2455   IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
2456
2457   if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
2458     LISP_STRING_TO_EXTERNAL (IMAGE_INSTANCE_WIDGET_TEXT (ii), nm, Qnative);
2459
2460   ii->data = xnew_and_zero (struct x_subwindow_data);
2461
2462   /* Create a clip window to contain the subwidget. Incredibly the
2463      XEmacs manager seems to be the most appropriate widget for
2464      this. Nothing else is simple enough and yet does what is
2465      required. */
2466   clip_wv = xmalloc_widget_value ();
2467
2468   lw_add_widget_value_arg (clip_wv, XtNresize, False);
2469   lw_add_widget_value_arg (clip_wv, XtNwidth,
2470                            (Dimension)IMAGE_INSTANCE_WIDTH (ii));
2471   lw_add_widget_value_arg (clip_wv, XtNheight,
2472                            (Dimension)IMAGE_INSTANCE_HEIGHT (ii));
2473   clip_wv->enabled = True;
2474
2475   clip_wv->name = xstrdup ("clip-window");
2476   clip_wv->value = xstrdup ("clip-window");
2477
2478   IMAGE_INSTANCE_X_CLIPWIDGET (ii)
2479     = lw_create_widget ("clip-window", "clip-window", new_lwlib_id (),
2480                         clip_wv, FRAME_X_CONTAINER_WIDGET (f),
2481                         False, 0, 0, 0);
2482
2483   free_widget_value_tree (clip_wv);
2484
2485   /* copy any args we were given */
2486   ac = 0;
2487   lw_add_value_args_to_args (wv, al, &ac);
2488
2489   /* Fixup the colors. We have to do this *before* the widget gets
2490      created so that Motif will fix up the shadow colors
2491      correctly. Once the widget is created Motif won't do this
2492      anymore...*/
2493   pixel = FACE_FOREGROUND
2494     (IMAGE_INSTANCE_WIDGET_FACE (ii),
2495      IMAGE_INSTANCE_FRAME (ii));
2496   fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2497
2498   pixel = FACE_BACKGROUND
2499     (IMAGE_INSTANCE_WIDGET_FACE (ii),
2500      IMAGE_INSTANCE_FRAME (ii));
2501   bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2502
2503   lw_add_widget_value_arg (wv, XtNbackground, bcolor.pixel);
2504   lw_add_widget_value_arg (wv, XtNforeground, fcolor.pixel);
2505   /* we cannot allow widgets to resize themselves */
2506   lw_add_widget_value_arg (wv, XtNresize, False);
2507   lw_add_widget_value_arg (wv, XtNwidth,
2508                            (Dimension)IMAGE_INSTANCE_WIDTH (ii));
2509   lw_add_widget_value_arg (wv, XtNheight,
2510                            (Dimension)IMAGE_INSTANCE_HEIGHT (ii));
2511   /* update the font. */
2512   update_widget_face (wv, ii, domain);
2513
2514   wid = lw_create_widget (type, wv->name, id, wv, IMAGE_INSTANCE_X_CLIPWIDGET (ii),
2515                           False, 0, popup_selection_callback, 0);
2516
2517   IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void*)wid;
2518   IMAGE_INSTANCE_X_WIDGET_LWID (ii) = id;
2519   /* because the EmacsManager is the widgets parent we have to
2520      offset the redisplay of the widget by the amount the text
2521      widget is inside the manager. */
2522   ac = 0;
2523   XtSetArg (al [ac], XtNx, &IMAGE_INSTANCE_X_WIDGET_XOFFSET (ii)); ac++;
2524   XtSetArg (al [ac], XtNy, &IMAGE_INSTANCE_X_WIDGET_YOFFSET (ii)); ac++;
2525   XtGetValues (FRAME_X_TEXT_WIDGET (f), al, ac);
2526
2527   XtSetMappedWhenManaged (wid, TRUE);
2528
2529   free_widget_value_tree (wv);
2530   /* A kludgy but simple way to make sure the callback for a widget
2531      doesn't get deleted. */
2532   gcpro_popup_callbacks (id);
2533 }
2534
2535 /* get properties of a control */
2536 static Lisp_Object
2537 x_widget_property (Lisp_Object image_instance, Lisp_Object prop)
2538 {
2539   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2540   /* get the text from a control */
2541   if (EQ (prop, Q_text))
2542     {
2543       widget_value* wv = lw_get_all_values (IMAGE_INSTANCE_X_WIDGET_LWID (ii));
2544       return build_ext_string (wv->value, Qnative);
2545     }
2546   return Qunbound;
2547 }
2548
2549 /* Instantiate a layout control for putting other widgets in. */
2550 static void
2551 x_native_layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2552                              Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2553                              int dest_mask, Lisp_Object domain)
2554 {
2555   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2556                         pointer_bg, dest_mask, domain, "layout", 0);
2557 }
2558
2559 /* Instantiate a button widget. Unfortunately instantiated widgets are
2560    particular to a frame since they need to have a parent. It's not
2561    like images where you just select the image into the context you
2562    want to display it in and BitBlt it. So images instances can have a
2563    many-to-one relationship with things you see, whereas widgets can
2564    only be one-to-one (i.e. per frame) */
2565 static void
2566 x_button_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2567                       Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2568                       int dest_mask, Lisp_Object domain)
2569 {
2570   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2571   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2572   Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
2573   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 1);
2574
2575   if (!NILP (glyph))
2576     {
2577       if (!IMAGE_INSTANCEP (glyph))
2578         glyph = glyph_image_instance (glyph, domain, ERROR_ME, 1);
2579     }
2580
2581   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2582                         pointer_bg, dest_mask, domain, "button", wv);
2583
2584   /* add the image if one was given */
2585   if (!NILP (glyph) && IMAGE_INSTANCEP (glyph)
2586       && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (glyph)))
2587     {
2588       Arg al [2];
2589       int ac =0;
2590 #ifdef LWLIB_WIDGETS_MOTIF
2591       XtSetArg (al [ac], XmNlabelType, XmPIXMAP);       ac++;
2592       XtSetArg (al [ac], XmNlabelPixmap, XIMAGE_INSTANCE_X_PIXMAP (glyph));ac++;
2593 #else
2594       XtSetArg (al [ac], XtNpixmap, XIMAGE_INSTANCE_X_PIXMAP (glyph));  ac++;
2595 #endif
2596       XtSetValues (IMAGE_INSTANCE_X_WIDGET_ID (ii), al, ac);
2597     }
2598 }
2599
2600 /* Update a button's clicked state.
2601
2602    #### This is overkill, but it works. Right now this causes all
2603    button instances to flash for some reason buried deep in lwlib. In
2604    theory this should be the Right Thing to do since lwlib should only
2605    merge in changed values - and if nothing has changed then nothing
2606    should get done. This may be because of the args stuff,
2607    i.e. although the arg contents may be the same the args look
2608    different and so are re-applied to the widget. */
2609 static void
2610 x_button_redisplay (Lisp_Object image_instance)
2611 {
2612   /* This function can GC if IN_REDISPLAY is false. */
2613   Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
2614   widget_value* wv =
2615     gui_items_to_widget_values (image_instance,
2616                                 IMAGE_INSTANCE_WIDGET_ITEMS (p), 1);
2617
2618   /* now modify the widget */
2619   lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (p),
2620                          wv, True);
2621   free_widget_value_tree (wv);
2622 }
2623
2624 /* get properties of a button */
2625 static Lisp_Object
2626 x_button_property (Lisp_Object image_instance, Lisp_Object prop)
2627 {
2628   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2629   /* check the state of a button */
2630   if (EQ (prop, Q_selected))
2631     {
2632       widget_value* wv = lw_get_all_values (IMAGE_INSTANCE_X_WIDGET_LWID (ii));
2633
2634       if (wv->selected)
2635         return Qt;
2636       else
2637         return Qnil;
2638     }
2639   return Qunbound;
2640 }
2641
2642 /* instantiate a progress gauge */
2643 static void
2644 x_progress_gauge_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2645                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2646                         int dest_mask, Lisp_Object domain)
2647 {
2648   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2649   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2650   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 0);
2651
2652   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2653                         pointer_bg, dest_mask, domain, "progress", wv);
2654 }
2655
2656 /* set the properties of a progress gauge */
2657 static void
2658 x_progress_gauge_redisplay (Lisp_Object image_instance)
2659 {
2660   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2661
2662   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
2663     {
2664       Arg al [1];
2665       Lisp_Object val;
2666 #ifdef ERROR_CHECK_GLYPHS
2667       assert (GUI_ITEMP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)));
2668 #endif
2669       val = XGUI_ITEM (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))->value;
2670       XtSetArg (al[0], XtNvalue, XINT (val));
2671       XtSetValues (IMAGE_INSTANCE_X_WIDGET_ID (ii), al, 1);
2672     }
2673 }
2674
2675 /* instantiate an edit control */
2676 static void
2677 x_edit_field_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2678                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2679                     int dest_mask, Lisp_Object domain)
2680 {
2681   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2682   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2683   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 0);
2684
2685   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2686                         pointer_bg, dest_mask, domain, "text-field", wv);
2687 }
2688
2689 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2690 /* instantiate a combo control */
2691 static void
2692 x_combo_box_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2693                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2694                      int dest_mask, Lisp_Object domain)
2695 {
2696   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2697   widget_value * wv = 0;
2698   /* This is not done generically because of sizing problems under
2699      mswindows. */
2700   widget_instantiate (image_instance, instantiator, pointer_fg,
2701                       pointer_bg, dest_mask, domain);
2702
2703   wv = gui_items_to_widget_values (image_instance,
2704                                    IMAGE_INSTANCE_WIDGET_ITEMS (ii), 0);
2705
2706   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2707                         pointer_bg, dest_mask, domain, "combo-box", wv);
2708 }
2709 #endif
2710
2711 static void
2712 x_tab_control_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2713                            Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2714                            int dest_mask, Lisp_Object domain)
2715 {
2716   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2717   widget_value * wv =
2718     gui_items_to_widget_values (image_instance,
2719                                 IMAGE_INSTANCE_WIDGET_ITEMS (ii), 0);
2720   update_tab_widget_face (wv, ii,
2721                           IMAGE_INSTANCE_FRAME (ii));
2722   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2723                         pointer_bg, dest_mask, domain, "tab-control", wv);
2724 }
2725
2726 /* Set the properties of a tab control */
2727 static void
2728 x_tab_control_redisplay (Lisp_Object image_instance)
2729 {
2730   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2731
2732   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii)
2733       ||
2734       IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED (ii))
2735     {
2736       /* If only the order has changed then simply select the first
2737          one of the pending set. This stops horrendous rebuilding -
2738          and hence flicker - of the tabs each time you click on
2739          one. */
2740       if (tab_control_order_only_changed (image_instance))
2741         {
2742           Lisp_Object rest, selected =
2743             gui_item_list_find_selected
2744             (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)) ?
2745              XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)) :
2746              XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)));
2747
2748           LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
2749             {
2750               if (gui_item_equal_sans_selected (XCAR (rest), selected, 0))
2751                 {
2752                   /* There may be an encapsulated way of doing this,
2753                      but I couldn't find it. */
2754                   Lisp_Object old_selected =gui_item_list_find_selected
2755                     (XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)));
2756                   Arg al [1];
2757                   char* name;
2758                   unsigned int num_children, i;
2759                   Widget* children;
2760
2761                   LISP_STRING_TO_EXTERNAL (XGUI_ITEM (XCAR (rest))->name,
2762                                            name, Qnative);
2763                   /* The name may contain a `.' which confuses
2764                      XtNameToWidget, so we do it ourselves. */
2765                   children = XtCompositeChildren (IMAGE_INSTANCE_X_WIDGET_ID (ii),
2766                                                   &num_children);
2767                   for (i = 0; i < num_children; i++)
2768                     {
2769                       if (!strcmp (XtName (children [i]), name))
2770                         {
2771                           XtSetArg (al [0], XtNtopWidget, children [i]);
2772                           XtSetValues (IMAGE_INSTANCE_X_WIDGET_ID (ii), al, 1);
2773                           break;
2774                         }
2775                     }
2776                   /* Pick up the new selected item. */
2777                   XGUI_ITEM (old_selected)->selected =
2778                     XGUI_ITEM (XCAR (rest))->selected;
2779                   XGUI_ITEM (XCAR (rest))->selected =
2780                     XGUI_ITEM (selected)->selected;
2781                   /* We're not actually changing the items anymore. */
2782                   IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 0;
2783                   IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
2784                   break;
2785                 }
2786             }
2787         }
2788     }
2789   /* Possibly update the face. */
2790   if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (ii)
2791       ||
2792       XFRAME (IMAGE_INSTANCE_FRAME (ii))->faces_changed
2793       ||
2794       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
2795     {
2796       /* See previous comments on the brokeness of lwlib.
2797
2798          #### There's actually not much point in doing this here
2799          since, colors will have been set appropriately by
2800          x_redisplay_widget. */
2801       widget_value* wv =copy_widget_value_tree
2802         (lw_get_all_values
2803          (IMAGE_INSTANCE_X_WIDGET_LWID (ii)),
2804          NO_CHANGE);
2805
2806       update_tab_widget_face (wv, ii,
2807                               IMAGE_INSTANCE_FRAME (ii));
2808
2809       lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (ii), wv, True);
2810       free_widget_value_tree (wv);
2811     }
2812 }
2813
2814 /* instantiate a static control possible for putting other things in */
2815 static void
2816 x_label_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2817                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2818                      int dest_mask, Lisp_Object domain)
2819 {
2820   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2821   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2822   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 0);
2823
2824   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2825                         pointer_bg, dest_mask, domain, "button", wv);
2826 }
2827 #endif /* HAVE_WIDGETS */
2828
2829 \f
2830 /************************************************************************/
2831 /*                            initialization                            */
2832 /************************************************************************/
2833
2834 void
2835 syms_of_glyphs_x (void)
2836 {
2837 #if 0
2838   DEFSUBR (Fchange_subwindow_property);
2839 #endif
2840 }
2841
2842 void
2843 console_type_create_glyphs_x (void)
2844 {
2845   /* image methods */
2846
2847   CONSOLE_HAS_METHOD (x, print_image_instance);
2848   CONSOLE_HAS_METHOD (x, finalize_image_instance);
2849   CONSOLE_HAS_METHOD (x, image_instance_equal);
2850   CONSOLE_HAS_METHOD (x, image_instance_hash);
2851   CONSOLE_HAS_METHOD (x, colorize_image_instance);
2852   CONSOLE_HAS_METHOD (x, init_image_instance_from_eimage);
2853   CONSOLE_HAS_METHOD (x, locate_pixmap_file);
2854   CONSOLE_HAS_METHOD (x, unmap_subwindow);
2855   CONSOLE_HAS_METHOD (x, map_subwindow);
2856   CONSOLE_HAS_METHOD (x, redisplay_widget);
2857   CONSOLE_HAS_METHOD (x, redisplay_subwindow);
2858 }
2859
2860 void
2861 image_instantiator_format_create_glyphs_x (void)
2862 {
2863   IIFORMAT_VALID_CONSOLE (x, nothing);
2864   IIFORMAT_VALID_CONSOLE (x, string);
2865 #ifdef HAVE_WIDGETS
2866   IIFORMAT_VALID_CONSOLE (x, layout);
2867 #endif
2868   IIFORMAT_VALID_CONSOLE (x, formatted_string);
2869   IIFORMAT_VALID_CONSOLE (x, inherit);
2870 #ifdef HAVE_XPM
2871   INITIALIZE_DEVICE_IIFORMAT (x, xpm);
2872   IIFORMAT_HAS_DEVMETHOD (x, xpm, instantiate);
2873 #endif
2874 #ifdef HAVE_JPEG
2875   IIFORMAT_VALID_CONSOLE (x, jpeg);
2876 #endif
2877 #ifdef HAVE_TIFF
2878   IIFORMAT_VALID_CONSOLE (x, tiff);
2879 #endif
2880 #ifdef HAVE_PNG
2881   IIFORMAT_VALID_CONSOLE (x, png);
2882 #endif
2883 #ifdef HAVE_GIF
2884   IIFORMAT_VALID_CONSOLE (x, gif);
2885 #endif
2886   INITIALIZE_DEVICE_IIFORMAT (x, xbm);
2887   IIFORMAT_HAS_DEVMETHOD (x, xbm, instantiate);
2888
2889   INITIALIZE_DEVICE_IIFORMAT (x, subwindow);
2890   IIFORMAT_HAS_DEVMETHOD (x, subwindow, instantiate);
2891 #ifdef HAVE_WIDGETS
2892   /* layout widget */
2893   INITIALIZE_DEVICE_IIFORMAT (x, native_layout);
2894   IIFORMAT_HAS_DEVMETHOD (x, native_layout, instantiate);
2895   /* button widget */
2896   INITIALIZE_DEVICE_IIFORMAT (x, button);
2897   IIFORMAT_HAS_DEVMETHOD (x, button, property);
2898   IIFORMAT_HAS_DEVMETHOD (x, button, instantiate);
2899   IIFORMAT_HAS_DEVMETHOD (x, button, redisplay);
2900   /* general widget methods. */
2901   INITIALIZE_DEVICE_IIFORMAT (x, widget);
2902   IIFORMAT_HAS_DEVMETHOD (x, widget, property);
2903   /* progress gauge */
2904   INITIALIZE_DEVICE_IIFORMAT (x, progress_gauge);
2905   IIFORMAT_HAS_DEVMETHOD (x, progress_gauge, redisplay);
2906   IIFORMAT_HAS_DEVMETHOD (x, progress_gauge, instantiate);
2907   /* text field */
2908   INITIALIZE_DEVICE_IIFORMAT (x, edit_field);
2909   IIFORMAT_HAS_DEVMETHOD (x, edit_field, instantiate);
2910 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2911   /* combo box */
2912   INITIALIZE_DEVICE_IIFORMAT (x, combo_box);
2913   IIFORMAT_HAS_DEVMETHOD (x, combo_box, instantiate);
2914   IIFORMAT_HAS_SHARED_DEVMETHOD (x, combo_box, redisplay, tab_control);
2915 #endif
2916   /* tab control widget */
2917   INITIALIZE_DEVICE_IIFORMAT (x, tab_control);
2918   IIFORMAT_HAS_DEVMETHOD (x, tab_control, instantiate);
2919   IIFORMAT_HAS_DEVMETHOD (x, tab_control, redisplay);
2920   /* label */
2921   INITIALIZE_DEVICE_IIFORMAT (x, label);
2922   IIFORMAT_HAS_DEVMETHOD (x, label, instantiate);
2923 #endif
2924   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (cursor_font, "cursor-font");
2925   IIFORMAT_VALID_CONSOLE (x, cursor_font);
2926
2927   IIFORMAT_HAS_METHOD (cursor_font, validate);
2928   IIFORMAT_HAS_METHOD (cursor_font, possible_dest_types);
2929   IIFORMAT_HAS_METHOD (cursor_font, instantiate);
2930
2931   IIFORMAT_VALID_KEYWORD (cursor_font, Q_data, check_valid_string);
2932   IIFORMAT_VALID_KEYWORD (cursor_font, Q_foreground, check_valid_string);
2933   IIFORMAT_VALID_KEYWORD (cursor_font, Q_background, check_valid_string);
2934
2935   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (font, "font");
2936
2937   IIFORMAT_HAS_METHOD (font, validate);
2938   IIFORMAT_HAS_METHOD (font, possible_dest_types);
2939   IIFORMAT_HAS_METHOD (font, instantiate);
2940   IIFORMAT_VALID_CONSOLE (x, font);
2941
2942   IIFORMAT_VALID_KEYWORD (font, Q_data, check_valid_string);
2943   IIFORMAT_VALID_KEYWORD (font, Q_foreground, check_valid_string);
2944   IIFORMAT_VALID_KEYWORD (font, Q_background, check_valid_string);
2945
2946 #ifdef HAVE_XFACE
2947   INITIALIZE_DEVICE_IIFORMAT (x, xface);
2948   IIFORMAT_HAS_DEVMETHOD (x, xface, instantiate);
2949 #endif
2950
2951   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (autodetect,
2952                                         "autodetect");
2953
2954   IIFORMAT_HAS_METHOD (autodetect, validate);
2955   IIFORMAT_HAS_METHOD (autodetect, normalize);
2956   IIFORMAT_HAS_METHOD (autodetect, possible_dest_types);
2957   /* #### autodetect is flawed IMO: 
2958   1. It makes the assumption that you can detect whether the user
2959   wanted a cursor or a string based on the data, since the data is a
2960   string you have to prioritise cursors. Instead we will force users
2961   to pick the appropriate image type, this is what we do under
2962   MS-Windows anyway.
2963   2. It doesn't fit with the new domain model - you cannot tell which
2964   domain it needs to be instantiated in until you've actually
2965   instantiated it, which mucks up caching.
2966   3. It only copes with cursors and strings which seems bogus. */
2967   IIFORMAT_HAS_SHARED_METHOD (autodetect, governing_domain, subwindow);
2968   IIFORMAT_HAS_METHOD (autodetect, instantiate);
2969   IIFORMAT_VALID_CONSOLE (x, autodetect);
2970
2971   IIFORMAT_VALID_KEYWORD (autodetect, Q_data, check_valid_string);
2972 }
2973
2974 void
2975 vars_of_glyphs_x (void)
2976 {
2977   DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path /*
2978 A list of the directories in which X bitmap files may be found.
2979 If nil, this is initialized from the "*bitmapFilePath" resource.
2980 This is used by the `make-image-instance' function (however, note that if
2981 the environment variable XBMLANGPATH is set, it is consulted first).
2982 */ );
2983   Vx_bitmap_file_path = Qnil;
2984 }
2985
2986 void
2987 complex_vars_of_glyphs_x (void)
2988 {
2989 #define BUILD_GLYPH_INST(variable, name)                        \
2990   Fadd_spec_to_specifier                                        \
2991     (GLYPH_IMAGE (XGLYPH (variable)),                           \
2992      vector3 (Qxbm, Q_data,                                     \
2993               list3 (make_int (name##_width),                   \
2994                      make_int (name##_height),                  \
2995                      make_ext_string ((Extbyte *) name##_bits,  \
2996                                       sizeof (name##_bits),     \
2997                                       Qbinary))),               \
2998      Qglobal, Qx, Qnil)
2999
3000   BUILD_GLYPH_INST (Vtruncation_glyph, truncator);
3001   BUILD_GLYPH_INST (Vcontinuation_glyph, continuer);
3002   BUILD_GLYPH_INST (Vxemacs_logo, xemacs);
3003   BUILD_GLYPH_INST (Vhscroll_glyph, hscroll);
3004
3005 #undef BUILD_GLYPH_INST
3006 }