e0fa2d29abf6d0edb78da2cb4fc4801a2c242b23
[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   assert (dga->width > 0 && dga->height > 0);
2144   if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
2145     {
2146       Window subwindow = IMAGE_INSTANCE_X_SUBWINDOW_ID (p);
2147       XMoveResizeWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2148                          IMAGE_INSTANCE_X_CLIPWINDOW (p),
2149                          x, y, dga->width, dga->height);
2150       XMoveWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2151                    subwindow, -dga->xoffset, -dga->yoffset);
2152       if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (p))
2153         XMapWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2154                     IMAGE_INSTANCE_X_CLIPWINDOW (p));
2155     }
2156   else                          /* must be a widget */
2157     {
2158       XtConfigureWidget (IMAGE_INSTANCE_X_CLIPWIDGET (p),
2159                          x + IMAGE_INSTANCE_X_WIDGET_XOFFSET (p),
2160                          y + IMAGE_INSTANCE_X_WIDGET_YOFFSET (p),
2161                          dga->width, dga->height, 0);
2162       XtMoveWidget (IMAGE_INSTANCE_X_WIDGET_ID (p),
2163                     -dga->xoffset, -dga->yoffset);
2164       if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (p))
2165         XtMapWidget (IMAGE_INSTANCE_X_CLIPWIDGET (p));
2166     }
2167 }
2168
2169 /* when you click on a widget you may activate another widget this
2170    needs to be checked and all appropriate widgets updated */
2171 static void
2172 x_redisplay_subwindow (Lisp_Image_Instance *p)
2173 {
2174   /* Update the subwindow size if necessary. */
2175   if (IMAGE_INSTANCE_SIZE_CHANGED (p))
2176     {
2177       XResizeWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2178                      IMAGE_INSTANCE_X_SUBWINDOW_ID (p),
2179                      IMAGE_INSTANCE_WIDTH (p),
2180                      IMAGE_INSTANCE_HEIGHT (p));
2181     }
2182 }
2183
2184 /* Update all attributes that have changed. Lwlib actually does most
2185    of this for us. */
2186 static void
2187 x_redisplay_widget (Lisp_Image_Instance *p)
2188 {
2189   /* This function can GC if IN_REDISPLAY is false. */
2190 #ifdef HAVE_WIDGETS
2191   widget_value* wv = 0;
2192
2193   /* First get the items if they have changed since this is a
2194      structural change. As such it will nuke all added values so we
2195      need to update most other things after the items have changed.*/
2196   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
2197     {
2198       Lisp_Object image_instance;
2199
2200       XSETIMAGE_INSTANCE (image_instance, p);
2201       wv = gui_items_to_widget_values
2202         (image_instance, IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (p),
2203          /* #### this is not right; we need to keep track of which widgets
2204             want accelerators and which don't */ 0);
2205       wv->change = STRUCTURAL_CHANGE;
2206     }
2207   else
2208     {
2209       /* Assume the lotus position, breath deeply and chant to
2210          yourself lwlibsux, lwlibsux ... lw_get_all_values returns a
2211          reference to the real values rather than a copy thus any
2212          changes we make to the values we get back will look like they
2213          have already been applied. If we rebuild the widget tree then
2214          we may lose properties. */
2215       wv = copy_widget_value_tree (lw_get_all_values 
2216                                    (IMAGE_INSTANCE_X_WIDGET_LWID (p)),
2217                                    NO_CHANGE);
2218     }
2219
2220   /* Possibly update the colors and font */
2221   if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p)
2222       ||
2223       XFRAME (IMAGE_INSTANCE_FRAME (p))->faces_changed
2224       ||
2225       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
2226     {
2227       update_widget_face (wv, p, IMAGE_INSTANCE_FRAME (p));
2228     }
2229
2230   /* Possibly update the text. */
2231   if (IMAGE_INSTANCE_TEXT_CHANGED (p))
2232     {
2233       char* str;
2234       Lisp_Object val = IMAGE_INSTANCE_WIDGET_TEXT (p);
2235       LISP_STRING_TO_EXTERNAL (val, str, Qnative);
2236       wv->value = str;
2237     }
2238
2239   /* Possibly update the size. */
2240   if (IMAGE_INSTANCE_SIZE_CHANGED (p)
2241       ||
2242       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p)
2243       ||
2244       IMAGE_INSTANCE_TEXT_CHANGED (p))
2245     {
2246       assert (IMAGE_INSTANCE_X_WIDGET_ID (p) &&
2247               IMAGE_INSTANCE_X_CLIPWIDGET (p)) ;
2248
2249       if (IMAGE_INSTANCE_X_WIDGET_ID (p)->core.being_destroyed
2250           || !XtIsManaged(IMAGE_INSTANCE_X_WIDGET_ID (p)))
2251         {
2252           Lisp_Object sw;
2253           XSETIMAGE_INSTANCE (sw, p);
2254           signal_simple_error ("XEmacs bug: subwindow is deleted", sw);
2255         }
2256
2257       lw_add_widget_value_arg (wv, XtNwidth,
2258                                (Dimension)IMAGE_INSTANCE_WIDTH (p));
2259       lw_add_widget_value_arg (wv, XtNheight,
2260                                (Dimension)IMAGE_INSTANCE_HEIGHT (p));
2261     }
2262
2263   /* Adjust offsets within the frame. */
2264   if (XFRAME (IMAGE_INSTANCE_FRAME (p))->frame_changed)
2265     {
2266       Arg al[2];
2267       XtSetArg (al [0], XtNx, &IMAGE_INSTANCE_X_WIDGET_XOFFSET (p));
2268       XtSetArg (al [1], XtNy, &IMAGE_INSTANCE_X_WIDGET_YOFFSET (p));
2269       XtGetValues (FRAME_X_TEXT_WIDGET 
2270                    (XFRAME (IMAGE_INSTANCE_FRAME (p))), al, 2);
2271     }
2272
2273   /* now modify the widget */
2274   lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (p),
2275                          wv, True);
2276   free_widget_value_tree (wv);
2277 #endif
2278 }
2279
2280 /* instantiate and x type subwindow */
2281 static void
2282 x_subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2283                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2284                         int dest_mask, Lisp_Object domain)
2285 {
2286   /* This function can GC */
2287   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2288   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
2289   Lisp_Object frame = DOMAIN_FRAME (domain);
2290   struct frame* f = XFRAME (frame);
2291   Display *dpy;
2292   Screen *xs;
2293   Window pw, win;
2294   XSetWindowAttributes xswa;
2295   Mask valueMask = 0;
2296   unsigned int w = IMAGE_INSTANCE_WIDTH (ii),
2297     h = IMAGE_INSTANCE_HEIGHT (ii);
2298
2299   if (!DEVICE_X_P (XDEVICE (device)))
2300     signal_simple_error ("Not an X device", device);
2301
2302   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
2303   xs = DefaultScreenOfDisplay (dpy);
2304
2305   IMAGE_INSTANCE_TYPE (ii) = IMAGE_SUBWINDOW;
2306
2307   pw = XtWindow (FRAME_X_TEXT_WIDGET (f));
2308
2309   ii->data = xnew_and_zero (struct x_subwindow_data);
2310
2311   IMAGE_INSTANCE_X_SUBWINDOW_PARENT (ii) = pw;
2312   IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (ii) = DisplayOfScreen (xs);
2313
2314   xswa.backing_store = Always;
2315   valueMask |= CWBackingStore;
2316   xswa.colormap = DefaultColormapOfScreen (xs);
2317   valueMask |= CWColormap;
2318
2319   /* Create a window for clipping */
2320   IMAGE_INSTANCE_X_CLIPWINDOW (ii) =
2321     XCreateWindow (dpy, pw, 0, 0, w, h, 0, CopyFromParent,
2322                    InputOutput, CopyFromParent, valueMask,
2323                    &xswa);
2324
2325   /* Now put the subwindow inside the clip window. */
2326   win = XCreateWindow (dpy, IMAGE_INSTANCE_X_CLIPWINDOW (ii),
2327                        0, 0, w, h, 0, CopyFromParent,
2328                        InputOutput, CopyFromParent, valueMask,
2329                        &xswa);
2330
2331   IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void*)win;
2332 }
2333
2334 #if 0
2335 /* #### Should this function exist? If there's any doubt I'm not implementing it --andyp */
2336 DEFUN ("change-subwindow-property", Fchange_subwindow_property, 3, 3, 0, /*
2337 For the given SUBWINDOW, set PROPERTY to DATA, which is a string.
2338 Subwindows are not currently implemented.
2339 */
2340        (subwindow, property, data))
2341 {
2342   Atom property_atom;
2343   Lisp_Subwindow *sw;
2344   Display *dpy;
2345
2346   CHECK_SUBWINDOW (subwindow);
2347   CHECK_STRING (property);
2348   CHECK_STRING (data);
2349
2350   sw = XSUBWINDOW (subwindow);
2351   dpy = DisplayOfScreen (LISP_DEVICE_TO_X_SCREEN
2352                          (FRAME_DEVICE (XFRAME (sw->frame))));
2353
2354   property_atom = XInternAtom (dpy, (char *) XSTRING_DATA (property), False);
2355   XChangeProperty (dpy, sw->subwindow, property_atom, XA_STRING, 8,
2356                    PropModeReplace,
2357                    XSTRING_DATA   (data),
2358                    XSTRING_LENGTH (data));
2359
2360   return property;
2361 }
2362 #endif
2363
2364 \f
2365 #ifdef HAVE_WIDGETS
2366
2367 /************************************************************************/
2368 /*                            widgets                            */
2369 /************************************************************************/
2370
2371 static void
2372 update_widget_face (widget_value* wv, Lisp_Image_Instance *ii,
2373                     Lisp_Object domain)
2374 {
2375 #ifdef LWLIB_WIDGETS_MOTIF
2376   XmFontList fontList;
2377 #endif
2378   /* Update the foreground. */
2379   Lisp_Object pixel = FACE_FOREGROUND
2380     (IMAGE_INSTANCE_WIDGET_FACE (ii),
2381      domain);
2382   XColor fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel)), bcolor;
2383   lw_add_widget_value_arg (wv, XtNforeground, fcolor.pixel);
2384
2385   /* Update the background. */
2386   pixel = FACE_BACKGROUND (IMAGE_INSTANCE_WIDGET_FACE (ii),
2387                            domain);
2388   bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2389   lw_add_widget_value_arg (wv, XtNbackground, bcolor.pixel);
2390
2391 #ifdef LWLIB_WIDGETS_MOTIF
2392   fontList = XmFontListCreate
2393     (FONT_INSTANCE_X_FONT
2394      (XFONT_INSTANCE (query_string_font
2395                       (IMAGE_INSTANCE_WIDGET_TEXT (ii),
2396                        IMAGE_INSTANCE_WIDGET_FACE (ii),
2397                        domain))),  XmSTRING_DEFAULT_CHARSET);
2398   lw_add_widget_value_arg (wv, XmNfontList, (XtArgVal)fontList);
2399 #endif
2400   lw_add_widget_value_arg
2401     (wv, XtNfont, (XtArgVal)FONT_INSTANCE_X_FONT
2402      (XFONT_INSTANCE (query_string_font
2403                       (IMAGE_INSTANCE_WIDGET_TEXT (ii),
2404                        IMAGE_INSTANCE_WIDGET_FACE (ii),
2405                        domain))));
2406   wv->change = VISIBLE_CHANGE;
2407   /* #### Megahack - but its just getting too complicated to do this
2408      in the right place. */
2409   if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qtab_control))
2410     update_tab_widget_face (wv, ii, domain);
2411 }
2412
2413 static void
2414 update_tab_widget_face (widget_value* wv, Lisp_Image_Instance *ii,
2415                         Lisp_Object domain)
2416 {
2417   if (wv->contents)
2418     {
2419       widget_value* val = wv->contents, *cur;
2420
2421       /* Give each child label the correct foreground color. */
2422       Lisp_Object pixel = FACE_FOREGROUND
2423         (IMAGE_INSTANCE_WIDGET_FACE (ii),
2424          domain);
2425       XColor fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2426       lw_add_widget_value_arg (val, XtNtabForeground, fcolor.pixel);
2427       wv->change = VISIBLE_CHANGE;
2428       val->change = VISIBLE_CHANGE;
2429
2430       for (cur = val->next; cur; cur = cur->next)
2431         {
2432           cur->change = VISIBLE_CHANGE;
2433           if (cur->value)
2434             {
2435               lw_copy_widget_value_args (val, cur);
2436             }
2437         }
2438     }
2439 }
2440
2441 static void
2442 x_widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2443                       Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2444                       int dest_mask, Lisp_Object domain,
2445                       const char* type, widget_value* wv)
2446 {
2447   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2448   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii), pixel;
2449   struct device* d = XDEVICE (device);
2450   Lisp_Object frame = DOMAIN_FRAME (domain);
2451   struct frame* f = XFRAME (frame);
2452   char* nm=0;
2453   Widget wid;
2454   Arg al [32];
2455   int ac = 0;
2456   int id = new_lwlib_id ();
2457   widget_value* clip_wv;
2458   XColor fcolor, bcolor;
2459
2460   if (!DEVICE_X_P (d))
2461     signal_simple_error ("Not an X device", device);
2462
2463   /* have to set the type this late in case there is no device
2464      instantiation for a widget. But we can go ahead and do it without
2465      checking because there is always a generic instantiator. */
2466   IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
2467
2468   if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
2469     LISP_STRING_TO_EXTERNAL (IMAGE_INSTANCE_WIDGET_TEXT (ii), nm, Qnative);
2470
2471   ii->data = xnew_and_zero (struct x_subwindow_data);
2472
2473   /* Create a clip window to contain the subwidget. Incredibly the
2474      XEmacs manager seems to be the most appropriate widget for
2475      this. Nothing else is simple enough and yet does what is
2476      required. */
2477   clip_wv = xmalloc_widget_value ();
2478
2479   lw_add_widget_value_arg (clip_wv, XtNresize, False);
2480   lw_add_widget_value_arg (clip_wv, XtNwidth,
2481                            (Dimension)IMAGE_INSTANCE_WIDTH (ii));
2482   lw_add_widget_value_arg (clip_wv, XtNheight,
2483                            (Dimension)IMAGE_INSTANCE_HEIGHT (ii));
2484   clip_wv->enabled = True;
2485
2486   clip_wv->name = xstrdup ("clip-window");
2487   clip_wv->value = xstrdup ("clip-window");
2488
2489   IMAGE_INSTANCE_X_CLIPWIDGET (ii)
2490     = lw_create_widget ("clip-window", "clip-window", new_lwlib_id (),
2491                         clip_wv, FRAME_X_CONTAINER_WIDGET (f),
2492                         False, 0, 0, 0);
2493
2494   free_widget_value_tree (clip_wv);
2495
2496   /* copy any args we were given */
2497   ac = 0;
2498   lw_add_value_args_to_args (wv, al, &ac);
2499
2500   /* Fixup the colors. We have to do this *before* the widget gets
2501      created so that Motif will fix up the shadow colors
2502      correctly. Once the widget is created Motif won't do this
2503      anymore...*/
2504   pixel = FACE_FOREGROUND
2505     (IMAGE_INSTANCE_WIDGET_FACE (ii),
2506      IMAGE_INSTANCE_FRAME (ii));
2507   fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2508
2509   pixel = FACE_BACKGROUND
2510     (IMAGE_INSTANCE_WIDGET_FACE (ii),
2511      IMAGE_INSTANCE_FRAME (ii));
2512   bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2513
2514   lw_add_widget_value_arg (wv, XtNbackground, bcolor.pixel);
2515   lw_add_widget_value_arg (wv, XtNforeground, fcolor.pixel);
2516   /* we cannot allow widgets to resize themselves */
2517   lw_add_widget_value_arg (wv, XtNresize, False);
2518   lw_add_widget_value_arg (wv, XtNwidth,
2519                            (Dimension)IMAGE_INSTANCE_WIDTH (ii));
2520   lw_add_widget_value_arg (wv, XtNheight,
2521                            (Dimension)IMAGE_INSTANCE_HEIGHT (ii));
2522   /* update the font. */
2523   update_widget_face (wv, ii, domain);
2524
2525   wid = lw_create_widget (type, wv->name, id, wv, IMAGE_INSTANCE_X_CLIPWIDGET (ii),
2526                           False, 0, popup_selection_callback, 0);
2527
2528   IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void*)wid;
2529   IMAGE_INSTANCE_X_WIDGET_LWID (ii) = id;
2530   /* because the EmacsManager is the widgets parent we have to
2531      offset the redisplay of the widget by the amount the text
2532      widget is inside the manager. */
2533   ac = 0;
2534   XtSetArg (al [ac], XtNx, &IMAGE_INSTANCE_X_WIDGET_XOFFSET (ii)); ac++;
2535   XtSetArg (al [ac], XtNy, &IMAGE_INSTANCE_X_WIDGET_YOFFSET (ii)); ac++;
2536   XtGetValues (FRAME_X_TEXT_WIDGET (f), al, ac);
2537
2538   XtSetMappedWhenManaged (wid, TRUE);
2539
2540   free_widget_value_tree (wv);
2541   /* A kludgy but simple way to make sure the callback for a widget
2542      doesn't get deleted. */
2543   gcpro_popup_callbacks (id);
2544 }
2545
2546 /* get properties of a control */
2547 static Lisp_Object
2548 x_widget_property (Lisp_Object image_instance, Lisp_Object prop)
2549 {
2550   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2551   /* get the text from a control */
2552   if (EQ (prop, Q_text))
2553     {
2554       widget_value* wv = lw_get_all_values (IMAGE_INSTANCE_X_WIDGET_LWID (ii));
2555       return build_ext_string (wv->value, Qnative);
2556     }
2557   return Qunbound;
2558 }
2559
2560 /* Instantiate a layout control for putting other widgets in. */
2561 static void
2562 x_native_layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2563                              Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2564                              int dest_mask, Lisp_Object domain)
2565 {
2566   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2567                         pointer_bg, dest_mask, domain, "layout", 0);
2568 }
2569
2570 /* Instantiate a button widget. Unfortunately instantiated widgets are
2571    particular to a frame since they need to have a parent. It's not
2572    like images where you just select the image into the context you
2573    want to display it in and BitBlt it. So images instances can have a
2574    many-to-one relationship with things you see, whereas widgets can
2575    only be one-to-one (i.e. per frame) */
2576 static void
2577 x_button_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2578                       Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2579                       int dest_mask, Lisp_Object domain)
2580 {
2581   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2582   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2583   Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
2584   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 1);
2585
2586   if (!NILP (glyph))
2587     {
2588       if (!IMAGE_INSTANCEP (glyph))
2589         glyph = glyph_image_instance (glyph, domain, ERROR_ME, 1);
2590     }
2591
2592   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2593                         pointer_bg, dest_mask, domain, "button", wv);
2594
2595   /* add the image if one was given */
2596   if (!NILP (glyph) && IMAGE_INSTANCEP (glyph)
2597       && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (glyph)))
2598     {
2599       Arg al [2];
2600       int ac =0;
2601 #ifdef LWLIB_WIDGETS_MOTIF
2602       XtSetArg (al [ac], XmNlabelType, XmPIXMAP);       ac++;
2603       XtSetArg (al [ac], XmNlabelPixmap, XIMAGE_INSTANCE_X_PIXMAP (glyph));ac++;
2604 #else
2605       XtSetArg (al [ac], XtNpixmap, XIMAGE_INSTANCE_X_PIXMAP (glyph));  ac++;
2606 #endif
2607       XtSetValues (IMAGE_INSTANCE_X_WIDGET_ID (ii), al, ac);
2608     }
2609 }
2610
2611 /* Update a button's clicked state.
2612
2613    #### This is overkill, but it works. Right now this causes all
2614    button instances to flash for some reason buried deep in lwlib. In
2615    theory this should be the Right Thing to do since lwlib should only
2616    merge in changed values - and if nothing has changed then nothing
2617    should get done. This may be because of the args stuff,
2618    i.e. although the arg contents may be the same the args look
2619    different and so are re-applied to the widget. */
2620 static void
2621 x_button_redisplay (Lisp_Object image_instance)
2622 {
2623   /* This function can GC if IN_REDISPLAY is false. */
2624   Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
2625   widget_value* wv =
2626     gui_items_to_widget_values (image_instance,
2627                                 IMAGE_INSTANCE_WIDGET_ITEMS (p), 1);
2628
2629   /* now modify the widget */
2630   lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (p),
2631                          wv, True);
2632   free_widget_value_tree (wv);
2633 }
2634
2635 /* get properties of a button */
2636 static Lisp_Object
2637 x_button_property (Lisp_Object image_instance, Lisp_Object prop)
2638 {
2639   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2640   /* check the state of a button */
2641   if (EQ (prop, Q_selected))
2642     {
2643       widget_value* wv = lw_get_all_values (IMAGE_INSTANCE_X_WIDGET_LWID (ii));
2644
2645       if (wv->selected)
2646         return Qt;
2647       else
2648         return Qnil;
2649     }
2650   return Qunbound;
2651 }
2652
2653 /* instantiate a progress gauge */
2654 static void
2655 x_progress_gauge_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2656                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2657                         int dest_mask, Lisp_Object domain)
2658 {
2659   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2660   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2661   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 0);
2662
2663   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2664                         pointer_bg, dest_mask, domain, "progress", wv);
2665 }
2666
2667 /* set the properties of a progress gauge */
2668 static void
2669 x_progress_gauge_redisplay (Lisp_Object image_instance)
2670 {
2671   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2672
2673   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
2674     {
2675       Arg al [1];
2676       Lisp_Object val;
2677 #ifdef ERROR_CHECK_GLYPHS
2678       assert (GUI_ITEMP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)));
2679 #endif
2680       val = XGUI_ITEM (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))->value;
2681       XtSetArg (al[0], XtNvalue, XINT (val));
2682       XtSetValues (IMAGE_INSTANCE_X_WIDGET_ID (ii), al, 1);
2683     }
2684 }
2685
2686 /* instantiate an edit control */
2687 static void
2688 x_edit_field_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2689                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2690                     int dest_mask, Lisp_Object domain)
2691 {
2692   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2693   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2694   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 0);
2695
2696   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2697                         pointer_bg, dest_mask, domain, "text-field", wv);
2698 }
2699
2700 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2701 /* instantiate a combo control */
2702 static void
2703 x_combo_box_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2704                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2705                      int dest_mask, Lisp_Object domain)
2706 {
2707   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2708   widget_value * wv = 0;
2709   /* This is not done generically because of sizing problems under
2710      mswindows. */
2711   widget_instantiate (image_instance, instantiator, pointer_fg,
2712                       pointer_bg, dest_mask, domain);
2713
2714   wv = gui_items_to_widget_values (image_instance,
2715                                    IMAGE_INSTANCE_WIDGET_ITEMS (ii), 0);
2716
2717   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2718                         pointer_bg, dest_mask, domain, "combo-box", wv);
2719 }
2720 #endif
2721
2722 static void
2723 x_tab_control_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2724                            Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2725                            int dest_mask, Lisp_Object domain)
2726 {
2727   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2728   widget_value * wv =
2729     gui_items_to_widget_values (image_instance,
2730                                 IMAGE_INSTANCE_WIDGET_ITEMS (ii), 0);
2731   update_tab_widget_face (wv, ii,
2732                           IMAGE_INSTANCE_FRAME (ii));
2733   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2734                         pointer_bg, dest_mask, domain, "tab-control", wv);
2735 }
2736
2737 /* Set the properties of a tab control */
2738 static void
2739 x_tab_control_redisplay (Lisp_Object image_instance)
2740 {
2741   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2742
2743   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii)
2744       ||
2745       IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED (ii))
2746     {
2747       /* If only the order has changed then simply select the first
2748          one of the pending set. This stops horrendous rebuilding -
2749          and hence flicker - of the tabs each time you click on
2750          one. */
2751       if (tab_control_order_only_changed (image_instance))
2752         {
2753           Lisp_Object rest, selected =
2754             gui_item_list_find_selected
2755             (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)) ?
2756              XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)) :
2757              XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)));
2758
2759           LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
2760             {
2761               if (gui_item_equal_sans_selected (XCAR (rest), selected, 0))
2762                 {
2763                   /* There may be an encapsulated way of doing this,
2764                      but I couldn't find it. */
2765                   Lisp_Object old_selected =gui_item_list_find_selected
2766                     (XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)));
2767                   Arg al [1];
2768                   char* name;
2769                   unsigned int num_children, i;
2770                   Widget* children;
2771
2772                   LISP_STRING_TO_EXTERNAL (XGUI_ITEM (XCAR (rest))->name,
2773                                            name, Qnative);
2774                   /* The name may contain a `.' which confuses
2775                      XtNameToWidget, so we do it ourselves. */
2776                   children = XtCompositeChildren (IMAGE_INSTANCE_X_WIDGET_ID (ii),
2777                                                   &num_children);
2778                   for (i = 0; i < num_children; i++)
2779                     {
2780                       if (!strcmp (XtName (children [i]), name))
2781                         {
2782                           XtSetArg (al [0], XtNtopWidget, children [i]);
2783                           XtSetValues (IMAGE_INSTANCE_X_WIDGET_ID (ii), al, 1);
2784                           break;
2785                         }
2786                     }
2787                   /* Pick up the new selected item. */
2788                   XGUI_ITEM (old_selected)->selected =
2789                     XGUI_ITEM (XCAR (rest))->selected;
2790                   XGUI_ITEM (XCAR (rest))->selected =
2791                     XGUI_ITEM (selected)->selected;
2792                   /* We're not actually changing the items anymore. */
2793                   IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 0;
2794                   IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
2795                   break;
2796                 }
2797             }
2798         }
2799     }
2800   /* Possibly update the face. */
2801   if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (ii)
2802       ||
2803       XFRAME (IMAGE_INSTANCE_FRAME (ii))->faces_changed
2804       ||
2805       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
2806     {
2807       /* See previous comments on the brokeness of lwlib.
2808
2809          #### There's actually not much point in doing this here
2810          since, colors will have been set appropriately by
2811          x_redisplay_widget. */
2812       widget_value* wv =copy_widget_value_tree
2813         (lw_get_all_values
2814          (IMAGE_INSTANCE_X_WIDGET_LWID (ii)),
2815          NO_CHANGE);
2816
2817       update_tab_widget_face (wv, ii,
2818                               IMAGE_INSTANCE_FRAME (ii));
2819
2820       lw_modify_all_widgets (IMAGE_INSTANCE_X_WIDGET_LWID (ii), wv, True);
2821       free_widget_value_tree (wv);
2822     }
2823 }
2824
2825 /* instantiate a static control possible for putting other things in */
2826 static void
2827 x_label_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2828                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2829                      int dest_mask, Lisp_Object domain)
2830 {
2831   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2832   Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
2833   widget_value* wv = gui_items_to_widget_values (image_instance, gui, 0);
2834
2835   x_widget_instantiate (image_instance, instantiator, pointer_fg,
2836                         pointer_bg, dest_mask, domain, "button", wv);
2837 }
2838 #endif /* HAVE_WIDGETS */
2839
2840 \f
2841 /************************************************************************/
2842 /*                            initialization                            */
2843 /************************************************************************/
2844
2845 void
2846 syms_of_glyphs_x (void)
2847 {
2848 #if 0
2849   DEFSUBR (Fchange_subwindow_property);
2850 #endif
2851 }
2852
2853 void
2854 console_type_create_glyphs_x (void)
2855 {
2856   /* image methods */
2857
2858   CONSOLE_HAS_METHOD (x, print_image_instance);
2859   CONSOLE_HAS_METHOD (x, finalize_image_instance);
2860   CONSOLE_HAS_METHOD (x, image_instance_equal);
2861   CONSOLE_HAS_METHOD (x, image_instance_hash);
2862   CONSOLE_HAS_METHOD (x, colorize_image_instance);
2863   CONSOLE_HAS_METHOD (x, init_image_instance_from_eimage);
2864   CONSOLE_HAS_METHOD (x, locate_pixmap_file);
2865   CONSOLE_HAS_METHOD (x, unmap_subwindow);
2866   CONSOLE_HAS_METHOD (x, map_subwindow);
2867   CONSOLE_HAS_METHOD (x, redisplay_widget);
2868   CONSOLE_HAS_METHOD (x, redisplay_subwindow);
2869 }
2870
2871 void
2872 image_instantiator_format_create_glyphs_x (void)
2873 {
2874   IIFORMAT_VALID_CONSOLE (x, nothing);
2875   IIFORMAT_VALID_CONSOLE (x, string);
2876 #ifdef HAVE_WIDGETS
2877   IIFORMAT_VALID_CONSOLE (x, layout);
2878 #endif
2879   IIFORMAT_VALID_CONSOLE (x, formatted_string);
2880   IIFORMAT_VALID_CONSOLE (x, inherit);
2881 #ifdef HAVE_XPM
2882   INITIALIZE_DEVICE_IIFORMAT (x, xpm);
2883   IIFORMAT_HAS_DEVMETHOD (x, xpm, instantiate);
2884 #endif
2885 #ifdef HAVE_JPEG
2886   IIFORMAT_VALID_CONSOLE (x, jpeg);
2887 #endif
2888 #ifdef HAVE_TIFF
2889   IIFORMAT_VALID_CONSOLE (x, tiff);
2890 #endif
2891 #ifdef HAVE_PNG
2892   IIFORMAT_VALID_CONSOLE (x, png);
2893 #endif
2894 #ifdef HAVE_GIF
2895   IIFORMAT_VALID_CONSOLE (x, gif);
2896 #endif
2897   INITIALIZE_DEVICE_IIFORMAT (x, xbm);
2898   IIFORMAT_HAS_DEVMETHOD (x, xbm, instantiate);
2899
2900   INITIALIZE_DEVICE_IIFORMAT (x, subwindow);
2901   IIFORMAT_HAS_DEVMETHOD (x, subwindow, instantiate);
2902 #ifdef HAVE_WIDGETS
2903   /* layout widget */
2904   INITIALIZE_DEVICE_IIFORMAT (x, native_layout);
2905   IIFORMAT_HAS_DEVMETHOD (x, native_layout, instantiate);
2906   /* button widget */
2907   INITIALIZE_DEVICE_IIFORMAT (x, button);
2908   IIFORMAT_HAS_DEVMETHOD (x, button, property);
2909   IIFORMAT_HAS_DEVMETHOD (x, button, instantiate);
2910   IIFORMAT_HAS_DEVMETHOD (x, button, redisplay);
2911   /* general widget methods. */
2912   INITIALIZE_DEVICE_IIFORMAT (x, widget);
2913   IIFORMAT_HAS_DEVMETHOD (x, widget, property);
2914   /* progress gauge */
2915   INITIALIZE_DEVICE_IIFORMAT (x, progress_gauge);
2916   IIFORMAT_HAS_DEVMETHOD (x, progress_gauge, redisplay);
2917   IIFORMAT_HAS_DEVMETHOD (x, progress_gauge, instantiate);
2918   /* text field */
2919   INITIALIZE_DEVICE_IIFORMAT (x, edit_field);
2920   IIFORMAT_HAS_DEVMETHOD (x, edit_field, instantiate);
2921 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2922   /* combo box */
2923   INITIALIZE_DEVICE_IIFORMAT (x, combo_box);
2924   IIFORMAT_HAS_DEVMETHOD (x, combo_box, instantiate);
2925   IIFORMAT_HAS_SHARED_DEVMETHOD (x, combo_box, redisplay, tab_control);
2926 #endif
2927   /* tab control widget */
2928   INITIALIZE_DEVICE_IIFORMAT (x, tab_control);
2929   IIFORMAT_HAS_DEVMETHOD (x, tab_control, instantiate);
2930   IIFORMAT_HAS_DEVMETHOD (x, tab_control, redisplay);
2931   /* label */
2932   INITIALIZE_DEVICE_IIFORMAT (x, label);
2933   IIFORMAT_HAS_DEVMETHOD (x, label, instantiate);
2934 #endif
2935   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (cursor_font, "cursor-font");
2936   IIFORMAT_VALID_CONSOLE (x, cursor_font);
2937
2938   IIFORMAT_HAS_METHOD (cursor_font, validate);
2939   IIFORMAT_HAS_METHOD (cursor_font, possible_dest_types);
2940   IIFORMAT_HAS_METHOD (cursor_font, instantiate);
2941
2942   IIFORMAT_VALID_KEYWORD (cursor_font, Q_data, check_valid_string);
2943   IIFORMAT_VALID_KEYWORD (cursor_font, Q_foreground, check_valid_string);
2944   IIFORMAT_VALID_KEYWORD (cursor_font, Q_background, check_valid_string);
2945
2946   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (font, "font");
2947
2948   IIFORMAT_HAS_METHOD (font, validate);
2949   IIFORMAT_HAS_METHOD (font, possible_dest_types);
2950   IIFORMAT_HAS_METHOD (font, instantiate);
2951   IIFORMAT_VALID_CONSOLE (x, font);
2952
2953   IIFORMAT_VALID_KEYWORD (font, Q_data, check_valid_string);
2954   IIFORMAT_VALID_KEYWORD (font, Q_foreground, check_valid_string);
2955   IIFORMAT_VALID_KEYWORD (font, Q_background, check_valid_string);
2956
2957 #ifdef HAVE_XFACE
2958   INITIALIZE_DEVICE_IIFORMAT (x, xface);
2959   IIFORMAT_HAS_DEVMETHOD (x, xface, instantiate);
2960 #endif
2961
2962   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (autodetect,
2963                                         "autodetect");
2964
2965   IIFORMAT_HAS_METHOD (autodetect, validate);
2966   IIFORMAT_HAS_METHOD (autodetect, normalize);
2967   IIFORMAT_HAS_METHOD (autodetect, possible_dest_types);
2968   /* #### autodetect is flawed IMO: 
2969   1. It makes the assumption that you can detect whether the user
2970   wanted a cursor or a string based on the data, since the data is a
2971   string you have to prioritise cursors. Instead we will force users
2972   to pick the appropriate image type, this is what we do under
2973   MS-Windows anyway.
2974   2. It doesn't fit with the new domain model - you cannot tell which
2975   domain it needs to be instantiated in until you've actually
2976   instantiated it, which mucks up caching.
2977   3. It only copes with cursors and strings which seems bogus. */
2978   IIFORMAT_HAS_SHARED_METHOD (autodetect, governing_domain, subwindow);
2979   IIFORMAT_HAS_METHOD (autodetect, instantiate);
2980   IIFORMAT_VALID_CONSOLE (x, autodetect);
2981
2982   IIFORMAT_VALID_KEYWORD (autodetect, Q_data, check_valid_string);
2983 }
2984
2985 void
2986 vars_of_glyphs_x (void)
2987 {
2988   DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path /*
2989 A list of the directories in which X bitmap files may be found.
2990 If nil, this is initialized from the "*bitmapFilePath" resource.
2991 This is used by the `make-image-instance' function (however, note that if
2992 the environment variable XBMLANGPATH is set, it is consulted first).
2993 */ );
2994   Vx_bitmap_file_path = Qnil;
2995 }
2996
2997 void
2998 complex_vars_of_glyphs_x (void)
2999 {
3000 #define BUILD_GLYPH_INST(variable, name)                        \
3001   Fadd_spec_to_specifier                                        \
3002     (GLYPH_IMAGE (XGLYPH (variable)),                           \
3003      vector3 (Qxbm, Q_data,                                     \
3004               list3 (make_int (name##_width),                   \
3005                      make_int (name##_height),                  \
3006                      make_ext_string ((Extbyte *) name##_bits,  \
3007                                       sizeof (name##_bits),     \
3008                                       Qbinary))),               \
3009      Qglobal, Qx, Qnil)
3010
3011   BUILD_GLYPH_INST (Vtruncation_glyph, truncator);
3012   BUILD_GLYPH_INST (Vcontinuation_glyph, continuer);
3013   BUILD_GLYPH_INST (Vxemacs_logo, xemacs);
3014   BUILD_GLYPH_INST (Vhscroll_glyph, hscroll);
3015
3016 #undef BUILD_GLYPH_INST
3017 }