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