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