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