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