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