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