More warning suppressions
[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                         image_instance_add_x_image(ii, ximage, slice,
875                                                    instantiator);
876
877                 if (ximage) {
878                         if (ximage->data) {
879                                 xfree(ximage->data);
880                                 ximage->data = 0;
881                         }
882                         XDestroyImage(ximage);
883                 }
884                 ximage = 0;
885         }
886 }
887
888 int read_bitmap_data_from_file(const char *filename, unsigned int *width,
889                                unsigned int *height, unsigned char **datap,
890                                int *x_hot, int *y_hot)
891 {
892         return XmuReadBitmapDataFromFile(filename, width, height,
893                                          datap, x_hot, y_hot);
894 }
895
896 /* Given inline data for a mono pixmap, create and return the
897    corresponding X object. */
898
899 static Pixmap
900 pixmap_from_xbm_inline(Lisp_Object device, int width, int height,
901                        /* Note that data is in ext-format! */
902                        char *bits)
903 {
904         return XCreatePixmapFromBitmapData
905                 (DEVICE_X_DISPLAY(XDEVICE(device)),
906                  XtWindow(DEVICE_XT_APP_SHELL(XDEVICE(device))),
907                  bits, width, height, 1, 0, 1);
908 }
909
910 /* Given inline data for a mono pixmap, initialize the given
911    image instance accordingly. */
912
913 static void
914 init_image_instance_from_xbm_inline(Lisp_Image_Instance * ii,
915                                     int width, int height,
916                                     /* Note that data is in ext-format! */
917                                     char *bits,
918                                     Lisp_Object instantiator,
919                                     Lisp_Object pointer_fg,
920                                     Lisp_Object pointer_bg,
921                                     int dest_mask,
922                                     Pixmap mask, Lisp_Object mask_filename)
923 {
924         Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
925         Lisp_Object foreground =
926                 find_keyword_in_vector(instantiator, Q_foreground);
927         Lisp_Object background =
928                 find_keyword_in_vector(instantiator, Q_background);
929         Display *dpy;
930         Screen *scr;
931         Drawable draw;
932         enum image_instance_type type;
933
934         if (!DEVICE_X_P(XDEVICE(device)))
935                 signal_simple_error("Not an X device", device);
936
937         dpy = DEVICE_X_DISPLAY(XDEVICE(device));
938         draw = XtWindow(DEVICE_XT_APP_SHELL(XDEVICE(device)));
939         scr = DefaultScreenOfDisplay(dpy);
940
941         if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) &&
942             (dest_mask & IMAGE_COLOR_PIXMAP_MASK)) {
943                 if (!NILP(foreground) || !NILP(background))
944                         type = IMAGE_COLOR_PIXMAP;
945                 else
946                         type = IMAGE_MONO_PIXMAP;
947         } else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
948                 type = IMAGE_MONO_PIXMAP;
949         else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
950                 type = IMAGE_COLOR_PIXMAP;
951         else if (dest_mask & IMAGE_POINTER_MASK)
952                 type = IMAGE_POINTER;
953         else
954                 incompatible_image_types(instantiator, dest_mask,
955                                          IMAGE_MONO_PIXMAP_MASK |
956                                          IMAGE_COLOR_PIXMAP_MASK |
957                                          IMAGE_POINTER_MASK);
958
959         x_initialize_pixmap_image_instance(ii, 1, type);
960         IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = width;
961         IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = height;
962         IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
963             find_keyword_in_vector(instantiator, Q_file);
964
965         switch (type) {
966         case IMAGE_MONO_PIXMAP: {
967                 IMAGE_INSTANCE_X_PIXMAP(ii) =
968                         pixmap_from_xbm_inline(device, width, height,
969                                                (Extbyte *) bits);
970         }
971                 break;
972
973         case IMAGE_COLOR_PIXMAP: {
974                 Dimension d = DEVICE_X_DEPTH(XDEVICE(device));
975                 unsigned long fg = BlackPixelOfScreen(scr);
976                 unsigned long bg = WhitePixelOfScreen(scr);
977
978                 if (!NILP(foreground) && !COLOR_INSTANCEP(foreground))
979                         foreground =
980                                 Fmake_color_instance(foreground, device,
981                                                      encode_error_behavior_flag
982                                                      (ERROR_ME));
983
984                 if (COLOR_INSTANCEP(foreground))
985                         fg = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE
986                                                     (foreground)).pixel;
987
988                 if (!NILP(background) && !COLOR_INSTANCEP(background))
989                         background =
990                                 Fmake_color_instance(background, device,
991                                                      encode_error_behavior_flag
992                                                      (ERROR_ME));
993
994                 if (COLOR_INSTANCEP(background))
995                         bg = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE
996                                                     (background)).pixel;
997
998                 /* We used to duplicate the pixels using XAllocColor(), to protect
999                    against their getting freed.  Just as easy to just store the
1000                    color instances here and GC-protect them, so this doesn't
1001                    happen. */
1002                 IMAGE_INSTANCE_PIXMAP_FG(ii) = foreground;
1003                 IMAGE_INSTANCE_PIXMAP_BG(ii) = background;
1004                 IMAGE_INSTANCE_X_PIXMAP(ii) =
1005                         XCreatePixmapFromBitmapData(dpy, draw,
1006                                                     (char *)bits, width,
1007                                                     height, fg, bg, d);
1008                 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = d;
1009         }
1010                 break;
1011
1012         case IMAGE_POINTER: {
1013                 XColor fg_color, bg_color;
1014                 Pixmap source;
1015
1016                 check_pointer_sizes(scr, width, height, instantiator);
1017
1018                 source =
1019                         XCreatePixmapFromBitmapData(dpy, draw,
1020                                                     (char *)bits, width,
1021                                                     height, 1, 0, 1);
1022
1023                 if (NILP(foreground))
1024                         foreground = pointer_fg;
1025                 if (NILP(background))
1026                         background = pointer_bg;
1027                 generate_cursor_fg_bg(device, &foreground, &background,
1028                                       &fg_color, &bg_color);
1029
1030                 IMAGE_INSTANCE_PIXMAP_FG(ii) = foreground;
1031                 IMAGE_INSTANCE_PIXMAP_BG(ii) = background;
1032                 IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii) =
1033                         find_keyword_in_vector(instantiator, Q_hotspot_x);
1034                 IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii) =
1035                         find_keyword_in_vector(instantiator, Q_hotspot_y);
1036                 IMAGE_INSTANCE_X_CURSOR(ii) =
1037                         XCreatePixmapCursor
1038                         (dpy, source, mask, &fg_color, &bg_color,
1039                          !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) ?
1040                          XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii)) : 0,
1041                          !NILP(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii)) ?
1042                          XINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii)) : 0);
1043         }
1044                 break;
1045
1046         case IMAGE_UNKNOWN:
1047         case IMAGE_NOTHING:
1048         case IMAGE_TEXT:
1049         case IMAGE_SUBWINDOW:
1050         case IMAGE_WIDGET:
1051         default:
1052                 abort();
1053         }
1054 }
1055
1056 static void
1057 xbm_instantiate_1(Lisp_Object image_instance, Lisp_Object instantiator,
1058                   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1059                   int dest_mask, int width, int height,
1060                   /* Note that data is in ext-format! */
1061                   char *bits)
1062 {
1063         Lisp_Object mask_data =
1064                 find_keyword_in_vector(instantiator, Q_mask_data);
1065         Lisp_Object mask_file =
1066                 find_keyword_in_vector(instantiator, Q_mask_file);
1067         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1068         Pixmap mask = 0;
1069
1070         if (!NILP(mask_data)) {
1071                 char *ext_data;
1072
1073                 LISP_STRING_TO_EXTERNAL(XCAR(XCDR(XCDR(mask_data))), ext_data,
1074                                         Qbinary);
1075                 mask = pixmap_from_xbm_inline(
1076                         IMAGE_INSTANCE_DEVICE(ii),
1077                         XINT(XCAR(mask_data)),
1078                         XINT(XCAR(XCDR(mask_data))),
1079                         ext_data);
1080         }
1081
1082         init_image_instance_from_xbm_inline(ii, width, height, bits,
1083                                             instantiator, pointer_fg,
1084                                             pointer_bg, dest_mask, mask,
1085                                             mask_file);
1086 }
1087
1088 /* Instantiate method for XBM's. */
1089
1090 static void
1091 x_xbm_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1092                   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1093                   int dest_mask, Lisp_Object domain)
1094 {
1095         Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1096         char *ext_data;
1097
1098         assert(!NILP(data));
1099
1100         LISP_STRING_TO_EXTERNAL(XCAR(XCDR(XCDR(data))), ext_data, Qbinary);
1101
1102         xbm_instantiate_1(image_instance, instantiator, pointer_fg,
1103                           pointer_bg, dest_mask, XINT(XCAR(data)),
1104                           XINT(XCAR(XCDR(data))), ext_data);
1105 }
1106 \f
1107 #ifdef HAVE_XPM
1108
1109 /**********************************************************************
1110  *                             XPM                                    *
1111  **********************************************************************/
1112  /* xpm 3.2g and better has XpmCreatePixmapFromBuffer()...
1113     There was no version number in xpm.h before 3.3, but this should do.
1114   */
1115 #if (XpmVersion >= 3) || defined(XpmExactColors)
1116 # define XPM_DOES_BUFFERS
1117 #endif
1118
1119 #ifndef XPM_DOES_BUFFERS
1120 Your version of XPM is too old.You cannot compile with it.
1121     Upgrade to version 3.2 g or better or compile with-- with - xpm = no.
1122 #endif                          /* !XPM_DOES_BUFFERS */
1123     static XpmColorSymbol *
1124 extract_xpm_color_names(XpmAttributes * xpmattrs, Lisp_Object device,
1125                         Lisp_Object domain,
1126                         Lisp_Object color_symbol_alist) {
1127         /* This function can GC */
1128         Display * dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1129         Colormap cmap = DEVICE_X_COLORMAP(XDEVICE(device));
1130         XColor color;
1131         Lisp_Object rest;
1132         Lisp_Object results = Qnil;
1133         int i;
1134         XpmColorSymbol *symbols;
1135         struct gcpro gcpro1, gcpro2;
1136
1137         GCPRO2(results, device);
1138
1139         /* We built up results to be (("name" . #<color>) ...) so that if an
1140            error happens we don't lose any malloc()ed data, or more importantly,
1141            leave any pixels allocated in the server. */
1142         i = 0;
1143         LIST_LOOP(rest, color_symbol_alist) {
1144                 Lisp_Object cons = XCAR(rest);
1145                 Lisp_Object name = XCAR(cons);
1146                 Lisp_Object value = XCDR(cons);
1147                 if (NILP(value))
1148                         continue;
1149                 if (STRINGP(value))
1150                         value =
1151                             Fmake_color_instance
1152                             (value, device,
1153                              encode_error_behavior_flag(ERROR_ME_NOT));
1154                 else {
1155                         assert(COLOR_SPECIFIERP(value));
1156                         value = Fspecifier_instance(value, domain, Qnil, Qnil);
1157                 }
1158                 if (NILP(value))
1159                         continue;
1160                 results = noseeum_cons(noseeum_cons(name, value), results);
1161                 i++;
1162         }
1163         UNGCPRO;                /* no more evaluation */
1164
1165         if (i == 0)
1166                 return 0;
1167
1168         symbols = xnew_atomic_array(XpmColorSymbol, i);
1169         xpmattrs->valuemask |= XpmColorSymbols;
1170         xpmattrs->colorsymbols = symbols;
1171         xpmattrs->numsymbols = i;
1172
1173         while (--i >= 0) {
1174                 Lisp_Object cons = XCAR(results);
1175                 color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(XCDR(cons)));
1176                 /* Duplicate the pixel value so that we still have
1177                  * a lock on it if the pixel we were passed is later freed. */
1178                 if (!XAllocColor(dpy, cmap, &color)) {
1179                         /* it must be allocable since we're
1180                          * just duplicating it */
1181                         abort();
1182                 }
1183
1184                 symbols[i].name = (char *)XSTRING_DATA(XCAR(cons));
1185                 symbols[i].pixel = color.pixel;
1186                 symbols[i].value = 0;
1187                 free_cons(XCONS(cons));
1188                 cons = results;
1189                 results = XCDR(results);
1190                 free_cons(XCONS(cons));
1191         }
1192         return symbols;
1193 }
1194
1195 static void xpm_free(XpmAttributes * xpmattrs)
1196 {
1197         /* Could conceivably lose if XpmXXX returned an error without first
1198            initializing this structure, if we didn't know that initializing it
1199            to all zeros was ok (and also that it's ok to call XpmFreeAttributes()
1200            multiple times, since it zeros slots as it frees them...) */
1201         XpmFreeAttributes(xpmattrs);
1202 }
1203
1204 static void
1205 x_xpm_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1206                   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1207                   int dest_mask, Lisp_Object domain)
1208 {
1209         /* This function can GC */
1210         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1211         Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1212         Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1213         Display *dpy;
1214         Screen *xs;
1215         Colormap cmap;
1216         int depth;
1217         Visual *visual;
1218         Pixmap pixmap;
1219         Pixmap mask = 0;
1220         XpmAttributes xpmattrs;
1221         int result;
1222         XpmColorSymbol *color_symbols;
1223         Lisp_Object color_symbol_alist = find_keyword_in_vector(instantiator,
1224                                                                 Q_color_symbols);
1225         enum image_instance_type type;
1226         int force_mono;
1227         unsigned int w, h;
1228
1229         if (!DEVICE_X_P(XDEVICE(device)))
1230                 signal_simple_error("Not an X device", device);
1231
1232         dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1233         xs = DefaultScreenOfDisplay(dpy);
1234
1235         if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1236                 type = IMAGE_COLOR_PIXMAP;
1237         else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1238                 type = IMAGE_MONO_PIXMAP;
1239         else if (dest_mask & IMAGE_POINTER_MASK)
1240                 type = IMAGE_POINTER;
1241         else
1242                 incompatible_image_types(instantiator, dest_mask,
1243                                          IMAGE_MONO_PIXMAP_MASK |
1244                                          IMAGE_COLOR_PIXMAP_MASK |
1245                                          IMAGE_POINTER_MASK);
1246         force_mono = (type != IMAGE_COLOR_PIXMAP);
1247
1248 #if 1
1249         /* Although I haven't found it documented yet, it appears that pointers are
1250            always colored via the default window colormap... Sigh. */
1251         if (type == IMAGE_POINTER) {
1252                 cmap = DefaultColormap(dpy, DefaultScreen(dpy));
1253                 depth = DefaultDepthOfScreen(xs);
1254                 visual = DefaultVisualOfScreen(xs);
1255         } else {
1256                 cmap = DEVICE_X_COLORMAP(XDEVICE(device));
1257                 depth = DEVICE_X_DEPTH(XDEVICE(device));
1258                 visual = DEVICE_X_VISUAL(XDEVICE(device));
1259         }
1260 #else
1261         cmap = DEVICE_X_COLORMAP(XDEVICE(device));
1262         depth = DEVICE_X_DEPTH(XDEVICE(device));
1263         visual = DEVICE_X_VISUAL(XDEVICE(device));
1264 #endif
1265
1266         x_initialize_pixmap_image_instance(ii, 1, type);
1267
1268         assert(!NILP(data));
1269
1270       retry:
1271
1272         xzero(xpmattrs);        /* want XpmInitAttributes() */
1273         xpmattrs.valuemask = XpmReturnPixels;
1274         if (force_mono) {
1275                 /* Without this, we get a 1-bit version of the color image, which
1276                    isn't quite right.  With this, we get the mono image, which might
1277                    be very different looking. */
1278                 xpmattrs.valuemask |= XpmColorKey;
1279                 xpmattrs.color_key = XPM_MONO;
1280                 xpmattrs.depth = 1;
1281                 xpmattrs.valuemask |= XpmDepth;
1282         } else {
1283                 xpmattrs.closeness = 65535;
1284                 xpmattrs.valuemask |= XpmCloseness;
1285                 xpmattrs.depth = depth;
1286                 xpmattrs.valuemask |= XpmDepth;
1287                 xpmattrs.visual = visual;
1288                 xpmattrs.valuemask |= XpmVisual;
1289                 xpmattrs.colormap = cmap;
1290                 xpmattrs.valuemask |= XpmColormap;
1291         }
1292
1293         color_symbols = extract_xpm_color_names(&xpmattrs, device, domain,
1294                                                 color_symbol_alist);
1295
1296         result = XpmCreatePixmapFromBuffer(dpy,
1297                                            XtWindow(DEVICE_XT_APP_SHELL
1298                                                     (XDEVICE(device))),
1299                                            (char *)XSTRING_DATA(data), &pixmap,
1300                                            &mask, &xpmattrs);
1301
1302         if (color_symbols) {
1303                 xfree(color_symbols);
1304                 xpmattrs.colorsymbols = 0;      /* in case XpmFreeAttr is too smart... */
1305                 xpmattrs.numsymbols = 0;
1306         }
1307
1308         switch (result) {
1309         case XpmSuccess:
1310                 break;
1311         case XpmFileInvalid:
1312                 {
1313                         xpm_free(&xpmattrs);
1314                         signal_image_error("invalid XPM data", data);
1315                 }
1316         case XpmColorFailed:
1317         case XpmColorError:
1318                 {
1319                         xpm_free(&xpmattrs);
1320                         if (force_mono) {
1321                                 /* second time; blow out. */
1322                                 signal_double_file_error("Reading pixmap data",
1323                                                          "color allocation failed",
1324                                                          data);
1325                         } else {
1326                                 if (!(dest_mask & IMAGE_MONO_PIXMAP_MASK)) {
1327                                         /* second time; blow out. */
1328                                         signal_double_file_error
1329                                             ("Reading pixmap data",
1330                                              "color allocation failed", data);
1331                                 }
1332                                 force_mono = 1;
1333                                 IMAGE_INSTANCE_TYPE(ii) = IMAGE_MONO_PIXMAP;
1334                                 goto retry;
1335                         }
1336                 }
1337         case XpmNoMemory:
1338                 {
1339                         xpm_free(&xpmattrs);
1340                         signal_double_file_error("Parsing pixmap data",
1341                                                  "out of memory", data);
1342                 }
1343         default:
1344                 {
1345                         xpm_free(&xpmattrs);
1346                         signal_double_file_error_2("Parsing pixmap data",
1347                                                    "unknown error code",
1348                                                    make_int(result), data);
1349                 }
1350         }
1351
1352         w = xpmattrs.width;
1353         h = xpmattrs.height;
1354
1355         {
1356                 int npixels = xpmattrs.npixels;
1357                 Pixel *pixels;
1358
1359                 if (npixels != 0) {
1360                         pixels = xnew_atomic_array(Pixel, npixels);
1361                         memcpy(pixels, xpmattrs.pixels,
1362                                npixels * sizeof(Pixel));
1363                 } else {
1364                         pixels = NULL;
1365                 }
1366
1367                 IMAGE_INSTANCE_X_PIXMAP(ii) = pixmap;
1368                 IMAGE_INSTANCE_PIXMAP_MASK(ii) = (void *)mask;
1369                 IMAGE_INSTANCE_X_COLORMAP(ii) = cmap;
1370                 IMAGE_INSTANCE_X_PIXELS(ii) = pixels;
1371                 IMAGE_INSTANCE_X_NPIXELS(ii) = npixels;
1372                 IMAGE_INSTANCE_PIXMAP_WIDTH(ii) = w;
1373                 IMAGE_INSTANCE_PIXMAP_HEIGHT(ii) = h;
1374                 IMAGE_INSTANCE_PIXMAP_FILENAME(ii) =
1375                     find_keyword_in_vector(instantiator, Q_file);
1376         }
1377
1378         switch (type) {
1379         case IMAGE_MONO_PIXMAP:
1380                 break;
1381
1382         case IMAGE_COLOR_PIXMAP: {
1383                 IMAGE_INSTANCE_PIXMAP_DEPTH(ii) = depth;
1384         }
1385                 break;
1386
1387         case IMAGE_POINTER: {
1388                 int npixels = xpmattrs.npixels;
1389                 Pixel *pixels = xpmattrs.pixels;
1390                 XColor fg, bg;
1391                 int i;
1392                 int xhot = 0, yhot = 0;
1393
1394                 if (xpmattrs.valuemask & XpmHotspot) {
1395                         xhot = xpmattrs.x_hotspot;
1396                         XSETINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_X(ii),
1397                                 xpmattrs.x_hotspot);
1398                 }
1399                 if (xpmattrs.valuemask & XpmHotspot) {
1400                         yhot = xpmattrs.y_hotspot;
1401                         XSETINT(IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y(ii),
1402                                 xpmattrs.y_hotspot);
1403                 }
1404                 check_pointer_sizes(xs, w, h, instantiator);
1405
1406                 /* If the loaded pixmap has colors allocated (meaning it came
1407                    from an XPM file), then use those as the default colors for
1408                    the cursor we create.  Otherwise, default to pointer_fg and
1409                    pointer_bg.
1410                 */
1411                 if (npixels >= 2) {
1412                         /* With an XBM file, it's obvious which bit is
1413                            foreground and which is background, or rather, it's
1414                            implicit: in an XBM file, a 1 bit is foreground, and
1415                            a 0 bit is background.
1416
1417                            XCreatePixmapCursor() assumes this property of the
1418                            pixmap it is called with as well; the `foreground'
1419                            color argument is used for the 1 bits.
1420
1421                            With an XPM file, it's tricker, since the elements of
1422                            the pixmap don't represent FG and BG, but are actual
1423                            pixel values.  So we need to figure out which of
1424                            those pixels is the foreground color and which is the
1425                            background.  We do it by comparing RGB and assuming
1426                            that the darker color is the foreground.  This works
1427                            with the result of xbmtopbm|ppmtoxpm, at least.
1428
1429                            It might be nice if there was some way to tag the
1430                            colors in the XPM file with whether they are the
1431                            foreground - perhaps with logical color names
1432                            somehow?
1433
1434                            Once we have decided which color is the foreground,
1435                            we need to ensure that that color corresponds to a
1436                            `1' bit in the Pixmap.  The XPM library wrote into
1437                            the (1-bit) pixmap with XPutPixel, which will ignore
1438                            all but the least significant bit.
1439
1440                            This means that a 1 bit in the image corresponds to
1441                            `fg' only if `fg.pixel' is odd.
1442
1443                            (This also means that the image will be all the same
1444                            color if both `fg' and `bg' are odd or even, but we
1445                            can safely assume that that won't happen if the XPM
1446                            file is sensible I think.)
1447
1448                            The desired result is that the image use `1' to
1449                            represent the foreground color, and `0' to represent
1450                            the background color.  So, we may need to invert the
1451                            image to accomplish this; we invert if fg is
1452                            odd. (Remember that WhitePixel and BlackPixel are not
1453                            necessarily 1 and 0 respectively, though I think it
1454                            might be safe to assume that one of them is always 1
1455                            and the other is always 0.  We also pretty much need
1456                            to assume that one is even and the other is odd.)
1457                         */
1458
1459                         fg.pixel = pixels[0];   /* pick a pixel at random. */
1460                         bg.pixel = fg.pixel;
1461                         for (i = 1; i < npixels; i++) {
1462                                 /* Look for an "other" pixel value. */
1463                                 bg.pixel = pixels[i];
1464                                 if (fg.pixel != bg.pixel)
1465                                         break;
1466                         }
1467
1468                         /* If (fg.pixel == bg.pixel) then probably something has
1469                            gone wrong, but I don't think signalling an error
1470                            would be appropriate. */
1471
1472                         XQueryColor(dpy, cmap, &fg);
1473                         XQueryColor(dpy, cmap, &bg);
1474
1475                         /* If the foreground is lighter than the background,
1476                            swap them.  (This occurs semi-randomly, depending on
1477                            the ordering of the color list in the XPM file.)
1478                         */
1479                         {
1480                                 unsigned short fg_total =
1481                                         ((fg.red / 3) + (fg.green / 3)
1482                                          + (fg.blue / 3));
1483                                 unsigned short bg_total =
1484                                         ((bg.red / 3) + (bg.green / 3)
1485                                          + (bg.blue / 3));
1486                                 if (fg_total > bg_total) {
1487                                         XColor swap;
1488                                         swap = fg;
1489                                         fg = bg;
1490                                         bg = swap;
1491                                 }
1492                         }
1493
1494                         /* If the fg pixel corresponds to a `0' in the bitmap,
1495                            invert it.  (This occurs (only?) on servers with
1496                            Black=0, White=1.)
1497                         */
1498                         if ((fg.pixel & 1) == 0) {
1499                                 XGCValues gcv;
1500                                 GC gc;
1501                                 gcv.function = GXxor;
1502                                 gcv.foreground = 1;
1503                                 gc = XCreateGC(dpy, pixmap,
1504                                                (GCFunction |
1505                                                 GCForeground), &gcv);
1506                                 XFillRectangle(dpy, pixmap, gc, 0, 0, w,
1507                                                h);
1508                                 XFreeGC(dpy, gc);
1509                         }
1510                 } else {
1511                         generate_cursor_fg_bg(device, &pointer_fg,
1512                                               &pointer_bg, &fg, &bg);
1513                         IMAGE_INSTANCE_PIXMAP_FG(ii) = pointer_fg;
1514                         IMAGE_INSTANCE_PIXMAP_BG(ii) = pointer_bg;
1515                 }
1516
1517                 IMAGE_INSTANCE_X_CURSOR(ii) =
1518                         XCreatePixmapCursor
1519                         (dpy, pixmap, mask, &fg, &bg, xhot, yhot);
1520         }
1521
1522                 break;
1523
1524         case IMAGE_UNKNOWN:
1525         case IMAGE_NOTHING:
1526         case IMAGE_TEXT:
1527         case IMAGE_SUBWINDOW:
1528         case IMAGE_WIDGET:
1529         default:
1530                 abort();
1531         }
1532
1533         xpm_free(&xpmattrs);    /* after we've read pixels and hotspot */
1534 }
1535
1536 #endif                          /* HAVE_XPM */
1537 \f
1538 #ifdef HAVE_XFACE
1539
1540 /**********************************************************************
1541  *                             X-Face                                 *
1542  **********************************************************************/
1543 #if defined(EXTERN)
1544 /* This is about to get redefined! */
1545 #undef EXTERN
1546 #endif
1547 /* We have to define SYSV32 so that compface.h includes string.h
1548    instead of strings.h. */
1549 #define SYSV32
1550 #ifdef __cplusplus
1551 extern "C" {
1552 #endif
1553 #include <compface.h>
1554 #ifdef __cplusplus
1555 }
1556 #endif
1557 /* JMP_BUF cannot be used here because if it doesn't get defined
1558    to jmp_buf we end up with a conflicting type error with the
1559    definition in compface.h */ extern jmp_buf comp_env;
1560 #undef SYSV32
1561
1562 static void
1563 x_xface_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1564                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1565                     int dest_mask, Lisp_Object domain)
1566 {
1567         Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1568         int i, stattis;
1569         char *bits, *bp;
1570         char *p;
1571         const char *volatile emsg = 0;
1572         char *volatile dstring;
1573
1574         assert(!NILP(data));
1575
1576         LISP_STRING_TO_EXTERNAL(data, dstring, Qbinary);
1577
1578         if ((p = strchr(dstring, ':'))) {
1579                 dstring = p + 1;
1580         }
1581
1582         /* Must use setjmp not SETJMP because we used jmp_buf above not
1583            JMP_BUF */
1584         if (!(stattis = setjmp(comp_env))) {
1585                 UnCompAll(dstring);
1586                 UnGenFace();
1587         }
1588
1589         switch (stattis) {
1590         case -2:
1591                 emsg = "uncompface: internal error";
1592                 break;
1593         case -1:
1594                 emsg = "uncompface: insufficient or invalid data";
1595                 break;
1596         case 1:
1597                 emsg = "uncompface: excess data ignored";
1598                 break;
1599         default:
1600                 break;
1601         }
1602
1603         if (emsg) {
1604                 signal_simple_error_2(emsg, data, Qimage);
1605         }
1606         bp = bits = (char *)alloca(PIXELS / 8);
1607
1608         /* the compface library exports char F[], which uses a single byte per
1609            pixel to represent a 48x48 bitmap.  Yuck. */
1610         for (i = 0, p = F; i < (PIXELS / 8); ++i) {
1611                 int n, b;
1612                 /* reverse the bit order of each byte... */
1613                 for (b = n = 0; b < 8; ++b) {
1614                         n |= ((*p++) << b);
1615                 }
1616                 *bp++ = (char)n;
1617         }
1618
1619         xbm_instantiate_1(image_instance, instantiator, pointer_fg,
1620                           pointer_bg, dest_mask, 48, 48, bits);
1621 }
1622
1623 #endif                          /* HAVE_XFACE */
1624 \f
1625 /**********************************************************************
1626  *                       Autodetect                                      *
1627  **********************************************************************/
1628
1629 static void autodetect_validate(Lisp_Object instantiator)
1630 {
1631         data_must_be_present(instantiator);
1632 }
1633
1634 static Lisp_Object
1635 autodetect_normalize(Lisp_Object instantiator,
1636                      Lisp_Object console_type, Lisp_Object dest_mask)
1637 {
1638         Lisp_Object file = find_keyword_in_vector(instantiator, Q_data);
1639         Lisp_Object filename = Qnil;
1640         Lisp_Object data = Qnil;
1641         struct gcpro gcpro1, gcpro2, gcpro3;
1642         Lisp_Object alist = Qnil;
1643
1644         GCPRO3(filename, data, alist);
1645
1646         if (NILP(file))         /* no conversion necessary */
1647                 RETURN_UNGCPRO(instantiator);
1648
1649         alist = tagged_vector_to_alist(instantiator);
1650
1651         filename = locate_pixmap_file(file);
1652         if (!NILP(filename)) {
1653                 int xhot, yhot;
1654                 /* #### Apparently some versions of XpmReadFileToData, which is
1655                    called by pixmap_to_lisp_data, don't return an error value if
1656                    the given file is not a valid XPM file.  Instead, they just
1657                    seg fault.  It is definitely caused by passing a bitmap.  To
1658                    try and avoid this we check for bitmaps first.  */
1659
1660                 data = bitmap_to_lisp_data(filename, &xhot, &yhot, 1);
1661
1662                 if (!EQ(data, Qt)) {
1663                         alist = remassq_no_quit(Q_data, alist);
1664                         alist = Fcons(Fcons(Q_file, filename),
1665                                       Fcons(Fcons(Q_data, data), alist));
1666                         if (xhot != -1) {
1667                                 alist = Fcons(Fcons(Q_hotspot_x, make_int(xhot)),
1668                                               alist);
1669                         }
1670                         if (yhot != -1) {
1671                                 alist = Fcons(Fcons(Q_hotspot_y,
1672                                                     make_int(yhot)),
1673                                               alist);
1674                         }
1675                         alist = xbm_mask_file_munging(alist, filename, Qnil,
1676                                                       console_type);
1677
1678                         {
1679                                 Lisp_Object result =
1680                                     alist_to_tagged_vector(Qxbm, alist);
1681                                 free_alist(alist);
1682                                 RETURN_UNGCPRO(result);
1683                         }
1684                 }
1685 #ifdef HAVE_XPM
1686                 data = pixmap_to_lisp_data(filename, 1);
1687
1688                 if (!EQ(data, Qt)) {
1689                         alist = remassq_no_quit(Q_data, alist);
1690                         alist = Fcons(Fcons(Q_file, filename),
1691                                       Fcons(Fcons(Q_data, data), alist));
1692                         alist = Fcons(Fcons(Q_color_symbols,
1693                                             evaluate_xpm_color_symbols()),
1694                                       alist);
1695                         {
1696                                 Lisp_Object result =
1697                                     alist_to_tagged_vector(Qxpm, alist);
1698                                 free_alist(alist);
1699                                 RETURN_UNGCPRO(result);
1700                         }
1701                 }
1702 #endif
1703         }
1704
1705         /* If we couldn't convert it, just put it back as it is.
1706            We might try to further frob it later as a cursor-font
1707            specification. (We can't do that now because we don't know
1708            what dest-types it's going to be instantiated into.) */
1709         {
1710                 Lisp_Object result = alist_to_tagged_vector(Qautodetect, alist);
1711                 free_alist(alist);
1712                 RETURN_UNGCPRO(result);
1713         }
1714 }
1715
1716 static int autodetect_possible_dest_types(void)
1717 {
1718         return
1719             IMAGE_MONO_PIXMAP_MASK |
1720             IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK | IMAGE_TEXT_MASK;
1721 }
1722
1723 static void
1724 autodetect_instantiate(Lisp_Object image_instance,
1725                        Lisp_Object instantiator,
1726                        Lisp_Object pointer_fg,
1727                        Lisp_Object pointer_bg,
1728                        int dest_mask, Lisp_Object domain)
1729 {
1730         Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1731         struct gcpro gcpro1, gcpro2, gcpro3;
1732         Lisp_Object alist = Qnil;
1733         Lisp_Object result = Qnil;
1734         int is_cursor_font = 0;
1735
1736         GCPRO3(data, alist, result);
1737
1738         alist = tagged_vector_to_alist(instantiator);
1739         if (dest_mask & IMAGE_POINTER_MASK) {
1740                 const char *name_ext;
1741                 LISP_STRING_TO_EXTERNAL(data, name_ext, Qfile_name);
1742                 if (XmuCursorNameToIndex(name_ext) != -1) {
1743                         result = alist_to_tagged_vector(Qcursor_font, alist);
1744                         is_cursor_font = 1;
1745                 }
1746         }
1747
1748         if (!is_cursor_font)
1749                 result = alist_to_tagged_vector(Qstring, alist);
1750         free_alist(alist);
1751
1752         if (is_cursor_font)
1753                 cursor_font_instantiate(image_instance, result, pointer_fg,
1754                                         pointer_bg, dest_mask, domain);
1755         else
1756                 string_instantiate(image_instance, result, pointer_fg,
1757                                    pointer_bg, dest_mask, domain);
1758
1759         UNGCPRO;
1760 }
1761 \f
1762 /**********************************************************************
1763  *                              Font                                  *
1764  **********************************************************************/
1765
1766 static void font_validate(Lisp_Object instantiator)
1767 {
1768         data_must_be_present(instantiator);
1769 }
1770
1771 /* XmuCvtStringToCursor is bogus in the following ways:
1772
1773    - When it can't convert the given string to a real cursor, it will
1774      sometimes return a "success" value, after triggering a BadPixmap
1775      error.  It then gives you a cursor that will itself generate BadCursor
1776      errors.  So we install this error handler to catch/notice the X error
1777      and take that as meaning "couldn't convert."
1778
1779    - When you tell it to find a cursor file that doesn't exist, it prints
1780      an error message on stderr.  You can't make it not do that.
1781
1782    - Also, using Xmu means we can't properly hack Lisp_Image_Instance
1783      objects, or XPM files, or $XBMLANGPATH.
1784  */
1785
1786 /* Duplicate the behavior of XmuCvtStringToCursor() to bypass its bogusness. */
1787
1788 static int XLoadFont_got_error;
1789
1790 static int XLoadFont_error_handler(Display * dpy, XErrorEvent * xerror)
1791 {
1792         XLoadFont_got_error = 1;
1793         return 0;
1794 }
1795
1796 static Font safe_XLoadFont(Display * dpy, char *name)
1797 {
1798         Font font;
1799         int (*old_handler) (Display *, XErrorEvent *);
1800         XLoadFont_got_error = 0;
1801         XSync(dpy, 0);
1802         old_handler = XSetErrorHandler(XLoadFont_error_handler);
1803         font = XLoadFont(dpy, name);
1804         XSync(dpy, 0);
1805         XSetErrorHandler(old_handler);
1806         if (XLoadFont_got_error)
1807                 return 0;
1808         return font;
1809 }
1810
1811 static int font_possible_dest_types(void)
1812 {
1813         return IMAGE_POINTER_MASK;
1814 }
1815
1816 static void
1817 font_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1818                  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1819                  int dest_mask, Lisp_Object domain)
1820 {
1821         /* This function can GC */
1822         Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1823         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1824         Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1825         Display *dpy;
1826         XColor fg, bg;
1827         Font source, mask;
1828         char source_name[MAXPATHLEN], mask_name[MAXPATHLEN], dummy;
1829         int source_char, mask_char;
1830         int count;
1831         Lisp_Object foreground, background;
1832
1833         if (!DEVICE_X_P(XDEVICE(device)))
1834                 signal_simple_error("Not an X device", device);
1835
1836         dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1837
1838         if (!STRINGP(data) || strncmp("FONT ", (char *)XSTRING_DATA(data), 5))
1839                 signal_simple_error("Invalid font-glyph instantiator",
1840                                     instantiator);
1841
1842         if (!(dest_mask & IMAGE_POINTER_MASK))
1843                 incompatible_image_types(instantiator, dest_mask,
1844                                          IMAGE_POINTER_MASK);
1845
1846         foreground = find_keyword_in_vector(instantiator, Q_foreground);
1847         if (NILP(foreground))
1848                 foreground = pointer_fg;
1849         background = find_keyword_in_vector(instantiator, Q_background);
1850         if (NILP(background))
1851                 background = pointer_bg;
1852
1853         generate_cursor_fg_bg(device, &foreground, &background, &fg, &bg);
1854
1855         count = sscanf((char *)XSTRING_DATA(data),
1856                        "FONT %s %d %s %d %c",
1857                        source_name, &source_char,
1858                        mask_name, &mask_char, &dummy);
1859         /* Allow "%s %d %d" as well... */
1860         if (count == 3 && (1 == sscanf(mask_name, "%d %c", &mask_char, &dummy)))
1861                 count = 4, mask_name[0] = 0;
1862
1863         if (count != 2 && count != 4)
1864                 signal_simple_error("invalid cursor specification", data);
1865         source = safe_XLoadFont(dpy, source_name);
1866         if (!source)
1867                 signal_simple_error_2("couldn't load font",
1868                                       build_string(source_name), data);
1869         if (count == 2)
1870                 mask = 0;
1871         else if (!mask_name[0])
1872                 mask = source;
1873         else {
1874                 mask = safe_XLoadFont(dpy, mask_name);
1875                 if (!mask)
1876                         /* continuable */
1877                         Fsignal(Qerror,
1878                                 list3(build_string("couldn't load font"),
1879                                       build_string(mask_name), data));
1880         }
1881         if (!mask)
1882                 mask_char = 0;
1883
1884         /* #### call XQueryTextExtents() and check_pointer_sizes() here. */
1885
1886         x_initialize_pixmap_image_instance(ii, 1, IMAGE_POINTER);
1887         IMAGE_INSTANCE_X_CURSOR(ii) =
1888             XCreateGlyphCursor(dpy, source, mask, source_char, mask_char,
1889                                &fg, &bg);
1890         XIMAGE_INSTANCE_PIXMAP_FG(image_instance) = foreground;
1891         XIMAGE_INSTANCE_PIXMAP_BG(image_instance) = background;
1892         XUnloadFont(dpy, source);
1893         if (mask && mask != source)
1894                 XUnloadFont(dpy, mask);
1895 }
1896 \f
1897 /**********************************************************************
1898  *                           Cursor-Font                              *
1899  **********************************************************************/
1900
1901 static void cursor_font_validate(Lisp_Object instantiator)
1902 {
1903         data_must_be_present(instantiator);
1904 }
1905
1906 static int cursor_font_possible_dest_types(void)
1907 {
1908         return IMAGE_POINTER_MASK;
1909 }
1910
1911 static void
1912 cursor_font_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
1913                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1914                         int dest_mask, Lisp_Object domain)
1915 {
1916         /* This function can GC */
1917         Lisp_Object data = find_keyword_in_vector(instantiator, Q_data);
1918         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
1919         Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
1920         Display *dpy;
1921         int i;
1922         const char *name_ext;
1923         Lisp_Object foreground, background;
1924
1925         if (!DEVICE_X_P(XDEVICE(device)))
1926                 signal_simple_error("Not an X device", device);
1927
1928         dpy = DEVICE_X_DISPLAY(XDEVICE(device));
1929
1930         if (!(dest_mask & IMAGE_POINTER_MASK))
1931                 incompatible_image_types(instantiator, dest_mask,
1932                                          IMAGE_POINTER_MASK);
1933
1934         LISP_STRING_TO_EXTERNAL(data, name_ext, Qfile_name);
1935         if ((i = XmuCursorNameToIndex(name_ext)) == -1)
1936                 signal_simple_error("Unrecognized cursor-font name", data);
1937
1938         x_initialize_pixmap_image_instance(ii, 1, IMAGE_POINTER);
1939         IMAGE_INSTANCE_X_CURSOR(ii) = XCreateFontCursor(dpy, i);
1940         foreground = find_keyword_in_vector(instantiator, Q_foreground);
1941         if (NILP(foreground))
1942                 foreground = pointer_fg;
1943         background = find_keyword_in_vector(instantiator, Q_background);
1944         if (NILP(background))
1945                 background = pointer_bg;
1946         maybe_recolor_cursor(image_instance, foreground, background);
1947 }
1948
1949 static int
1950 x_colorize_image_instance(Lisp_Object image_instance,
1951                           Lisp_Object foreground, Lisp_Object background)
1952 {
1953         Lisp_Image_Instance *p;
1954
1955         p = XIMAGE_INSTANCE(image_instance);
1956
1957         switch (IMAGE_INSTANCE_TYPE(p)) {
1958         case IMAGE_MONO_PIXMAP:
1959                 IMAGE_INSTANCE_TYPE(p) = IMAGE_COLOR_PIXMAP;
1960                 /* Make sure there aren't two pointers to the same mask, causing
1961                    it to get freed twice. */
1962                 IMAGE_INSTANCE_PIXMAP_MASK(p) = 0;
1963                 break;
1964
1965         case IMAGE_UNKNOWN:
1966         case IMAGE_NOTHING:
1967         case IMAGE_TEXT:
1968         case IMAGE_SUBWINDOW:
1969         case IMAGE_WIDGET:
1970         case IMAGE_COLOR_PIXMAP:
1971         case IMAGE_POINTER:
1972         default:
1973                 return 0;
1974         }
1975
1976         {
1977                 Display *dpy =
1978                     DEVICE_X_DISPLAY(XDEVICE(IMAGE_INSTANCE_DEVICE(p)));
1979                 Drawable draw =
1980                     XtWindow(DEVICE_XT_APP_SHELL
1981                              (XDEVICE(IMAGE_INSTANCE_DEVICE(p))));
1982                 Dimension d = DEVICE_X_DEPTH(XDEVICE(IMAGE_INSTANCE_DEVICE(p)));
1983                 Pixmap new = XCreatePixmap(dpy, draw,
1984                                            IMAGE_INSTANCE_PIXMAP_WIDTH(p),
1985                                            IMAGE_INSTANCE_PIXMAP_HEIGHT(p), d);
1986                 XColor color;
1987                 XGCValues gcv;
1988                 GC gc;
1989                 color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(foreground));
1990                 gcv.foreground = color.pixel;
1991                 color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(background));
1992                 gcv.background = color.pixel;
1993                 gc = XCreateGC(dpy, new, GCBackground | GCForeground, &gcv);
1994                 XCopyPlane(dpy, IMAGE_INSTANCE_X_PIXMAP(p), new, gc, 0, 0,
1995                            IMAGE_INSTANCE_PIXMAP_WIDTH(p),
1996                            IMAGE_INSTANCE_PIXMAP_HEIGHT(p), 0, 0, 1);
1997                 XFreeGC(dpy, gc);
1998                 IMAGE_INSTANCE_X_PIXMAP(p) = new;
1999                 IMAGE_INSTANCE_PIXMAP_DEPTH(p) = d;
2000                 IMAGE_INSTANCE_PIXMAP_FG(p) = foreground;
2001                 IMAGE_INSTANCE_PIXMAP_BG(p) = background;
2002                 return 1;
2003         }
2004 }
2005 \f
2006 /************************************************************************/
2007 /*                      subwindow and widget support                      */
2008 /************************************************************************/
2009
2010 /* unmap the image if it is a widget. This is used by redisplay via
2011    redisplay_unmap_subwindows */
2012 static void x_unmap_subwindow(Lisp_Image_Instance * p)
2013 {
2014         if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
2015                 XUnmapWindow
2016                     (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2017                      IMAGE_INSTANCE_X_CLIPWINDOW(p));
2018         } else {                /* must be a widget */
2019
2020                 /* Since we are being unmapped we want the enclosing frame to
2021                    get focus. The losing with simple scrolling but is the safest
2022                    thing to do. */
2023                 emacs_Xt_handle_widget_losing_focus
2024                         (XFRAME(IMAGE_INSTANCE_FRAME(p)),
2025                          IMAGE_INSTANCE_X_WIDGET_ID(p));
2026                 XtUnmapWidget(IMAGE_INSTANCE_X_CLIPWIDGET(p));
2027         }
2028 }
2029
2030 /* map the subwindow. This is used by redisplay via
2031    redisplay_output_subwindow */
2032 static void
2033 x_map_subwindow(Lisp_Image_Instance * p, int x, int y,
2034                 struct display_glyph_area *dga)
2035 {
2036         assert(dga->width > 0 && dga->height > 0);
2037         if (IMAGE_INSTANCE_TYPE(p) == IMAGE_SUBWINDOW) {
2038                 Window subwindow = IMAGE_INSTANCE_X_SUBWINDOW_ID(p);
2039                 XMoveResizeWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2040                                   IMAGE_INSTANCE_X_CLIPWINDOW(p),
2041                                   x, y, dga->width, dga->height);
2042                 XMoveWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2043                             subwindow, -dga->xoffset, -dga->yoffset);
2044                 if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(p))
2045                         XMapWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2046                                    IMAGE_INSTANCE_X_CLIPWINDOW(p));
2047         } else {                /* must be a widget */
2048
2049                 XtConfigureWidget(IMAGE_INSTANCE_X_CLIPWIDGET(p),
2050                                   x + IMAGE_INSTANCE_X_WIDGET_XOFFSET(p),
2051                                   y + IMAGE_INSTANCE_X_WIDGET_YOFFSET(p),
2052                                   dga->width, dga->height, 0);
2053                 XtMoveWidget(IMAGE_INSTANCE_X_WIDGET_ID(p),
2054                              -dga->xoffset, -dga->yoffset);
2055                 if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP(p))
2056                         XtMapWidget(IMAGE_INSTANCE_X_CLIPWIDGET(p));
2057                 if (IMAGE_INSTANCE_WANTS_INITIAL_FOCUS(p)) {
2058                         /* #### FIXME to pop-up the find dialog we map the text-field
2059                            seven times! This doesn't show on a fast linux, though. */
2060                         enqueue_focus_event(IMAGE_INSTANCE_X_WIDGET_ID(p),
2061                                             IMAGE_INSTANCE_FRAME(p), 1);
2062                 }
2063         }
2064 }
2065
2066 /* when you click on a widget you may activate another widget this
2067    needs to be checked and all appropriate widgets updated */
2068 static void x_redisplay_subwindow(Lisp_Image_Instance * p)
2069 {
2070         /* Update the subwindow size if necessary. */
2071         if (IMAGE_INSTANCE_SIZE_CHANGED(p)) {
2072                 XResizeWindow(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(p),
2073                               IMAGE_INSTANCE_X_SUBWINDOW_ID(p),
2074                               IMAGE_INSTANCE_WIDTH(p),
2075                               IMAGE_INSTANCE_HEIGHT(p));
2076         }
2077 }
2078
2079 /* Update all attributes that have changed. Lwlib actually does most
2080    of this for us. */
2081 static void x_redisplay_widget(Lisp_Image_Instance * p)
2082 {
2083         /* This function can GC if IN_REDISPLAY is false. */
2084 #ifdef HAVE_WIDGETS
2085         widget_value *wv = 0;
2086
2087         /* First get the items if they have changed since this is a
2088            structural change. As such it will nuke all added values so we
2089            need to update most other things after the items have changed. */
2090         if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)) {
2091                 Lisp_Object image_instance;
2092
2093                 XSETIMAGE_INSTANCE(image_instance, p);
2094                 wv = gui_items_to_widget_values
2095                     (image_instance, IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(p),
2096                      /* #### this is not right; we need to keep track of which widgets
2097                         want accelerators and which don't */ 0);
2098                 wv->change = STRUCTURAL_CHANGE;
2099         } else {
2100                 /* Assume the lotus position, breath deeply and chant to
2101                    yourself lwlibsux, lwlibsux ... lw_get_all_values returns a
2102                    reference to the real values rather than a copy thus any
2103                    changes we make to the values we get back will look like they
2104                    have already been applied. If we rebuild the widget tree then
2105                    we may lose properties. */
2106                 wv = copy_widget_value_tree(lw_get_all_values
2107                                             (IMAGE_INSTANCE_X_WIDGET_LWID(p)),
2108                                             NO_CHANGE);
2109         }
2110
2111         /* Possibly update the colors and font */
2112         if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED(p)
2113             ||
2114             /* #### This is not sufficient because it will not cope with widgets
2115                that are not currently visible. Once redisplay has done the
2116                visible ones it will clear this flag so that when new ones
2117                become visible they will not be updated. */
2118             XFRAME(IMAGE_INSTANCE_FRAME(p))->faces_changed
2119             ||
2120             XFRAME(IMAGE_INSTANCE_FRAME(p))->frame_changed
2121             || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)) {
2122                 update_widget_face(wv, p, IMAGE_INSTANCE_FRAME(p));
2123         }
2124
2125         /* Possibly update the text. */
2126         if (IMAGE_INSTANCE_TEXT_CHANGED(p)) {
2127                 char *str;
2128                 Lisp_Object val = IMAGE_INSTANCE_WIDGET_TEXT(p);
2129                 LISP_STRING_TO_EXTERNAL(val, str, Qnative);
2130                 wv->value = str;
2131         }
2132
2133         /* Possibly update the size. */
2134         if (IMAGE_INSTANCE_SIZE_CHANGED(p)
2135             || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(p)
2136             || IMAGE_INSTANCE_TEXT_CHANGED(p)) {
2137                 assert(IMAGE_INSTANCE_X_WIDGET_ID(p) &&
2138                        IMAGE_INSTANCE_X_CLIPWIDGET(p));
2139
2140                 if (IMAGE_INSTANCE_X_WIDGET_ID(p)->core.being_destroyed
2141                     || !XtIsManaged(IMAGE_INSTANCE_X_WIDGET_ID(p))) {
2142                         Lisp_Object sw;
2143                         XSETIMAGE_INSTANCE(sw, p);
2144                         signal_simple_error("SXEmacs bug: subwindow is deleted",
2145                                             sw);
2146                 }
2147
2148                 lw_add_widget_value_arg(wv, XtNwidth,
2149                                         IMAGE_INSTANCE_WIDTH(p));
2150                 lw_add_widget_value_arg(wv, XtNheight,
2151                                         IMAGE_INSTANCE_HEIGHT(p));
2152         }
2153
2154         /* Adjust offsets within the frame. */
2155         if (XFRAME(IMAGE_INSTANCE_FRAME(p))->size_changed) {
2156                 Arg al[2];
2157                 XtSetArg(al[0], XtNx, &IMAGE_INSTANCE_X_WIDGET_XOFFSET(p));
2158                 XtSetArg(al[1], XtNy, &IMAGE_INSTANCE_X_WIDGET_YOFFSET(p));
2159                 XtGetValues(FRAME_X_TEXT_WIDGET
2160                             (XFRAME(IMAGE_INSTANCE_FRAME(p))), al, 2);
2161         }
2162
2163         /* now modify the widget */
2164         lw_modify_all_widgets(IMAGE_INSTANCE_X_WIDGET_LWID(p), wv, True);
2165         free_widget_value_tree(wv);
2166 #endif
2167 }
2168
2169 /* instantiate and x type subwindow */
2170 static void
2171 x_subwindow_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2172                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2173                         int dest_mask, Lisp_Object domain)
2174 {
2175         /* This function can GC */
2176         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2177         Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii);
2178         Lisp_Object frame = DOMAIN_FRAME(domain);
2179         struct frame *f = XFRAME(frame);
2180         Display *dpy;
2181         Screen *xs;
2182         Window pw, win;
2183         XSetWindowAttributes xswa;
2184         Mask valueMask = 0;
2185         unsigned int w = IMAGE_INSTANCE_WIDTH(ii),
2186             h = IMAGE_INSTANCE_HEIGHT(ii);
2187
2188         if (!DEVICE_X_P(XDEVICE(device)))
2189                 signal_simple_error("Not an X device", device);
2190
2191         dpy = DEVICE_X_DISPLAY(XDEVICE(device));
2192         xs = DefaultScreenOfDisplay(dpy);
2193
2194         IMAGE_INSTANCE_TYPE(ii) = IMAGE_SUBWINDOW;
2195
2196         pw = XtWindow(FRAME_X_TEXT_WIDGET(f));
2197
2198         ii->data = xnew_and_zero(struct x_subwindow_data);
2199
2200         IMAGE_INSTANCE_X_SUBWINDOW_PARENT(ii) = pw;
2201         IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(ii) = DisplayOfScreen(xs);
2202
2203         xswa.backing_store = Always;
2204         valueMask |= CWBackingStore;
2205         xswa.colormap = DefaultColormapOfScreen(xs);
2206         valueMask |= CWColormap;
2207
2208         /* Create a window for clipping */
2209         IMAGE_INSTANCE_X_CLIPWINDOW(ii) =
2210             XCreateWindow(dpy, pw, 0, 0, w, h, 0, CopyFromParent,
2211                           InputOutput, CopyFromParent, valueMask, &xswa);
2212
2213         /* Now put the subwindow inside the clip window. */
2214         win = XCreateWindow(dpy, IMAGE_INSTANCE_X_CLIPWINDOW(ii),
2215                             0, 0, w, h, 0, CopyFromParent,
2216                             InputOutput, CopyFromParent, valueMask, &xswa);
2217
2218         IMAGE_INSTANCE_SUBWINDOW_ID(ii) = (void *)win;
2219 }
2220
2221 /* Account for some of the limitations with widget images. */
2222 static int x_widget_border_width(void)
2223 {
2224         return DEFAULT_WIDGET_BORDER_WIDTH * 2;
2225 }
2226
2227 void
2228 x_subwindow_query_geometry(Lisp_Object image_instance,
2229                            int *width, int *height);
2230
2231 void
2232 x_subwindow_query_geometry(Lisp_Object image_instance,
2233                            int *width, int *height)
2234 {
2235         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2236         Window droot;
2237         int dx, dy;
2238         unsigned int dbdw, dd, dw = 20, dh = 20;
2239
2240         XGetGeometry(IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY(ii),
2241                      (Window)IMAGE_INSTANCE_SUBWINDOW_ID(ii),
2242                      &droot, &dx, &dy, &dw, &dh, &dbdw, &dd);
2243         if (width)
2244                 *width = dw;
2245         if (height)
2246                 *height = dh;
2247 }
2248
2249 #if 0
2250 /* #### Should this function exist? If there's any doubt I'm not implementing it --andyp */
2251 DEFUN("change-subwindow-property", Fchange_subwindow_property, 3, 3, 0, /*
2252 For the given SUBWINDOW, set PROPERTY to DATA, which is a string.
2253 Subwindows are not currently implemented.
2254 */
2255       (subwindow, property, data))
2256 {
2257         Atom property_atom;
2258         Lisp_Subwindow *sw;
2259         Display *dpy;
2260
2261         CHECK_SUBWINDOW(subwindow);
2262         CHECK_STRING(property);
2263         CHECK_STRING(data);
2264
2265         sw = XSUBWINDOW(subwindow);
2266         dpy = DisplayOfScreen(LISP_DEVICE_TO_X_SCREEN
2267                               (FRAME_DEVICE(XFRAME(sw->frame))));
2268
2269         property_atom = XInternAtom(dpy, (char *)XSTRING_DATA(property), False);
2270         XChangeProperty(dpy, sw->subwindow, property_atom, XA_STRING, 8,
2271                         PropModeReplace,
2272                         XSTRING_DATA(data), XSTRING_LENGTH(data));
2273
2274         return property;
2275 }
2276 #endif
2277 \f
2278 #ifdef HAVE_WIDGETS
2279
2280 /************************************************************************/
2281 /*                            widgets                            */
2282 /************************************************************************/
2283
2284 static void
2285 update_widget_face(widget_value * wv, Lisp_Image_Instance * ii,
2286                    Lisp_Object domain)
2287 {
2288 #ifdef LWLIB_WIDGETS_MOTIF
2289         XmFontList fontList;
2290 #endif
2291         /* Update the foreground. */
2292         Lisp_Object pixel = FACE_FOREGROUND(IMAGE_INSTANCE_WIDGET_FACE(ii),
2293                                             domain);
2294         XColor fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel)), bcolor;
2295         lw_add_widget_value_arg(wv, XtNforeground, fcolor.pixel);
2296
2297         /* Update the background. */
2298         pixel = FACE_BACKGROUND(IMAGE_INSTANCE_WIDGET_FACE(ii), domain);
2299         bcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2300         lw_add_widget_value_arg(wv, XtNbackground, bcolor.pixel);
2301
2302 #ifdef LWLIB_WIDGETS_MOTIF
2303         fontList = XmFontListCreate
2304                 (FONT_INSTANCE_X_FONT
2305                  (XFONT_INSTANCE(query_string_font
2306                                  (IMAGE_INSTANCE_WIDGET_TEXT(ii),
2307                                   IMAGE_INSTANCE_WIDGET_FACE(ii),
2308                                   domain))), XmSTRING_DEFAULT_CHARSET);
2309         lw_add_widget_value_arg(wv, XmNfontList, (XtArgVal) fontList);
2310 #endif
2311         {
2312                 Lisp_Object tmp = query_string_font(
2313                         IMAGE_INSTANCE_WIDGET_TEXT(ii),
2314                         IMAGE_INSTANCE_WIDGET_FACE(ii), domain);
2315                 lw_add_widget_value_arg(
2316                         wv, XtNfont,
2317                         (XtArgVal)FONT_INSTANCE_X_FONT(XFONT_INSTANCE(tmp)));
2318         }
2319         wv->change = VISIBLE_CHANGE;
2320         /* #### Megahack - but its just getting too complicated to do this
2321            in the right place. */
2322         if (EQ(IMAGE_INSTANCE_WIDGET_TYPE(ii), Qtab_control)) {
2323                 update_tab_widget_face(wv, ii, domain);
2324         }
2325         return;
2326 }
2327
2328 static void
2329 update_tab_widget_face(widget_value * wv, Lisp_Image_Instance * ii,
2330                        Lisp_Object domain)
2331 {
2332         if (wv->contents) {
2333                 widget_value *val = wv->contents, *cur;
2334
2335                 /* Give each child label the correct foreground color. */
2336                 Lisp_Object pixel = FACE_FOREGROUND
2337                     (IMAGE_INSTANCE_WIDGET_FACE(ii),
2338                      domain);
2339                 XColor fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2340                 lw_add_widget_value_arg(val, XtNtabForeground, fcolor.pixel);
2341                 wv->change = VISIBLE_CHANGE;
2342                 val->change = VISIBLE_CHANGE;
2343
2344                 for (cur = val->next; cur; cur = cur->next) {
2345                         cur->change = VISIBLE_CHANGE;
2346                         if (cur->value) {
2347                                 lw_copy_widget_value_args(val, cur);
2348                         }
2349                 }
2350         }
2351 }
2352
2353 static void
2354 x_widget_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2355                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2356                      int dest_mask, Lisp_Object domain,
2357                      const char *type, widget_value * wv)
2358 {
2359         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2360         Lisp_Object device = IMAGE_INSTANCE_DEVICE(ii), pixel;
2361         struct device *d = XDEVICE(device);
2362         Lisp_Object frame = DOMAIN_FRAME(domain);
2363         struct frame *f = XFRAME(frame);
2364         char *nm = 0;
2365         Widget wid;
2366         Arg al[32];
2367         int ac = 0;
2368         int id = new_lwlib_id();
2369         widget_value *clip_wv;
2370         XColor fcolor, bcolor;
2371
2372         if (!DEVICE_X_P(d))
2373                 signal_simple_error("Not an X device", device);
2374
2375         /* have to set the type this late in case there is no device
2376            instantiation for a widget. But we can go ahead and do it without
2377            checking because there is always a generic instantiator. */
2378         IMAGE_INSTANCE_TYPE(ii) = IMAGE_WIDGET;
2379
2380         if (!NILP(IMAGE_INSTANCE_WIDGET_TEXT(ii)))
2381                 LISP_STRING_TO_EXTERNAL(IMAGE_INSTANCE_WIDGET_TEXT(ii), nm,
2382                                         Qnative);
2383
2384         ii->data = xnew_and_zero(struct x_subwindow_data);
2385
2386         /* Create a clip window to contain the subwidget. Incredibly the
2387            SXEmacs manager seems to be the most appropriate widget for
2388            this. Nothing else is simple enough and yet does what is
2389            required. */
2390         clip_wv = xmalloc_widget_value();
2391
2392         lw_add_widget_value_arg(clip_wv, XtNresize, False);
2393         lw_add_widget_value_arg(clip_wv, XtNwidth,
2394                                 IMAGE_INSTANCE_WIDTH(ii));
2395         lw_add_widget_value_arg(clip_wv, XtNheight,
2396                                 IMAGE_INSTANCE_HEIGHT(ii));
2397         clip_wv->enabled = True;
2398
2399         clip_wv->name = xstrdup("clip-window");
2400         clip_wv->value = xstrdup("clip-window");
2401
2402         IMAGE_INSTANCE_X_CLIPWIDGET(ii)
2403             = lw_create_widget("clip-window", "clip-window", new_lwlib_id(),
2404                                clip_wv, FRAME_X_CONTAINER_WIDGET(f),
2405                                False, 0, 0, 0);
2406
2407         free_widget_value_tree(clip_wv);
2408
2409         /* create a sensible name. */
2410         if (wv->name == 0 || strcmp(wv->name, "") == 0)
2411                 wv->name = xstrdup(type);
2412
2413         /* copy any args we were given */
2414         ac = 0;
2415         lw_add_value_args_to_args(wv, al, &ac);
2416
2417         /* Fixup the colors. We have to do this *before* the widget gets
2418            created so that Motif will fix up the shadow colors
2419            correctly. Once the widget is created Motif won't do this
2420            anymore... */
2421         pixel = FACE_FOREGROUND
2422             (IMAGE_INSTANCE_WIDGET_FACE(ii), IMAGE_INSTANCE_FRAME(ii));
2423         fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2424
2425         pixel = FACE_BACKGROUND
2426             (IMAGE_INSTANCE_WIDGET_FACE(ii), IMAGE_INSTANCE_FRAME(ii));
2427         bcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(pixel));
2428
2429         lw_add_widget_value_arg(wv, XtNbackground, bcolor.pixel);
2430         lw_add_widget_value_arg(wv, XtNforeground, fcolor.pixel);
2431         /* we cannot allow widgets to resize themselves */
2432         lw_add_widget_value_arg(wv, XtNresize, False);
2433         lw_add_widget_value_arg(wv, XtNwidth, IMAGE_INSTANCE_WIDTH(ii));
2434         lw_add_widget_value_arg(wv, XtNheight, IMAGE_INSTANCE_HEIGHT(ii));
2435         /* update the font. */
2436         update_widget_face(wv, ii, domain);
2437
2438         wid =
2439             lw_create_widget(type, wv->name, id, wv,
2440                              IMAGE_INSTANCE_X_CLIPWIDGET(ii), False, 0,
2441                              popup_selection_callback, 0);
2442
2443         IMAGE_INSTANCE_SUBWINDOW_ID(ii) = (void *)wid;
2444         IMAGE_INSTANCE_X_WIDGET_LWID(ii) = id;
2445         /* because the EmacsManager is the widgets parent we have to
2446            offset the redisplay of the widget by the amount the text
2447            widget is inside the manager. */
2448         ac = 0;
2449         XtSetArg(al[ac], XtNx, &IMAGE_INSTANCE_X_WIDGET_XOFFSET(ii));
2450         ac++;
2451         XtSetArg(al[ac], XtNy, &IMAGE_INSTANCE_X_WIDGET_YOFFSET(ii));
2452         ac++;
2453         XtGetValues(FRAME_X_TEXT_WIDGET(f), al, ac);
2454
2455         XtSetMappedWhenManaged(wid, TRUE);
2456
2457         free_widget_value_tree(wv);
2458         /* A kludgy but simple way to make sure the callback for a widget
2459            doesn't get deleted. */
2460         gcpro_popup_callbacks(id);
2461 }
2462
2463 /* get properties of a control */
2464 static Lisp_Object
2465 x_widget_property(Lisp_Object image_instance, Lisp_Object prop)
2466 {
2467         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2468         /* get the text from a control */
2469         if (EQ(prop, Q_text)) {
2470                 widget_value *wv =
2471                     lw_get_all_values(IMAGE_INSTANCE_X_WIDGET_LWID(ii));
2472                 return build_ext_string(wv->value, Qnative);
2473         }
2474         return Qunbound;
2475 }
2476
2477 /* Instantiate a layout control for putting other widgets in. */
2478 static void
2479 x_native_layout_instantiate(Lisp_Object image_instance,
2480                             Lisp_Object instantiator, Lisp_Object pointer_fg,
2481                             Lisp_Object pointer_bg, int dest_mask,
2482                             Lisp_Object domain)
2483 {
2484         x_widget_instantiate(image_instance, instantiator, pointer_fg,
2485                              pointer_bg, dest_mask, domain, "layout", 0);
2486 }
2487
2488 /* Instantiate a button widget. Unfortunately instantiated widgets are
2489    particular to a frame since they need to have a parent. It's not
2490    like images where you just select the image into the context you
2491    want to display it in and BitBlt it. So images instances can have a
2492    many-to-one relationship with things you see, whereas widgets can
2493    only be one-to-one (i.e. per frame) */
2494 static void
2495 x_button_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2496                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2497                      int dest_mask, Lisp_Object domain)
2498 {
2499         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2500         Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2501         Lisp_Object glyph = find_keyword_in_vector(instantiator, Q_image);
2502         widget_value *wv = gui_items_to_widget_values(image_instance, gui, 1);
2503
2504         if (!NILP(glyph)) {
2505                 if (!IMAGE_INSTANCEP(glyph))
2506                         glyph =
2507                             glyph_image_instance(glyph, domain, ERROR_ME, 1);
2508         }
2509
2510         x_widget_instantiate(image_instance, instantiator, pointer_fg,
2511                              pointer_bg, dest_mask, domain, "button", wv);
2512
2513         /* add the image if one was given */
2514         if (!NILP(glyph) && IMAGE_INSTANCEP(glyph)
2515             && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(glyph))) {
2516                 Arg al[2];
2517                 int ac = 0;
2518 #ifdef LWLIB_WIDGETS_MOTIF
2519                 XtSetArg(al[ac], XmNlabelType, XmPIXMAP);
2520                 ac++;
2521                 XtSetArg(al[ac], XmNlabelPixmap,
2522                          XIMAGE_INSTANCE_X_PIXMAP(glyph));
2523                 ac++;
2524 #else
2525                 XtSetArg(al[ac], XtNpixmap, XIMAGE_INSTANCE_X_PIXMAP(glyph));
2526                 ac++;
2527 #endif
2528                 XtSetValues(IMAGE_INSTANCE_X_WIDGET_ID(ii), al, ac);
2529         }
2530 }
2531
2532 /* Update a button's clicked state.
2533
2534    #### This is overkill, but it works. Right now this causes all
2535    button instances to flash for some reason buried deep in lwlib. In
2536    theory this should be the Right Thing to do since lwlib should only
2537    merge in changed values - and if nothing has changed then nothing
2538    should get done. This may be because of the args stuff,
2539    i.e. although the arg contents may be the same the args look
2540    different and so are re-applied to the widget. */
2541 static void x_button_redisplay(Lisp_Object image_instance)
2542 {
2543         /* This function can GC if IN_REDISPLAY is false. */
2544         Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
2545         widget_value *wv = gui_items_to_widget_values(image_instance,
2546                                                       IMAGE_INSTANCE_WIDGET_ITEMS
2547                                                       (p), 1);
2548
2549         /* now modify the widget */
2550         lw_modify_all_widgets(IMAGE_INSTANCE_X_WIDGET_LWID(p), wv, True);
2551         free_widget_value_tree(wv);
2552 }
2553
2554 /* get properties of a button */
2555 static Lisp_Object
2556 x_button_property(Lisp_Object image_instance, Lisp_Object prop)
2557 {
2558         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2559         /* check the state of a button */
2560         if (EQ(prop, Q_selected)) {
2561                 widget_value *wv =
2562                     lw_get_all_values(IMAGE_INSTANCE_X_WIDGET_LWID(ii));
2563
2564                 if (wv->selected)
2565                         return Qt;
2566                 else
2567                         return Qnil;
2568         }
2569         return Qunbound;
2570 }
2571
2572 /* instantiate a progress gauge */
2573 static void
2574 x_progress_gauge_instantiate(Lisp_Object image_instance,
2575                              Lisp_Object instantiator, Lisp_Object pointer_fg,
2576                              Lisp_Object pointer_bg, int dest_mask,
2577                              Lisp_Object domain)
2578 {
2579         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2580         Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2581         widget_value *wv = gui_items_to_widget_values(image_instance, gui, 0);
2582
2583         x_widget_instantiate(image_instance, instantiator, pointer_fg,
2584                              pointer_bg, dest_mask, domain, "progress", wv);
2585 }
2586
2587 /* set the properties of a progress gauge */
2588 static void x_progress_gauge_redisplay(Lisp_Object image_instance)
2589 {
2590         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2591
2592         if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)) {
2593                 Arg al[1];
2594                 Lisp_Object val;
2595 #ifdef ERROR_CHECK_GLYPHS
2596                 assert(GUI_ITEMP(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)));
2597 #endif
2598                 val = XGUI_ITEM(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii))->value;
2599                 XtSetArg(al[0], XtNvalue, XINT(val));
2600                 XtSetValues(IMAGE_INSTANCE_X_WIDGET_ID(ii), al, 1);
2601         }
2602 }
2603
2604 /* instantiate an edit control */
2605 static void
2606 x_edit_field_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2607                          Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2608                          int dest_mask, Lisp_Object domain)
2609 {
2610         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2611         Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2612         widget_value *wv = gui_items_to_widget_values(image_instance, gui, 0);
2613
2614         x_widget_instantiate(image_instance, instantiator, pointer_fg,
2615                              pointer_bg, dest_mask, domain, "text-field", wv);
2616 }
2617
2618 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2619 /* instantiate a combo control */
2620 static void
2621 x_combo_box_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2622                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2623                         int dest_mask, Lisp_Object domain)
2624 {
2625         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2626         widget_value *wv = 0;
2627         /* This is not done generically because of sizing problems under
2628            mswindows. REVISE ME: We don't support windows, so? */
2629         widget_instantiate(image_instance, instantiator, pointer_fg,
2630                            pointer_bg, dest_mask, domain);
2631
2632         wv = gui_items_to_widget_values(image_instance,
2633                                         IMAGE_INSTANCE_WIDGET_ITEMS(ii), 0);
2634
2635         x_widget_instantiate(image_instance, instantiator, pointer_fg,
2636                              pointer_bg, dest_mask, domain, "combo-box", wv);
2637 }
2638 #endif
2639
2640 static void
2641 x_tab_control_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2642                           Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2643                           int dest_mask, Lisp_Object domain)
2644 {
2645         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2646         widget_value *wv = gui_items_to_widget_values(image_instance,
2647                                                       IMAGE_INSTANCE_WIDGET_ITEMS
2648                                                       (ii), 0);
2649         update_tab_widget_face(wv, ii, IMAGE_INSTANCE_FRAME(ii));
2650         x_widget_instantiate(image_instance, instantiator, pointer_fg,
2651                              pointer_bg, dest_mask, domain, "tab-control", wv);
2652 }
2653
2654 /* Set the properties of a tab control */
2655 static void x_tab_control_redisplay(Lisp_Object image_instance)
2656 {
2657         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2658
2659         if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)
2660             || IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED(ii)) {
2661                 /* If only the order has changed then simply select the first
2662                    one of the pending set. This stops horrendous rebuilding -
2663                    and hence flicker - of the tabs each time you click on
2664                    one. */
2665                 if (tab_control_order_only_changed(image_instance)) {
2666                         Lisp_Object rest, selected =
2667                             gui_item_list_find_selected
2668                             (NILP(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)) ?
2669                              XCDR(IMAGE_INSTANCE_WIDGET_ITEMS(ii)) :
2670                              XCDR(IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)));
2671
2672                         LIST_LOOP(rest, XCDR(IMAGE_INSTANCE_WIDGET_ITEMS(ii))) {
2673                                 if (gui_item_equal_sans_selected
2674                                     (XCAR(rest), selected, 0)) {
2675                                         /* There may be an encapsulated way of doing this,
2676                                            but I couldn't find it. */
2677                                         Lisp_Object old_selected =
2678                                             gui_item_list_find_selected(XCDR
2679                                                                         (IMAGE_INSTANCE_WIDGET_ITEMS
2680                                                                          (ii)));
2681                                         Arg al[2];
2682                                         char *name;
2683                                         unsigned int num_children, i;
2684                                         Widget *children;
2685
2686                                         LISP_STRING_TO_EXTERNAL(XGUI_ITEM
2687                                                                 (XCAR(rest))->
2688                                                                 name, name,
2689                                                                 Qnative);
2690                                         /* The name may contain a `.' which confuses
2691                                            XtNameToWidget, so we do it ourselves. */
2692                                         children =
2693                                             XtCompositeChildren
2694                                             (IMAGE_INSTANCE_X_WIDGET_ID(ii),
2695                                              &num_children);
2696                                         for (i = 0; i < num_children; i++) {
2697                                                 if (!strcmp
2698                                                     (XtName(children[i]),
2699                                                      name)) {
2700                                                         XtSetArg(al[0],
2701                                                                  XtNtopWidget,
2702                                                                  children[i]);
2703                                                         XtSetArg(al[1],
2704                                                                  XtNhighlightWidget,
2705                                                                  children[i]);
2706                                                         XtSetValues
2707                                                             (IMAGE_INSTANCE_X_WIDGET_ID
2708                                                              (ii), al, 2);
2709                                                         break;
2710                                                 }
2711                                         }
2712                                         /* Pick up the new selected item. */
2713                                         XGUI_ITEM(old_selected)->selected =
2714                                             XGUI_ITEM(XCAR(rest))->selected;
2715                                         XGUI_ITEM(XCAR(rest))->selected =
2716                                             XGUI_ITEM(selected)->selected;
2717                                         /* We're not actually changing the items anymore. */
2718                                         IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)
2719                                             = 0;
2720                                         IMAGE_INSTANCE_WIDGET_PENDING_ITEMS(ii)
2721                                             = Qnil;
2722                                         break;
2723                                 }
2724                         }
2725                 }
2726         }
2727         /* Possibly update the face. */
2728         if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED(ii)
2729             ||
2730             XFRAME(IMAGE_INSTANCE_FRAME(ii))->faces_changed
2731             || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED(ii)) {
2732                 /* See previous comments on the brokeness of lwlib.
2733
2734                    #### There's actually not much point in doing this here
2735                    since, colors will have been set appropriately by
2736                    x_redisplay_widget. */
2737                 widget_value *wv = copy_widget_value_tree
2738                     (lw_get_all_values(IMAGE_INSTANCE_X_WIDGET_LWID(ii)),
2739                      NO_CHANGE);
2740
2741                 update_tab_widget_face(wv, ii, IMAGE_INSTANCE_FRAME(ii));
2742
2743                 lw_modify_all_widgets(IMAGE_INSTANCE_X_WIDGET_LWID(ii), wv,
2744                                       True);
2745                 free_widget_value_tree(wv);
2746         }
2747 }
2748
2749 /* instantiate a static control possible for putting other things in */
2750 static void
2751 x_label_instantiate(Lisp_Object image_instance, Lisp_Object instantiator,
2752                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2753                     int dest_mask, Lisp_Object domain)
2754 {
2755         Lisp_Image_Instance *ii = XIMAGE_INSTANCE(image_instance);
2756         Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM(ii);
2757         widget_value *wv = gui_items_to_widget_values(image_instance, gui, 0);
2758
2759         x_widget_instantiate(image_instance, instantiator, pointer_fg,
2760                              pointer_bg, dest_mask, domain, "button", wv);
2761 }
2762 #endif                          /* HAVE_WIDGETS */
2763 \f
2764 /************************************************************************/
2765 /*                            initialization                            */
2766 /************************************************************************/
2767
2768 void syms_of_glyphs_x(void)
2769 {
2770 #if 0
2771         DEFSUBR(Fchange_subwindow_property);
2772 #endif
2773 }
2774
2775 void console_type_create_glyphs_x(void)
2776 {
2777         /* image methods */
2778
2779         CONSOLE_HAS_METHOD(x, print_image_instance);
2780         CONSOLE_HAS_METHOD(x, finalize_image_instance);
2781         CONSOLE_HAS_METHOD(x, image_instance_equal);
2782         CONSOLE_HAS_METHOD(x, image_instance_hash);
2783         CONSOLE_HAS_METHOD(x, colorize_image_instance);
2784         CONSOLE_HAS_METHOD(x, init_image_instance_from_eimage);
2785         CONSOLE_HAS_METHOD(x, locate_pixmap_file);
2786         CONSOLE_HAS_METHOD(x, unmap_subwindow);
2787         CONSOLE_HAS_METHOD(x, map_subwindow);
2788         CONSOLE_HAS_METHOD(x, redisplay_widget);
2789         CONSOLE_HAS_METHOD(x, redisplay_subwindow);
2790         CONSOLE_HAS_METHOD(x, widget_border_width);
2791 }
2792
2793 void image_instantiator_format_create_glyphs_x(void)
2794 {
2795         IIFORMAT_VALID_CONSOLE(x, nothing);
2796         IIFORMAT_VALID_CONSOLE(x, string);
2797 #ifdef HAVE_WIDGETS
2798         IIFORMAT_VALID_CONSOLE(x, layout);
2799 #endif
2800         IIFORMAT_VALID_CONSOLE(x, formatted_string);
2801         IIFORMAT_VALID_CONSOLE(x, inherit);
2802 #ifdef HAVE_XPM
2803         INITIALIZE_DEVICE_IIFORMAT(x, xpm);
2804         IIFORMAT_HAS_DEVMETHOD(x, xpm, instantiate);
2805 #endif
2806 #ifdef HAVE_JPEG
2807         IIFORMAT_VALID_CONSOLE(x, jpeg);
2808 #endif
2809 #ifdef HAVE_TIFF
2810         IIFORMAT_VALID_CONSOLE(x, tiff);
2811 #endif
2812 #if defined WITH_PNG && defined HAVE_PNG
2813         IIFORMAT_VALID_CONSOLE(x, png);
2814 #endif
2815 #ifdef HAVE_GIF
2816         IIFORMAT_VALID_CONSOLE(x, gif);
2817 #endif
2818 #if 1
2819         IIFORMAT_VALID_CONSOLE(x, rawrgb);
2820         IIFORMAT_VALID_CONSOLE(x, rawrgba);
2821 #endif
2822
2823         INITIALIZE_DEVICE_IIFORMAT(x, xbm);
2824         IIFORMAT_HAS_DEVMETHOD(x, xbm, instantiate);
2825
2826         INITIALIZE_DEVICE_IIFORMAT(x, subwindow);
2827         IIFORMAT_HAS_DEVMETHOD(x, subwindow, instantiate);
2828 #ifdef HAVE_WIDGETS
2829         /* layout widget */
2830         INITIALIZE_DEVICE_IIFORMAT(x, native_layout);
2831         IIFORMAT_HAS_DEVMETHOD(x, native_layout, instantiate);
2832         /* button widget */
2833         INITIALIZE_DEVICE_IIFORMAT(x, button);
2834         IIFORMAT_HAS_DEVMETHOD(x, button, property);
2835         IIFORMAT_HAS_DEVMETHOD(x, button, instantiate);
2836         IIFORMAT_HAS_DEVMETHOD(x, button, redisplay);
2837         /* general widget methods. */
2838         INITIALIZE_DEVICE_IIFORMAT(x, widget);
2839         IIFORMAT_HAS_DEVMETHOD(x, widget, property);
2840         /* progress gauge */
2841         INITIALIZE_DEVICE_IIFORMAT(x, progress_gauge);
2842         IIFORMAT_HAS_DEVMETHOD(x, progress_gauge, redisplay);
2843         IIFORMAT_HAS_DEVMETHOD(x, progress_gauge, instantiate);
2844         /* text field */
2845         INITIALIZE_DEVICE_IIFORMAT(x, edit_field);
2846         IIFORMAT_HAS_DEVMETHOD(x, edit_field, instantiate);
2847 #if defined (LWLIB_WIDGETS_MOTIF) && XmVERSION > 1
2848         /* combo box */
2849         INITIALIZE_DEVICE_IIFORMAT(x, combo_box);
2850         IIFORMAT_HAS_DEVMETHOD(x, combo_box, instantiate);
2851         IIFORMAT_HAS_SHARED_DEVMETHOD(x, combo_box, redisplay, tab_control);
2852 #endif
2853         /* tab control widget */
2854         INITIALIZE_DEVICE_IIFORMAT(x, tab_control);
2855         IIFORMAT_HAS_DEVMETHOD(x, tab_control, instantiate);
2856         IIFORMAT_HAS_DEVMETHOD(x, tab_control, redisplay);
2857         /* label */
2858         INITIALIZE_DEVICE_IIFORMAT(x, label);
2859         IIFORMAT_HAS_DEVMETHOD(x, label, instantiate);
2860 #endif
2861         INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(cursor_font, "cursor-font");
2862         IIFORMAT_VALID_CONSOLE(x, cursor_font);
2863
2864         IIFORMAT_HAS_METHOD(cursor_font, validate);
2865         IIFORMAT_HAS_METHOD(cursor_font, possible_dest_types);
2866         IIFORMAT_HAS_METHOD(cursor_font, instantiate);
2867
2868         IIFORMAT_VALID_KEYWORD(cursor_font, Q_data, check_valid_string);
2869         IIFORMAT_VALID_KEYWORD(cursor_font, Q_foreground, check_valid_string);
2870         IIFORMAT_VALID_KEYWORD(cursor_font, Q_background, check_valid_string);
2871
2872         INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(font, "font");
2873
2874         IIFORMAT_HAS_METHOD(font, validate);
2875         IIFORMAT_HAS_METHOD(font, possible_dest_types);
2876         IIFORMAT_HAS_METHOD(font, instantiate);
2877         IIFORMAT_VALID_CONSOLE(x, font);
2878
2879         IIFORMAT_VALID_KEYWORD(font, Q_data, check_valid_string);
2880         IIFORMAT_VALID_KEYWORD(font, Q_foreground, check_valid_string);
2881         IIFORMAT_VALID_KEYWORD(font, Q_background, check_valid_string);
2882
2883 #ifdef HAVE_XFACE
2884         INITIALIZE_DEVICE_IIFORMAT(x, xface);
2885         IIFORMAT_HAS_DEVMETHOD(x, xface, instantiate);
2886 #endif
2887
2888         INITIALIZE_IMAGE_INSTANTIATOR_FORMAT(autodetect, "autodetect");
2889
2890         IIFORMAT_HAS_METHOD(autodetect, validate);
2891         IIFORMAT_HAS_METHOD(autodetect, normalize);
2892         IIFORMAT_HAS_METHOD(autodetect, possible_dest_types);
2893         /* #### autodetect is flawed IMO: 
2894            1. It makes the assumption that you can detect whether the user
2895            wanted a cursor or a string based on the data, since the data is a
2896            string you have to prioritise cursors. Instead we will force users
2897            to pick the appropriate image type, this is what we do under
2898            MS-Windows anyway.
2899            2. It doesn't fit with the new domain model - you cannot tell which
2900            domain it needs to be instantiated in until you've actually
2901            instantiated it, which mucks up caching.
2902            3. It only copes with cursors and strings which seems bogus. */
2903         IIFORMAT_HAS_SHARED_METHOD(autodetect, governing_domain, subwindow);
2904         IIFORMAT_HAS_METHOD(autodetect, instantiate);
2905         IIFORMAT_VALID_CONSOLE(x, autodetect);
2906
2907         IIFORMAT_VALID_KEYWORD(autodetect, Q_data, check_valid_string);
2908 }
2909
2910 void vars_of_glyphs_x(void)
2911 {
2912         DEFVAR_LISP("x-bitmap-file-path", &Vx_bitmap_file_path  /*
2913 A list of the directories in which X bitmap files may be found.
2914 If nil, this is initialized from the "*bitmapFilePath" resource.
2915 This is used by the `make-image-instance' function (however, note that if
2916 the environment variable XBMLANGPATH is set, it is consulted first).
2917                                                                  */ );
2918         Vx_bitmap_file_path = Qnil;
2919 }
2920
2921 void complex_vars_of_glyphs_x(void)
2922 {
2923 #define BUILD_GLYPH_INST(variable, name)                        \
2924   Fadd_spec_to_specifier                                        \
2925     (GLYPH_IMAGE (XGLYPH (variable)),                           \
2926      vector3 (Qxbm, Q_data,                                     \
2927               list3 (make_int (name##_width),                   \
2928                      make_int (name##_height),                  \
2929                      make_ext_string ((Extbyte *) name##_bits,  \
2930                                       sizeof (name##_bits),     \
2931                                       Qbinary))),               \
2932      Qglobal, Qx, Qnil)
2933
2934         BUILD_GLYPH_INST(Vtruncation_glyph, truncator);
2935         BUILD_GLYPH_INST(Vcontinuation_glyph, continuer);
2936         BUILD_GLYPH_INST(Vsxemacs_logo, sxemacs);
2937         BUILD_GLYPH_INST(Vhscroll_glyph, hscroll);
2938
2939 #undef BUILD_GLYPH_INST
2940 }