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