This commit was generated by cvs2svn to compensate for changes in r5670,
[chise/xemacs-chise.git.1] / src / glyphs-gtk.c
1 /* X-specific Lisp objects.
2    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3    Copyright (C) 1995 Board of Trustees, University of Illinois.
4    Copyright (C) 1995 Tinker Systems
5    Copyright (C) 1995, 1996 Ben Wing
6    Copyright (C) 1995 Sun Microsystems
7
8 This file is part of XEmacs.
9
10 XEmacs is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2, or (at your option) any
13 later version.
14
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with XEmacs; see the file COPYING.  If not, write to
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA.  */
24
25 /* Synched up with: Not in FSF. */
26
27 /* Original author: Jamie Zawinski for 19.8
28    font-truename stuff added by Jamie Zawinski for 19.10
29    subwindow support added by Chuck Thompson
30    additional XPM support added by Chuck Thompson
31    initial X-Face support added by Stig
32    rewritten/restructured by Ben Wing for 19.12/19.13
33    GIF/JPEG support added by Ben Wing for 19.14
34    PNG support added by Bill Perry for 19.14
35    Improved GIF/JPEG support added by Bill Perry for 19.14
36    Cleanup/simplification of error handling by Ben Wing for 19.14
37    Pointer/icon overhaul, more restructuring by Ben Wing for 19.14
38    GIF support changed to external GIFlib 3.1 by Jareth Hein for 21.0
39    Many changes for color work and optimizations by Jareth Hein for 21.0
40    Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0
41    TIFF code by Jareth Hein for 21.0
42    GIF/JPEG/PNG/TIFF code moved to new glyph-eimage.c for 21.0
43    Gtk version by William Perry for 21.1
44
45    TODO:
46    Support the GrayScale, StaticColor and StaticGray visual classes.
47    Convert images.el to C and stick it in here?
48  */
49
50 #include <config.h>
51 #include "lisp.h"
52 #include "lstream.h"
53 #include "console-gtk.h"
54 #include "glyphs.h"
55 #include "glyphs-gtk.h"
56 #include "objects-gtk.h"
57 #include "gui-gtk.h"
58 #include "ui-gtk.h"
59
60 #include "buffer.h"
61 #include "window.h"
62 #include "frame.h"
63 #include "insdel.h"
64 #include "opaque.h"
65 #include "faces.h"
66
67 #include "imgproc.h"
68
69 #include "sysfile.h"
70
71 #include <setjmp.h>
72
73 #ifdef FILE_CODING
74 #include "file-coding.h"
75 #endif
76
77 #if INTBITS == 32
78 # define FOUR_BYTE_TYPE unsigned int
79 #elif LONGBITS == 32
80 # define FOUR_BYTE_TYPE unsigned long
81 #elif SHORTBITS == 32
82 # define FOUR_BYTE_TYPE unsigned short
83 #else
84 #error What kind of strange-ass system are we running on?
85 #endif
86
87 DECLARE_IMAGE_INSTANTIATOR_FORMAT (nothing);
88 DECLARE_IMAGE_INSTANTIATOR_FORMAT (string);
89 DECLARE_IMAGE_INSTANTIATOR_FORMAT (formatted_string);
90 DECLARE_IMAGE_INSTANTIATOR_FORMAT (inherit);
91 #ifdef HAVE_JPEG
92 DECLARE_IMAGE_INSTANTIATOR_FORMAT (jpeg);
93 #endif
94 #ifdef HAVE_TIFF
95 DECLARE_IMAGE_INSTANTIATOR_FORMAT (tiff);
96 #endif
97 #ifdef HAVE_PNG
98 DECLARE_IMAGE_INSTANTIATOR_FORMAT (png);
99 #endif
100 #ifdef HAVE_GIF
101 DECLARE_IMAGE_INSTANTIATOR_FORMAT (gif);
102 #endif
103
104 #ifdef HAVE_XFACE
105 DEFINE_DEVICE_IIFORMAT (gtk, xface);
106 Lisp_Object Qxface;
107 #endif
108
109 #ifdef HAVE_XPM
110 DEFINE_DEVICE_IIFORMAT (gtk, xpm);
111 #endif
112
113 DEFINE_DEVICE_IIFORMAT (gtk, xbm);
114 DEFINE_DEVICE_IIFORMAT (gtk, subwindow);
115
116 DEFINE_IMAGE_INSTANTIATOR_FORMAT (cursor_font);
117 Lisp_Object Qcursor_font;
118
119 DEFINE_IMAGE_INSTANTIATOR_FORMAT (font);
120
121 DEFINE_IMAGE_INSTANTIATOR_FORMAT (autodetect);
122
123 #ifdef HAVE_WIDGETS
124 DECLARE_IMAGE_INSTANTIATOR_FORMAT (layout);
125 DEFINE_DEVICE_IIFORMAT (gtk, widget);
126 DEFINE_DEVICE_IIFORMAT (gtk, native_layout);
127 DEFINE_DEVICE_IIFORMAT (gtk, button);
128 DEFINE_DEVICE_IIFORMAT (gtk, progress_gauge);
129 DEFINE_DEVICE_IIFORMAT (gtk, edit_field);
130 DEFINE_DEVICE_IIFORMAT (gtk, combo_box);
131 DEFINE_DEVICE_IIFORMAT (gtk, tab_control);
132 DEFINE_DEVICE_IIFORMAT (gtk, label);
133 #endif
134
135 static void update_widget_face (GtkWidget *w, Lisp_Image_Instance *ii,
136                                 Lisp_Object domain);
137 static void cursor_font_instantiate (Lisp_Object image_instance,
138                                      Lisp_Object instantiator,
139                                      Lisp_Object pointer_fg,
140                                      Lisp_Object pointer_bg,
141                                      int dest_mask,
142                                      Lisp_Object domain);
143
144 static gint cursor_name_to_index (const char *name);
145
146 #ifndef BitmapSuccess
147 #define BitmapSuccess           0
148 #define BitmapOpenFailed        1
149 #define BitmapFileInvalid       2
150 #define BitmapNoMemory          3
151 #endif
152
153 #include "bitmaps.h"
154
155 DEFINE_IMAGE_INSTANTIATOR_FORMAT (gtk_resource);
156 Lisp_Object Q_resource_type, Q_resource_id;
157 Lisp_Object Qgtk_resource;
158 #ifdef HAVE_WIDGETS
159 Lisp_Object Qgtk_widget_instantiate_internal, Qgtk_widget_property_internal;
160 Lisp_Object Qgtk_widget_redisplay_internal, Qgtk_widget_set_style;
161 #endif
162
163 #define CONST const
164
165 \f
166 /************************************************************************/
167 /*                      image instance methods                          */
168 /************************************************************************/
169
170 /************************************************************************/
171 /* convert from a series of RGB triples to an XImage formated for the   */
172 /* proper display                                                       */
173 /************************************************************************/
174 static GdkImage *
175 convert_EImage_to_GDKImage (Lisp_Object device, int width, int height,
176                             unsigned char *pic, unsigned long **pixtbl,
177                             int *npixels)
178 {
179   GdkColormap *cmap;
180   GdkVisual *vis;
181   GdkImage *outimg;
182   int depth, byte_cnt, i, j;
183   int rd,gr,bl,q;
184   unsigned char *data, *ip, *dp = NULL;
185   quant_table *qtable = NULL;
186   union {
187     FOUR_BYTE_TYPE val;
188     char cp[4];
189   } conv;
190
191   cmap = DEVICE_GTK_COLORMAP (XDEVICE(device));
192   vis = DEVICE_GTK_VISUAL (XDEVICE(device));
193   depth = DEVICE_GTK_DEPTH(XDEVICE(device));
194
195   if (vis->type == GDK_VISUAL_GRAYSCALE || vis->type == GDK_VISUAL_STATIC_COLOR ||
196       vis->type == GDK_VISUAL_STATIC_GRAY)
197     {
198       /* #### Implement me!!! */
199       return NULL;
200     }
201
202   if (vis->type == GDK_VISUAL_PSEUDO_COLOR)
203     {
204       /* Quantize the image and get a histogram while we're at it.
205          Do this first to save memory */
206       qtable = build_EImage_quantable(pic, width, height, 256);
207       if (qtable == NULL) return NULL;
208     }
209
210   /* The first parameter (GdkWindow *) is allowed to be NULL if we
211   ** specify the depth */
212   outimg = gdk_image_new (GDK_IMAGE_FASTEST, vis, width, height);
213
214   if (!outimg) return NULL;
215
216   byte_cnt = outimg->bpp;
217
218   data = (unsigned char *) outimg->mem;
219
220   if (!data)
221     {
222       gdk_image_destroy (outimg);
223       return NULL;
224     }
225   
226   if (vis->type == GDK_VISUAL_PSEUDO_COLOR)
227     {
228       unsigned long pixarray[256];
229       int pixcount, n;
230       /* use our quantize table to allocate the colors */
231       pixcount = 32;
232       *pixtbl = xnew_array (unsigned long, pixcount);
233       *npixels = 0;
234
235       /* ### should implement a sort by popularity to assure proper allocation */
236       n = *npixels;
237       for (i = 0; i < qtable->num_active_colors; i++)
238         {
239           GdkColor color;
240           int res;
241         
242           color.red = qtable->rm[i] ? qtable->rm[i] << 8 : 0;
243           color.green = qtable->gm[i] ? qtable->gm[i] << 8 : 0;
244           color.blue = qtable->bm[i] ? qtable->bm[i] << 8 : 0;
245           res = allocate_nearest_color (cmap, vis, &color);
246           if (res > 0 && res < 3)
247             {
248               DO_REALLOC(*pixtbl, pixcount, n+1, unsigned long);
249               (*pixtbl)[n] = color.pixel;
250               n++;
251             }
252           pixarray[i] = color.pixel;
253         }
254       *npixels = n;
255       ip = pic;
256       for (i = 0; i < height; i++)
257         {
258           dp = data + (i * outimg->bpl);
259           for (j = 0; j < width; j++)
260             {
261               rd = *ip++;
262               gr = *ip++;
263               bl = *ip++;
264               conv.val = pixarray[QUANT_GET_COLOR(qtable,rd,gr,bl)];
265 #if WORDS_BIGENDIAN
266               if (outimg->byte_order == GDK_MSB_FIRST)
267                 for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q];
268               else
269                 for (q = 3; q >= 4-byte_cnt; q--) *dp++ = conv.cp[q];
270 #else
271               if (outimg->byte_order == GDK_MSB_FIRST)
272                 for (q = byte_cnt-1; q >= 0; q--) *dp++ = conv.cp[q];
273               else
274                 for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q];
275 #endif
276             }
277         }
278       xfree(qtable);
279     } else {
280       unsigned long rshift,gshift,bshift,rbits,gbits,bbits,junk;
281       junk = vis->red_mask;
282       rshift = 0;
283       while ((junk & 0x1) == 0)
284         {
285           junk = junk >> 1;
286           rshift ++;
287         }
288       rbits = 0;
289       while (junk != 0)
290         {
291           junk = junk >> 1;
292           rbits++;
293         }
294       junk = vis->green_mask;
295       gshift = 0;
296       while ((junk & 0x1) == 0)
297         {
298           junk = junk >> 1;
299           gshift ++;
300         }
301       gbits = 0;
302       while (junk != 0)
303         {
304           junk = junk >> 1;
305           gbits++;
306         }
307       junk = vis->blue_mask;
308       bshift = 0;
309       while ((junk & 0x1) == 0)
310         {
311           junk = junk >> 1;
312           bshift ++;
313         }
314       bbits = 0;
315       while (junk != 0)
316         {
317           junk = junk >> 1;
318           bbits++;
319         }
320       ip = pic;
321       for (i = 0; i < height; i++)
322         {
323           dp = data + (i * outimg->bpl);
324           for (j = 0; j < width; j++)
325             {
326               if (rbits > 8)
327                 rd = *ip++ << (rbits - 8);
328               else
329                 rd = *ip++ >> (8 - rbits);
330               if (gbits > 8)
331                 gr = *ip++ << (gbits - 8);
332               else
333                 gr = *ip++ >> (8 - gbits);
334               if (bbits > 8)
335                 bl = *ip++ << (bbits - 8);
336               else
337                 bl = *ip++ >> (8 - bbits);
338
339               conv.val = (rd << rshift) | (gr << gshift) | (bl << bshift);
340 #if WORDS_BIGENDIAN
341               if (outimg->byte_order == GDK_MSB_FIRST)
342                 for (q = 4-byte_cnt; q < 4; q++) *dp++ = conv.cp[q];
343               else
344                 for (q = 3; q >= 4-byte_cnt; q--) *dp++ = conv.cp[q];
345 #else
346               if (outimg->byte_order == GDK_MSB_FIRST)
347                 for (q = byte_cnt-1; q >= 0; q--) *dp++ = conv.cp[q];
348               else
349                 for (q = 0; q < byte_cnt; q++) *dp++ = conv.cp[q];
350 #endif
351             }
352         }
353     }  
354   return outimg;
355 }
356
357 static void
358 gtk_print_image_instance (struct Lisp_Image_Instance *p,
359                           Lisp_Object printcharfun,
360                           int escapeflag)
361 {
362   char buf[100];
363
364   switch (IMAGE_INSTANCE_TYPE (p))
365     {
366     case IMAGE_MONO_PIXMAP:
367     case IMAGE_COLOR_PIXMAP:
368     case IMAGE_POINTER:
369       sprintf (buf, " (0x%lx", (unsigned long) IMAGE_INSTANCE_GTK_PIXMAP (p));
370       write_c_string (buf, printcharfun);
371       if (IMAGE_INSTANCE_GTK_MASK (p))
372         {
373           sprintf (buf, "/0x%lx", (unsigned long) IMAGE_INSTANCE_GTK_MASK (p));
374           write_c_string (buf, printcharfun);
375         }
376       write_c_string (")", printcharfun);
377       break;
378 #if HAVE_SUBWINDOWS
379     case IMAGE_SUBWINDOW:
380       /* #### implement me */
381 #endif
382     default:
383       break;
384     }
385 }
386
387 static void
388 gtk_finalize_image_instance (struct Lisp_Image_Instance *p)
389 {
390   if (!p->data)
391     return;
392
393   if (DEVICE_LIVE_P (XDEVICE (p->device)))
394     {
395       if (0)
396         ;
397 #ifdef HAVE_WIDGETS
398       if (IMAGE_INSTANCE_TYPE (p) == IMAGE_WIDGET)
399         {
400           if (IMAGE_INSTANCE_SUBWINDOW_ID (p))
401             {
402               gtk_widget_destroy (IMAGE_INSTANCE_SUBWINDOW_ID (p));
403
404               /* We can release the callbacks again. */
405               /* #### FIXME! */
406               /* ungcpro_popup_callbacks (...); */
407
408               /* IMAGE_INSTANCE_GTK_WIDGET_ID (p) = 0; */
409               IMAGE_INSTANCE_GTK_CLIPWIDGET (p) = 0;
410             }
411         }
412 #endif
413       else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
414         {
415           abort();
416         }
417       else
418         {
419           int i;
420           if (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p))
421             disable_glyph_animated_timeout (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p));
422
423           if (IMAGE_INSTANCE_GTK_MASK (p) &&
424               IMAGE_INSTANCE_GTK_MASK (p) != IMAGE_INSTANCE_GTK_PIXMAP (p))
425             gdk_pixmap_unref (IMAGE_INSTANCE_GTK_MASK (p));
426           IMAGE_INSTANCE_PIXMAP_MASK (p) = 0;
427
428           if (IMAGE_INSTANCE_GTK_PIXMAP_SLICES (p))
429             {
430               for (i = 0; i < IMAGE_INSTANCE_PIXMAP_MAXSLICE (p); i++)
431                 if (IMAGE_INSTANCE_GTK_PIXMAP_SLICE (p,i))
432                   {
433                     gdk_pixmap_unref (IMAGE_INSTANCE_GTK_PIXMAP_SLICE (p,i));
434                     IMAGE_INSTANCE_GTK_PIXMAP_SLICE (p, i) = 0;
435                   }
436               xfree (IMAGE_INSTANCE_GTK_PIXMAP_SLICES (p));
437               IMAGE_INSTANCE_GTK_PIXMAP_SLICES (p) = 0;
438             }
439
440           if (IMAGE_INSTANCE_GTK_CURSOR (p))
441             {
442               gdk_cursor_destroy (IMAGE_INSTANCE_GTK_CURSOR (p));
443               IMAGE_INSTANCE_GTK_CURSOR (p) = 0;
444             }
445         }
446
447 #if 0
448             /* #### BILL!!! */
449       if (IMAGE_INSTANCE_GTK_NPIXELS (p) != 0)
450         {
451           XFreeColors (dpy,
452                        IMAGE_INSTANCE_GTK_COLORMAP (p),
453                        IMAGE_INSTANCE_GTK_PIXELS (p),
454                        IMAGE_INSTANCE_GTK_NPIXELS (p), 0);
455           IMAGE_INSTANCE_GTK_NPIXELS (p) = 0;
456         }
457 #endif
458     }
459
460   if (IMAGE_INSTANCE_TYPE (p) != IMAGE_WIDGET
461       && IMAGE_INSTANCE_TYPE (p) != IMAGE_SUBWINDOW
462       && IMAGE_INSTANCE_GTK_PIXELS (p))
463     {
464       xfree (IMAGE_INSTANCE_GTK_PIXELS (p));
465       IMAGE_INSTANCE_GTK_PIXELS (p) = 0;
466     }
467
468   xfree (p->data);
469   p->data = 0;
470 }
471
472 static int
473 gtk_image_instance_equal (struct Lisp_Image_Instance *p1,
474                           struct Lisp_Image_Instance *p2, int depth)
475 {
476   switch (IMAGE_INSTANCE_TYPE (p1))
477     {
478     case IMAGE_MONO_PIXMAP:
479     case IMAGE_COLOR_PIXMAP:
480     case IMAGE_POINTER:
481       if (IMAGE_INSTANCE_GTK_COLORMAP (p1) != IMAGE_INSTANCE_GTK_COLORMAP (p2) ||
482           IMAGE_INSTANCE_GTK_NPIXELS (p1) != IMAGE_INSTANCE_GTK_NPIXELS (p2))
483         return 0;
484 #if HAVE_SUBWINDOWS
485     case IMAGE_SUBWINDOW:
486       /* #### implement me */
487 #endif
488       break;
489     default:
490       break;
491     }
492
493   return 1;
494 }
495
496 static unsigned long
497 gtk_image_instance_hash (struct Lisp_Image_Instance *p, int depth)
498 {
499   switch (IMAGE_INSTANCE_TYPE (p))
500     {
501     case IMAGE_MONO_PIXMAP:
502     case IMAGE_COLOR_PIXMAP:
503     case IMAGE_POINTER:
504       return IMAGE_INSTANCE_GTK_NPIXELS (p);
505 #if HAVE_SUBWINDOWS
506     case IMAGE_SUBWINDOW:
507       /* #### implement me */
508       return 0;
509 #endif
510     default:
511       return 0;
512     }
513 }
514
515 /* Set all the slots in an image instance structure to reasonable
516    default values.  This is used somewhere within an instantiate
517    method.  It is assumed that the device slot within the image
518    instance is already set -- this is the case when instantiate
519    methods are called. */
520
521 static void
522 gtk_initialize_pixmap_image_instance (struct Lisp_Image_Instance *ii,
523                                       int slices,
524                                       enum image_instance_type type)
525 {
526   ii->data = xnew_and_zero (struct gtk_image_instance_data);
527   IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii) = slices;
528   IMAGE_INSTANCE_GTK_PIXMAP_SLICES (ii) =
529     xnew_array_and_zero (GdkPixmap *, slices);
530   IMAGE_INSTANCE_TYPE (ii) = type;
531   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = Qnil;
532   IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (ii) = Qnil;
533   IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = Qnil;
534   IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = Qnil;
535   IMAGE_INSTANCE_PIXMAP_FG (ii) = Qnil;
536   IMAGE_INSTANCE_PIXMAP_BG (ii) = Qnil;
537 }
538
539 \f
540 /************************************************************************/
541 /*                        pixmap file functions                         */
542 /************************************************************************/
543
544 /* Where bitmaps are; initialized from resource database */
545 Lisp_Object Vgtk_bitmap_file_path;
546
547 #ifndef BITMAPDIR
548 #define BITMAPDIR "/usr/include/X11/bitmaps"
549 #endif
550
551 /* Given a pixmap filename, look through all of the "standard" places
552    where the file might be located.  Return a full pathname if found;
553    otherwise, return Qnil. */
554
555 static Lisp_Object
556 gtk_locate_pixmap_file (Lisp_Object name)
557 {
558   /* This function can GC if IN_REDISPLAY is false */
559
560   /* Check non-absolute pathnames with a directory component relative to
561      the search path; that's the way Xt does it. */
562   /* #### Unix-specific */
563   if (XSTRING_BYTE (name, 0) == '/' ||
564       (XSTRING_BYTE (name, 0) == '.' &&
565        (XSTRING_BYTE (name, 1) == '/' ||
566         (XSTRING_BYTE (name, 1) == '.' &&
567          (XSTRING_BYTE (name, 2) == '/')))))
568     {
569       if (!NILP (Ffile_readable_p (name)))
570         return name;
571       else
572         return Qnil;
573     }
574
575   if (NILP (Vdefault_gtk_device))
576     /* This may occur during intialization. */
577     return Qnil;
578
579   if (NILP (Vgtk_bitmap_file_path))
580     {
581       Vgtk_bitmap_file_path = nconc2 (Vgtk_bitmap_file_path,
582                                       (decode_path (BITMAPDIR)));
583     }
584
585   {
586     Lisp_Object found;
587     if (locate_file (Vgtk_bitmap_file_path, name, Qnil, &found, R_OK) < 0)
588       {
589         Lisp_Object temp = list1 (Vdata_directory);
590         struct gcpro gcpro1;
591
592         GCPRO1 (temp);
593         locate_file (temp, name, Qnil, &found, R_OK);
594         UNGCPRO;
595       }
596
597     return found;
598   }
599 }
600
601 static Lisp_Object
602 locate_pixmap_file (Lisp_Object name)
603 {
604   return gtk_locate_pixmap_file (name);
605 }
606
607 \f
608 /************************************************************************/
609 /*                           cursor functions                           */
610 /************************************************************************/
611
612 /* Check that this server supports cursors of size WIDTH * HEIGHT.  If
613    not, signal an error.  INSTANTIATOR is only used in the error
614    message. */
615
616 static void
617 check_pointer_sizes (unsigned int width, unsigned int height,
618                      Lisp_Object instantiator)
619 {
620     /* #### BILL!!! There is no way to call XQueryBestCursor from Gdk! */
621 #if 0
622   unsigned int best_width, best_height;
623   if (! XQueryBestCursor (DisplayOfScreen (xs), RootWindowOfScreen (xs),
624                           width, height, &best_width, &best_height))
625     /* this means that an X error of some sort occurred (we trap
626        these so they're not fatal). */
627     signal_simple_error ("XQueryBestCursor() failed?", instantiator);
628
629   if (width > best_width || height > best_height)
630     error_with_frob (instantiator,
631                      "pointer too large (%dx%d): "
632                      "server requires %dx%d or smaller",
633                      width, height, best_width, best_height);
634 #endif
635 }
636
637 static void
638 generate_cursor_fg_bg (Lisp_Object device, Lisp_Object *foreground,
639                        Lisp_Object *background, GdkColor *xfg, GdkColor *xbg)
640 {
641   if (!NILP (*foreground) && !COLOR_INSTANCEP (*foreground))
642     *foreground =
643       Fmake_color_instance (*foreground, device,
644                             encode_error_behavior_flag (ERROR_ME));
645   if (COLOR_INSTANCEP (*foreground))
646     *xfg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (*foreground));
647   else
648     {
649       xfg->pixel = 0;
650       xfg->red = xfg->green = xfg->blue = 0;
651     }
652
653   if (!NILP (*background) && !COLOR_INSTANCEP (*background))
654     *background =
655       Fmake_color_instance (*background, device,
656                             encode_error_behavior_flag (ERROR_ME));
657   if (COLOR_INSTANCEP (*background))
658     *xbg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (*background));
659   else
660     {
661       xbg->pixel = 0;
662       xbg->red = xbg->green = xbg->blue = ~0;
663     }
664 }
665
666 static void
667 maybe_recolor_cursor (Lisp_Object image_instance, Lisp_Object foreground,
668                       Lisp_Object background)
669 {
670 #if 0
671     /* #### BILL!!! */
672   Lisp_Object device = XIMAGE_INSTANCE_DEVICE (image_instance);
673   GdkColor xfg, xbg;
674
675   generate_cursor_fg_bg (device, &foreground, &background, &xfg, &xbg);
676   if (!NILP (foreground) || !NILP (background))
677     {
678       XRecolorCursor (DEVICE_X_DISPLAY (XDEVICE (device)),
679                       XIMAGE_INSTANCE_GTK_CURSOR (image_instance),
680                       &xfg, &xbg);
681       XIMAGE_INSTANCE_PIXMAP_FG (image_instance) = foreground;
682       XIMAGE_INSTANCE_PIXMAP_BG (image_instance) = background;
683     }
684 #else
685   /* stderr_out ("Don't know how to recolor cursors in Gtk!\n"); */
686 #endif
687 }
688
689 \f
690 /************************************************************************/
691 /*                        color pixmap functions                        */
692 /************************************************************************/
693
694 /* Initialize an image instance from an XImage.
695
696    DEST_MASK specifies the mask of allowed image types.
697
698    PIXELS and NPIXELS specify an array of pixels that are used in
699    the image.  These need to be kept around for the duration of the
700    image.  When the image instance is freed, XFreeColors() will
701    automatically be called on all the pixels specified here; thus,
702    you should have allocated the pixels yourself using XAllocColor()
703    or the like.  The array passed in is used directly without
704    being copied, so it should be heap data created with xmalloc().
705    It will be freed using xfree() when the image instance is
706    destroyed.
707
708    If this fails, signal an error.  INSTANTIATOR is only used
709    in the error message.
710
711    #### This should be able to handle conversion into `pointer'.
712    Use the same code as for `xpm'. */
713
714 static void
715 init_image_instance_from_gdk_image (struct Lisp_Image_Instance *ii,
716                                     GdkImage *gdk_image,
717                                     int dest_mask,
718                                     GdkColormap *cmap,
719                                     unsigned long *pixels,
720                                     int npixels,
721                                     int slices,
722                                     Lisp_Object instantiator)
723 {
724   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
725   GdkGC *gc;
726   GdkWindow *d;
727   GdkPixmap *pixmap;
728
729   if (!DEVICE_GTK_P (XDEVICE (device)))
730     signal_simple_error ("Not a Gtk device", device);
731
732   d = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device)));
733
734   if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
735     incompatible_image_types (instantiator, dest_mask,
736                               IMAGE_COLOR_PIXMAP_MASK);
737
738   pixmap = gdk_pixmap_new (d, gdk_image->width, gdk_image->height, gdk_image->depth);
739   if (!pixmap)
740     signal_simple_error ("Unable to create pixmap", instantiator);
741
742   gc = gdk_gc_new (pixmap);
743   if (!gc)
744     {
745       gdk_pixmap_unref (pixmap);
746       signal_simple_error ("Unable to create GC", instantiator);
747     }
748
749   gdk_draw_image (GDK_DRAWABLE (pixmap), gc, gdk_image,
750                   0, 0, 0, 0, gdk_image->width, gdk_image->height);
751
752   gdk_gc_destroy (gc);
753
754   gtk_initialize_pixmap_image_instance (ii, slices, IMAGE_COLOR_PIXMAP);
755
756   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
757     find_keyword_in_vector (instantiator, Q_file);
758
759   IMAGE_INSTANCE_GTK_PIXMAP (ii) = pixmap;
760   IMAGE_INSTANCE_GTK_MASK (ii) = 0;
761   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = gdk_image->width;
762   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = gdk_image->height;
763   IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = gdk_image->depth;
764   IMAGE_INSTANCE_GTK_COLORMAP (ii) = cmap;
765   IMAGE_INSTANCE_GTK_PIXELS (ii) = pixels;
766   IMAGE_INSTANCE_GTK_NPIXELS (ii) = npixels;
767 }
768
769 #if 0
770 void init_image_instance_from_gdk_pixmap (struct Lisp_Image_Instance *ii,
771                                           struct device *device,
772                                           GdkPixmap *gdk_pixmap,
773                                           int dest_mask,
774                                           Lisp_Object instantiator)
775 {
776   GdkWindow *d;
777   gint width, height, depth;
778
779   if (!DEVICE_GTK_P (device))
780     abort ();
781
782   IMAGE_INSTANCE_DEVICE (ii) = device;
783   IMAGE_INSTANCE_TYPE (ii) = IMAGE_COLOR_PIXMAP;
784
785   d = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (device));
786
787   if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
788     incompatible_image_types (instantiator, dest_mask,
789                               IMAGE_COLOR_PIXMAP_MASK);
790
791   gtk_initialize_pixmap_image_instance (ii, IMAGE_COLOR_PIXMAP);
792
793   gdk_window_get_geometry (gdk_pixmap, NULL, NULL, &width, &height, &depth);
794
795   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = Qnil;
796   IMAGE_INSTANCE_GTK_PIXMAP (ii) = gdk_pixmap;
797   IMAGE_INSTANCE_GTK_MASK (ii) = 0;
798   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = width;
799   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = height;
800   IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = depth;
801   IMAGE_INSTANCE_GTK_COLORMAP (ii) = gdk_window_get_colormap (gdk_pixmap);
802   IMAGE_INSTANCE_GTK_PIXELS (ii) = 0;
803   IMAGE_INSTANCE_GTK_NPIXELS (ii) = 0;
804 }
805 #endif
806
807 static void
808 image_instance_add_gdk_image (Lisp_Image_Instance *ii,
809                               GdkImage *gdk_image,
810                               int slice,
811                               Lisp_Object instantiator)
812 {
813   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
814   GdkWindow *d;
815   GdkPixmap *pixmap;
816   GdkGC *gc;
817
818   d = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device)));
819
820   pixmap = gdk_pixmap_new (d, gdk_image->width, gdk_image->height, gdk_image->depth);
821
822   if (!pixmap)
823     signal_simple_error ("Unable to create pixmap", instantiator);
824
825   gc = gdk_gc_new (pixmap);
826
827   if (!gc)
828     {
829       gdk_pixmap_unref (pixmap);
830       signal_simple_error ("Unable to create GC", instantiator);
831     }
832
833   gdk_draw_image (GDK_DRAWABLE (pixmap), gc, gdk_image, 0, 0, 0, 0,
834                   gdk_image->width, gdk_image->height);
835
836   gdk_gc_destroy (gc);
837
838   IMAGE_INSTANCE_GTK_PIXMAP_SLICE (ii, slice) = pixmap;
839 }
840
841 static void
842 gtk_init_image_instance_from_eimage (struct Lisp_Image_Instance *ii,
843                                      int width, int height,
844                                      int slices,
845                                      unsigned char *eimage, 
846                                      int dest_mask,
847                                      Lisp_Object instantiator,
848                                      Lisp_Object domain)
849 {
850   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
851   GdkColormap *cmap = DEVICE_GTK_COLORMAP (XDEVICE(device));
852   unsigned long *pixtbl = NULL;
853   int npixels = 0;
854   int slice;
855   GdkImage* gdk_image;
856
857
858   for (slice = 0; slice < slices; slice++)
859     {
860       gdk_image = convert_EImage_to_GDKImage (device, width, height, eimage,
861                                               &pixtbl, &npixels);
862       if (!gdk_image)
863         {
864           if (pixtbl) xfree (pixtbl);
865           signal_image_error("EImage to GdkImage conversion failed", instantiator);
866         }
867
868       if (slice == 0)
869         /* Now create the pixmap and set up the image instance */
870         init_image_instance_from_gdk_image (ii, gdk_image, dest_mask,
871                                             cmap, pixtbl, npixels, slices,
872                                             instantiator);
873       else
874         image_instance_add_gdk_image (ii, gdk_image, slice, instantiator);
875
876       if (gdk_image)
877         {
878           gdk_image_destroy (gdk_image);
879         }
880       gdk_image = 0;
881     }
882 }
883
884 /* Given inline data for a mono pixmap, create and return the
885    corresponding X object. */
886
887 static GdkPixmap *
888 pixmap_from_xbm_inline (Lisp_Object device, int width, int height,
889                         /* Note that data is in ext-format! */
890                         CONST Extbyte *bits)
891 {
892     return (gdk_bitmap_create_from_data (GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device))),
893                                          (char *) bits, width, height));
894 }
895
896 /* Given inline data for a mono pixmap, initialize the given
897    image instance accordingly. */
898
899 static void
900 init_image_instance_from_xbm_inline (struct Lisp_Image_Instance *ii,
901                                      int width, int height,
902                                      /* Note that data is in ext-format! */
903                                      CONST char *bits,
904                                      Lisp_Object instantiator,
905                                      Lisp_Object pointer_fg,
906                                      Lisp_Object pointer_bg,
907                                      int dest_mask,
908                                      GdkPixmap *mask,
909                                      Lisp_Object mask_filename)
910 {
911   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
912   Lisp_Object foreground = find_keyword_in_vector (instantiator, Q_foreground);
913   Lisp_Object background = find_keyword_in_vector (instantiator, Q_background);
914   GdkColor fg;
915   GdkColor bg;
916   enum image_instance_type type;
917   GdkWindow *draw = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device)));
918   GdkColormap *cmap = DEVICE_GTK_COLORMAP (XDEVICE(device));
919   GdkColor black;
920   GdkColor white;
921
922   gdk_color_black(cmap, &black);
923   gdk_color_white(cmap, &white);
924
925   if (!DEVICE_GTK_P (XDEVICE (device)))
926     signal_simple_error ("Not a Gtk device", device);
927
928   if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) &&
929       (dest_mask & IMAGE_COLOR_PIXMAP_MASK))
930     {
931       if (!NILP (foreground) || !NILP (background))
932         type = IMAGE_COLOR_PIXMAP;
933       else
934         type = IMAGE_MONO_PIXMAP;
935     }
936   else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
937     type = IMAGE_MONO_PIXMAP;
938   else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
939     type = IMAGE_COLOR_PIXMAP;
940   else if (dest_mask & IMAGE_POINTER_MASK)
941     type = IMAGE_POINTER;
942   else
943     incompatible_image_types (instantiator, dest_mask,
944                               IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
945                               | IMAGE_POINTER_MASK);
946
947   gtk_initialize_pixmap_image_instance (ii, 1, type);
948   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = width;
949   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = height;
950   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
951     find_keyword_in_vector (instantiator, Q_file);
952
953   switch (type)
954     {
955     case IMAGE_MONO_PIXMAP:
956       {
957         IMAGE_INSTANCE_GTK_PIXMAP (ii) =
958           pixmap_from_xbm_inline (device, width, height, (Extbyte *) bits);
959       }
960       break;
961
962     case IMAGE_COLOR_PIXMAP:
963       {
964         gint d = DEVICE_GTK_DEPTH (XDEVICE(device));
965
966         if (!NILP (foreground) && !COLOR_INSTANCEP (foreground))
967           foreground =
968             Fmake_color_instance (foreground, device,
969                                   encode_error_behavior_flag (ERROR_ME));
970
971         if (COLOR_INSTANCEP (foreground))
972           fg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (foreground));
973
974         if (!NILP (background) && !COLOR_INSTANCEP (background))
975           background =
976             Fmake_color_instance (background, device,
977                                   encode_error_behavior_flag (ERROR_ME));
978
979         if (COLOR_INSTANCEP (background))
980           bg = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (background));
981
982         /* We used to duplicate the pixels using XAllocColor(), to protect
983            against their getting freed.  Just as easy to just store the
984            color instances here and GC-protect them, so this doesn't
985            happen. */
986         IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
987         IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
988         IMAGE_INSTANCE_GTK_PIXMAP (ii) =
989             gdk_pixmap_create_from_data (draw, (char *) bits, width, height, d, &fg, &bg);
990         IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = d;
991       }
992       break;
993
994     case IMAGE_POINTER:
995     {
996         GdkColor fg_color, bg_color;
997         GdkPixmap *source;
998
999         check_pointer_sizes (width, height, instantiator);
1000
1001         source = gdk_pixmap_create_from_data (draw, (char *) bits, width, height, 1, &black, &white);
1002
1003         if (NILP (foreground))
1004           foreground = pointer_fg;
1005         if (NILP (background))
1006           background = pointer_bg;
1007         generate_cursor_fg_bg (device, &foreground, &background,
1008                                &fg_color, &bg_color);
1009
1010         IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
1011         IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
1012         IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) =
1013           find_keyword_in_vector (instantiator, Q_hotspot_x);
1014         IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) =
1015           find_keyword_in_vector (instantiator, Q_hotspot_y);
1016         IMAGE_INSTANCE_GTK_CURSOR (ii) =
1017             gdk_cursor_new_from_pixmap (source, mask, &fg_color, &bg_color,
1018                                         !NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)) ?
1019                                         XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)) : 0,
1020                                         !NILP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)) ?
1021                                         XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)) : 0);
1022       }
1023       break;
1024
1025     default:
1026       abort ();
1027     }
1028 }
1029
1030 static void
1031 xbm_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator,
1032                    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1033                    int dest_mask, int width, int height,
1034                    /* Note that data is in ext-format! */
1035                    CONST char *bits)
1036 {
1037   Lisp_Object mask_data = find_keyword_in_vector (instantiator, Q_mask_data);
1038   Lisp_Object mask_file = find_keyword_in_vector (instantiator, Q_mask_file);
1039   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1040   GdkPixmap *mask = 0;
1041   CONST char *gcc_may_you_rot_in_hell;
1042
1043   if (!NILP (mask_data))
1044     {
1045       TO_EXTERNAL_FORMAT (LISP_STRING, XCAR (XCDR (XCDR (mask_data))),
1046                           C_STRING_ALLOCA, gcc_may_you_rot_in_hell,
1047                           Qfile_name);
1048       mask =
1049         pixmap_from_xbm_inline (IMAGE_INSTANCE_DEVICE (ii),
1050                                 XINT (XCAR (mask_data)),
1051                                 XINT (XCAR (XCDR (mask_data))),
1052                                 (CONST unsigned char *)
1053                                 gcc_may_you_rot_in_hell);
1054     }
1055
1056   init_image_instance_from_xbm_inline (ii, width, height, bits,
1057                                        instantiator, pointer_fg, pointer_bg,
1058                                        dest_mask, mask, mask_file);
1059 }
1060
1061 /* Instantiate method for XBM's. */
1062
1063 static void
1064 gtk_xbm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1065                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1066                      int dest_mask, Lisp_Object domain)
1067 {
1068   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1069   CONST char *gcc_go_home;
1070
1071   assert (!NILP (data));
1072
1073   TO_EXTERNAL_FORMAT (LISP_STRING, XCAR (XCDR (XCDR (data))),
1074                       C_STRING_ALLOCA, gcc_go_home,
1075                       Qbinary);
1076
1077   xbm_instantiate_1 (image_instance, instantiator, pointer_fg,
1078                      pointer_bg, dest_mask, XINT (XCAR (data)),
1079                      XINT (XCAR (XCDR (data))), gcc_go_home);
1080 }
1081
1082 \f
1083 #ifdef HAVE_XPM
1084 /**********************************************************************
1085  *                             XPM                                    *
1086  **********************************************************************/
1087 static void
1088 write_lisp_string_to_temp_file (Lisp_Object string, char *filename_out)
1089 {
1090   Lisp_Object instream, outstream;
1091   Lstream *istr, *ostr;
1092   char tempbuf[1024]; /* some random amount */
1093   int fubar = 0;
1094   FILE *tmpfil;
1095   static Extbyte_dynarr *conversion_out_dynarr;
1096   Bytecount bstart, bend;
1097   struct gcpro gcpro1, gcpro2;
1098 #ifdef FILE_CODING
1099   Lisp_Object conv_out_stream;
1100   Lstream *costr;
1101   struct gcpro gcpro3;
1102 #endif
1103
1104   /* This function can GC */
1105   if (!conversion_out_dynarr)
1106     conversion_out_dynarr = Dynarr_new (Extbyte);
1107   else
1108     Dynarr_reset (conversion_out_dynarr);
1109
1110   /* Create the temporary file ... */
1111   sprintf (filename_out, "/tmp/emacs%d.XXXXXX", (int) getpid ());
1112   mktemp (filename_out);
1113   tmpfil = fopen (filename_out, "w");
1114   if (!tmpfil)
1115     {
1116       if (tmpfil)
1117         {
1118           int old_errno = errno;
1119           fclose (tmpfil);
1120           unlink (filename_out);
1121           errno = old_errno;
1122         }
1123       report_file_error ("Creating temp file",
1124                          list1 (build_string (filename_out)));
1125     }
1126
1127   CHECK_STRING (string);
1128   get_string_range_byte (string, Qnil, Qnil, &bstart, &bend,
1129                          GB_HISTORICAL_STRING_BEHAVIOR);
1130   instream = make_lisp_string_input_stream (string, bstart, bend);
1131   istr = XLSTREAM (instream);
1132   /* setup the out stream */
1133   outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr);
1134   ostr = XLSTREAM (outstream);
1135 #ifdef FILE_CODING
1136   /* setup the conversion stream */
1137   conv_out_stream = make_encoding_output_stream (ostr, Fget_coding_system(Qbinary));
1138   costr = XLSTREAM (conv_out_stream);
1139   GCPRO3 (instream, outstream, conv_out_stream);
1140 #else
1141   GCPRO2 (instream, outstream);
1142 #endif
1143
1144   /* Get the data while doing the conversion */
1145   while (1)
1146     {
1147       int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
1148       if (!size_in_bytes)
1149         break;
1150       /* It does seem the flushes are necessary... */
1151 #ifdef FILE_CODING
1152       Lstream_write (costr, tempbuf, size_in_bytes);
1153       Lstream_flush (costr);
1154 #else
1155       Lstream_write (ostr, tempbuf, size_in_bytes);
1156 #endif
1157       Lstream_flush (ostr);
1158       if (fwrite ((unsigned char *)Dynarr_atp(conversion_out_dynarr, 0),
1159                   Dynarr_length(conversion_out_dynarr), 1, tmpfil) != 1)
1160         {
1161           fubar = 1;
1162           break;
1163         }
1164       /* reset the dynarr */
1165       Lstream_rewind(ostr);
1166     }
1167   
1168   if (fclose (tmpfil) != 0)
1169     fubar = 1;
1170   Lstream_close (istr);
1171 #ifdef FILE_CODING
1172   Lstream_close (costr);
1173 #endif
1174   Lstream_close (ostr);
1175
1176   UNGCPRO;
1177   Lstream_delete (istr);
1178   Lstream_delete (ostr);
1179 #ifdef FILE_CODING
1180   Lstream_delete (costr);
1181 #endif
1182
1183   if (fubar)
1184     report_file_error ("Writing temp file",
1185                        list1 (build_string (filename_out)));
1186 }
1187
1188 struct color_symbol
1189 {
1190   char*         name;
1191   GdkColor      color;
1192 };
1193
1194 static struct color_symbol*
1195 extract_xpm_color_names (Lisp_Object device,
1196                          Lisp_Object domain,
1197                          Lisp_Object color_symbol_alist,
1198                          int* nsymbols)
1199 {
1200   /* This function can GC */
1201   Lisp_Object rest;
1202   Lisp_Object results = Qnil;
1203   int i, j;
1204   struct color_symbol *colortbl;
1205   struct gcpro gcpro1, gcpro2;
1206
1207   GCPRO2 (results, device);
1208
1209   /* We built up results to be (("name" . #<color>) ...) so that if an
1210      error happens we don't lose any malloc()ed data, or more importantly,
1211      leave any pixels allocated in the server. */
1212   i = 0;
1213   LIST_LOOP (rest, color_symbol_alist)
1214     {
1215       Lisp_Object cons = XCAR (rest);
1216       Lisp_Object name = XCAR (cons);
1217       Lisp_Object value = XCDR (cons);
1218       if (NILP (value))
1219         continue;
1220       if (STRINGP (value))
1221         value =
1222           Fmake_color_instance
1223           (value, device, encode_error_behavior_flag (ERROR_ME_NOT));
1224       else
1225         {
1226           assert (COLOR_SPECIFIERP (value));
1227           value = Fspecifier_instance (value, domain, Qnil, Qnil);
1228         }
1229       if (NILP (value))
1230         continue;
1231       results = noseeum_cons (noseeum_cons (name, value), results);
1232       i++;
1233     }
1234   UNGCPRO;                      /* no more evaluation */
1235
1236   *nsymbols=i;
1237   if (i == 0) return 0;
1238
1239   colortbl = xnew_array_and_zero (struct color_symbol, i);
1240
1241   for (j=0; j<i; j++)
1242     {
1243       Lisp_Object cons = XCAR (results);
1244       colortbl[j].color = 
1245         * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (XCDR (cons)));
1246
1247       colortbl[j].name = (char *) XSTRING_DATA (XCAR (cons));
1248       free_cons (XCONS (cons));
1249       cons = results;
1250       results = XCDR (results);
1251       free_cons (XCONS (cons));
1252     }
1253   return colortbl;
1254 }
1255
1256 static void
1257 gtk_xpm_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1258                      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1259                      int dest_mask, Lisp_Object domain)
1260 {
1261   /* This function can GC */
1262   char temp_file_name[1024];
1263   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1264   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1265   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1266   GdkColormap *cmap;
1267   int depth;
1268   GdkVisual *visual;
1269   GdkPixmap *pixmap;
1270   GdkPixmap *mask = 0;
1271   GdkWindow *window = 0;
1272   int nsymbols = 0, i = 0;
1273   struct color_symbol *color_symbols = NULL;
1274   GdkColor *transparent_color = NULL;
1275   Lisp_Object color_symbol_alist = find_keyword_in_vector (instantiator,
1276                                                            Q_color_symbols);
1277   enum image_instance_type type;
1278   int force_mono;
1279   unsigned int w, h;
1280
1281   if (!DEVICE_GTK_P (XDEVICE (device)))
1282     signal_simple_error ("Not a Gtk device", device);
1283
1284   if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1285     type = IMAGE_COLOR_PIXMAP;
1286   else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1287     type = IMAGE_MONO_PIXMAP;
1288   else if (dest_mask & IMAGE_POINTER_MASK)
1289     type = IMAGE_POINTER;
1290   else
1291     incompatible_image_types (instantiator, dest_mask,
1292                               IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
1293                               | IMAGE_POINTER_MASK);
1294   force_mono = (type != IMAGE_COLOR_PIXMAP);
1295
1296   window = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device)));
1297   cmap = DEVICE_GTK_COLORMAP (XDEVICE (device));
1298   depth = DEVICE_GTK_DEPTH (XDEVICE (device));
1299   visual = DEVICE_GTK_VISUAL (XDEVICE (device));
1300
1301   gtk_initialize_pixmap_image_instance (ii, 1, type);
1302
1303   assert (!NILP (data));
1304
1305   /* Need to get the transparent color here */
1306   color_symbols = extract_xpm_color_names (device, domain, color_symbol_alist, &nsymbols);
1307   for (i = 0; i < nsymbols; i++)
1308     {
1309       if (!strcasecmp ("BgColor", color_symbols[i].name) ||
1310           !strcasecmp ("None", color_symbols[i].name))
1311         {
1312           transparent_color = &color_symbols[i].color;
1313         }
1314     }
1315
1316   write_lisp_string_to_temp_file (data, temp_file_name);
1317   pixmap = gdk_pixmap_create_from_xpm (window, &mask, transparent_color, temp_file_name);
1318   unlink (temp_file_name);
1319
1320   if (color_symbols) xfree (color_symbols);
1321
1322   if (!pixmap)
1323   {
1324     signal_image_error ("Error reading pixmap", data);
1325   }
1326
1327   gdk_window_get_geometry (pixmap, NULL, NULL, &w, &h, &depth);
1328
1329   IMAGE_INSTANCE_GTK_PIXMAP (ii) = pixmap;
1330   IMAGE_INSTANCE_GTK_MASK (ii) = mask;
1331   IMAGE_INSTANCE_GTK_COLORMAP (ii) = cmap;
1332   IMAGE_INSTANCE_GTK_PIXELS (ii) = 0;
1333   IMAGE_INSTANCE_GTK_NPIXELS (ii) = 0;
1334   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = w;
1335   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = h;
1336   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
1337     find_keyword_in_vector (instantiator, Q_file);
1338
1339   switch (type)
1340     {
1341     case IMAGE_MONO_PIXMAP:
1342       break;
1343
1344     case IMAGE_COLOR_PIXMAP:
1345       {
1346         IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = depth;
1347       }
1348       break;
1349
1350     case IMAGE_POINTER:
1351       {
1352         GdkColor fg, bg;
1353         unsigned int xhot, yhot;
1354
1355         /* #### Gtk does not give us access to the hotspots of a pixmap */
1356         xhot = yhot = 1;
1357         XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), xhot);
1358         XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), yhot);
1359
1360         check_pointer_sizes (w, h, instantiator);
1361
1362         /* If the loaded pixmap has colors allocated (meaning it came from an
1363            XPM file), then use those as the default colors for the cursor we
1364            create.  Otherwise, default to pointer_fg and pointer_bg.
1365         */
1366         if (depth > 1)
1367           {
1368             warn_when_safe (Qunimplemented, Qnotice,
1369                             "GTK does not support XPM cursors...\n");
1370             IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new (GDK_COFFEE_MUG);
1371           }
1372         else
1373           {
1374             generate_cursor_fg_bg (device, &pointer_fg, &pointer_bg,
1375                                    &fg, &bg);
1376             IMAGE_INSTANCE_PIXMAP_FG (ii) = pointer_fg;
1377             IMAGE_INSTANCE_PIXMAP_BG (ii) = pointer_bg;
1378             IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, xhot, yhot);
1379           }
1380       }
1381
1382       break;
1383
1384     default:
1385       abort ();
1386     }
1387 }
1388 #endif /* HAVE_XPM */
1389
1390 \f
1391 #ifdef HAVE_XFACE
1392
1393 /**********************************************************************
1394  *                             X-Face                                 *
1395  **********************************************************************/
1396 #if defined(EXTERN)
1397 /* This is about to get redefined! */
1398 #undef EXTERN
1399 #endif
1400 /* We have to define SYSV32 so that compface.h includes string.h
1401    instead of strings.h. */
1402 #define SYSV32
1403 #ifdef __cplusplus
1404 extern "C" {
1405 #endif
1406 #include <compface.h>
1407 #ifdef __cplusplus
1408 }
1409 #endif
1410 /* JMP_BUF cannot be used here because if it doesn't get defined
1411    to jmp_buf we end up with a conflicting type error with the
1412    definition in compface.h */
1413 extern jmp_buf comp_env;
1414 #undef SYSV32
1415
1416 static void
1417 gtk_xface_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1418                    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1419                    int dest_mask, Lisp_Object domain)
1420 {
1421   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1422   int i, stattis;
1423   char *p, *bits, *bp;
1424   CONST char * volatile emsg = 0;
1425   CONST char * volatile dstring;
1426
1427   assert (!NILP (data));
1428
1429   LISP_STRING_TO_EXTERNAL (data, dstring, Qbinary);
1430
1431   if ((p = strchr (dstring, ':')))
1432     {
1433       dstring = p + 1;
1434     }
1435
1436   /* Must use setjmp not SETJMP because we used jmp_buf above not JMP_BUF */
1437   if (!(stattis = setjmp (comp_env)))
1438     {
1439       UnCompAll ((char *) dstring);
1440       UnGenFace ();
1441     }
1442
1443   switch (stattis)
1444     {
1445     case -2:
1446       emsg = "uncompface: internal error";
1447       break;
1448     case -1:
1449       emsg = "uncompface: insufficient or invalid data";
1450       break;
1451     case 1:
1452       emsg = "uncompface: excess data ignored";
1453       break;
1454     }
1455
1456   if (emsg)
1457     signal_simple_error_2 (emsg, data, Qimage);
1458
1459   bp = bits = (char *) alloca (PIXELS / 8);
1460
1461   /* the compface library exports char F[], which uses a single byte per
1462      pixel to represent a 48x48 bitmap.  Yuck. */
1463   for (i = 0, p = F; i < (PIXELS / 8); ++i)
1464     {
1465       int n, b;
1466       /* reverse the bit order of each byte... */
1467       for (b = n = 0; b < 8; ++b)
1468         {
1469           n |= ((*p++) << b);
1470         }
1471       *bp++ = (char) n;
1472     }
1473
1474   xbm_instantiate_1 (image_instance, instantiator, pointer_fg,
1475                      pointer_bg, dest_mask, 48, 48, bits);
1476 }
1477
1478 #endif /* HAVE_XFACE */
1479
1480 /**********************************************************************
1481  *                             RESOURCES                              *
1482  **********************************************************************/
1483
1484 static void
1485 gtk_resource_validate (Lisp_Object instantiator)
1486 {
1487   if ((NILP (find_keyword_in_vector (instantiator, Q_file)) 
1488        &&
1489        NILP (find_keyword_in_vector (instantiator, Q_resource_id))) 
1490       ||
1491       NILP (find_keyword_in_vector (instantiator, Q_resource_type)))
1492     signal_simple_error ("Must supply :file, :resource-id and :resource-type",
1493                          instantiator);
1494 }
1495
1496 static Lisp_Object
1497 gtk_resource_normalize (Lisp_Object inst, Lisp_Object console_type, Lisp_Object dest_mask)
1498 {
1499   /* This function can call lisp */
1500   Lisp_Object file = Qnil;
1501   struct gcpro gcpro1, gcpro2;
1502   Lisp_Object alist = Qnil;
1503
1504   GCPRO2 (file, alist);
1505
1506   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data, 
1507                                              console_type);
1508
1509   if (CONSP (file)) /* failure locating filename */
1510     signal_double_file_error ("Opening pixmap file",
1511                               "no such file or directory",
1512                               Fcar (file));
1513
1514   if (NILP (file)) /* no conversion necessary */
1515     RETURN_UNGCPRO (inst);
1516
1517   alist = tagged_vector_to_alist (inst);
1518
1519   {
1520     alist = remassq_no_quit (Q_file, alist);
1521     alist = Fcons (Fcons (Q_file, file), alist);
1522   }
1523
1524   {
1525     Lisp_Object result = alist_to_tagged_vector (Qgtk_resource, alist);
1526     free_alist (alist);
1527     RETURN_UNGCPRO (result);
1528   }
1529 }
1530
1531 static int
1532 gtk_resource_possible_dest_types (void)
1533 {
1534   return IMAGE_POINTER_MASK | IMAGE_COLOR_PIXMAP_MASK;
1535 }
1536
1537 extern guint symbol_to_enum (Lisp_Object, GtkType);
1538
1539 static guint resource_name_to_resource (Lisp_Object name, int type)
1540 {
1541   if (type == IMAGE_POINTER)
1542     return (symbol_to_enum (name, GTK_TYPE_GDK_CURSOR_TYPE));
1543   else
1544     return (0);
1545 }
1546
1547 static int
1548 resource_symbol_to_type (Lisp_Object data)
1549 {
1550   if (EQ (data, Qcursor))
1551     return IMAGE_POINTER;
1552 #if 0
1553   else if (EQ (data, Qicon))
1554     return IMAGE_ICON;
1555   else if (EQ (data, Qbitmap))
1556     return IMAGE_BITMAP;
1557 #endif
1558   else
1559     return 0;
1560 }
1561
1562 static void
1563 gtk_resource_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   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1568   GdkCursor *c = NULL;
1569   unsigned int type = 0;
1570   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1571   Lisp_Object resource_type = find_keyword_in_vector (instantiator, Q_resource_type);
1572   Lisp_Object resource_id = find_keyword_in_vector (instantiator, Q_resource_id);
1573
1574   if (!DEVICE_GTK_P (XDEVICE (device)))
1575     signal_simple_error ("Not a GTK device", device);
1576
1577   type = resource_symbol_to_type (resource_type);
1578
1579   //   if (dest_mask & IMAGE_POINTER_MASK && type == IMAGE_POINTER_MASK)
1580   //     iitype = IMAGE_POINTER;
1581   //   else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1582   //     iitype = IMAGE_COLOR_PIXMAP;
1583   //   else 
1584   //     incompatible_image_types (instantiator, dest_mask,
1585   //                          IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK);
1586
1587   /* mess with the keyword info we were provided with */
1588   gtk_initialize_pixmap_image_instance (ii, 1, type);
1589   c = gdk_cursor_new (resource_name_to_resource (resource_id, type));
1590   IMAGE_INSTANCE_GTK_CURSOR (ii) = c;
1591   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = resource_id;
1592   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = 10;
1593   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = 10;
1594   IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = 1;
1595 }
1596
1597 static void
1598 check_valid_resource_symbol (Lisp_Object data)
1599 {
1600   CHECK_SYMBOL (data);
1601   if (!resource_symbol_to_type (data))
1602     signal_simple_error ("invalid resource type", data);
1603 }
1604
1605 static void
1606 check_valid_resource_id (Lisp_Object data)
1607 {
1608   if (!resource_name_to_resource (data, IMAGE_POINTER)
1609       &&
1610       !resource_name_to_resource (data, IMAGE_COLOR_PIXMAP)
1611 #if 0
1612       &&
1613       !resource_name_to_resource (data, IMAGE_BITMAP)
1614 #endif
1615       )
1616     signal_simple_error ("invalid resource identifier", data);
1617 }
1618
1619 #if 0
1620 void
1621 check_valid_string_or_int (Lisp_Object data)
1622 {
1623   if (!INTP (data))
1624     CHECK_STRING (data);
1625   else
1626     CHECK_INT (data);
1627 }
1628 #endif
1629
1630 \f
1631 /**********************************************************************
1632  *                       Autodetect                                      *
1633  **********************************************************************/
1634
1635 static void
1636 autodetect_validate (Lisp_Object instantiator)
1637 {
1638   data_must_be_present (instantiator);
1639 }
1640
1641 static Lisp_Object
1642 autodetect_normalize (Lisp_Object instantiator,
1643                       Lisp_Object console_type,
1644                       Lisp_Object dest_mask)
1645 {
1646   Lisp_Object file = find_keyword_in_vector (instantiator, Q_data);
1647   Lisp_Object filename = Qnil;
1648   Lisp_Object data = Qnil;
1649   struct gcpro gcpro1, gcpro2, gcpro3;
1650   Lisp_Object alist = Qnil;
1651
1652   GCPRO3 (filename, data, alist);
1653
1654   if (NILP (file)) /* no conversion necessary */
1655     RETURN_UNGCPRO (instantiator);
1656
1657   alist = tagged_vector_to_alist (instantiator);
1658
1659   filename = locate_pixmap_file (file);
1660   if (!NILP (filename))
1661     {
1662       int xhot, yhot;
1663       /* #### Apparently some versions of XpmReadFileToData, which is
1664          called by pixmap_to_lisp_data, don't return an error value
1665          if the given file is not a valid XPM file.  Instead, they
1666          just seg fault.  It is definitely caused by passing a
1667          bitmap.  To try and avoid this we check for bitmaps first.  */
1668
1669       data = bitmap_to_lisp_data (filename, &xhot, &yhot, 1);
1670
1671       if (!EQ (data, Qt))
1672         {
1673           alist = remassq_no_quit (Q_data, alist);
1674           alist = Fcons (Fcons (Q_file, filename),
1675                          Fcons (Fcons (Q_data, data), alist));
1676           if (xhot != -1)
1677             alist = Fcons (Fcons (Q_hotspot_x, make_int (xhot)),
1678                            alist);
1679           if (yhot != -1)
1680             alist = Fcons (Fcons (Q_hotspot_y, make_int (yhot)),
1681                            alist);
1682
1683           alist = xbm_mask_file_munging (alist, filename, Qnil, console_type);
1684
1685           {
1686             Lisp_Object result = alist_to_tagged_vector (Qxbm, alist);
1687             free_alist (alist);
1688             RETURN_UNGCPRO (result);
1689           }
1690         }
1691
1692 #ifdef HAVE_XPM
1693       data = pixmap_to_lisp_data (filename, 1);
1694
1695       if (!EQ (data, Qt))
1696         {
1697           alist = remassq_no_quit (Q_data, alist);
1698           alist = Fcons (Fcons (Q_file, filename),
1699                          Fcons (Fcons (Q_data, data), alist));
1700           alist = Fcons (Fcons (Q_color_symbols,
1701                                 evaluate_xpm_color_symbols ()),
1702                          alist);
1703           {
1704             Lisp_Object result = alist_to_tagged_vector (Qxpm, alist);
1705             free_alist (alist);
1706             RETURN_UNGCPRO (result);
1707           }
1708         }
1709 #endif
1710     }
1711
1712   /* If we couldn't convert it, just put it back as it is.
1713      We might try to further frob it later as a cursor-font
1714      specification. (We can't do that now because we don't know
1715      what dest-types it's going to be instantiated into.) */
1716   {
1717     Lisp_Object result = alist_to_tagged_vector (Qautodetect, alist);
1718     free_alist (alist);
1719     RETURN_UNGCPRO (result);
1720   }
1721 }
1722
1723 static int
1724 autodetect_possible_dest_types (void)
1725 {
1726   return
1727     IMAGE_MONO_PIXMAP_MASK  |
1728     IMAGE_COLOR_PIXMAP_MASK |
1729     IMAGE_POINTER_MASK      |
1730     IMAGE_TEXT_MASK;
1731 }
1732
1733 static void
1734 autodetect_instantiate (Lisp_Object image_instance,
1735                                   Lisp_Object instantiator,
1736                                   Lisp_Object pointer_fg,
1737                                   Lisp_Object pointer_bg,
1738                                   int dest_mask, Lisp_Object domain)
1739 {
1740   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1741   struct gcpro gcpro1, gcpro2, gcpro3;
1742   Lisp_Object alist = Qnil;
1743   Lisp_Object result = Qnil;
1744   int is_cursor_font = 0;
1745
1746   GCPRO3 (data, alist, result);
1747
1748   alist = tagged_vector_to_alist (instantiator);
1749   if (dest_mask & IMAGE_POINTER_MASK)
1750     {
1751       CONST char *name_ext;
1752
1753       TO_EXTERNAL_FORMAT (LISP_STRING, data,
1754                           C_STRING_ALLOCA, name_ext,
1755                           Qfile_name);
1756
1757       if (cursor_name_to_index (name_ext) != -1)
1758         {
1759           result = alist_to_tagged_vector (Qcursor_font, alist);
1760           is_cursor_font = 1;
1761         }
1762     }
1763
1764   if (!is_cursor_font)
1765     result = alist_to_tagged_vector (Qstring, alist);
1766   free_alist (alist);
1767
1768   if (is_cursor_font)
1769     cursor_font_instantiate (image_instance, result, pointer_fg,
1770                              pointer_bg, dest_mask, domain);
1771   else
1772     string_instantiate (image_instance, result, pointer_fg,
1773                         pointer_bg, dest_mask, domain);
1774
1775   UNGCPRO;
1776 }
1777
1778 \f
1779 /**********************************************************************
1780  *                              Font                                  *
1781  **********************************************************************/
1782
1783 static void
1784 font_validate (Lisp_Object instantiator)
1785 {
1786   data_must_be_present (instantiator);
1787 }
1788
1789 static int
1790 font_possible_dest_types (void)
1791 {
1792   return IMAGE_POINTER_MASK;
1793 }
1794
1795 static void
1796 font_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1797                   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1798                   int dest_mask, Lisp_Object domain)
1799 {
1800   /* This function can GC */
1801   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1802   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1803   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1804   GdkColor fg, bg;
1805   GdkFont *source, *mask;
1806   char source_name[MAXPATHLEN], mask_name[MAXPATHLEN], dummy;
1807   int source_char, mask_char;
1808   int count;
1809   Lisp_Object foreground, background;
1810
1811   if (!DEVICE_GTK_P (XDEVICE (device)))
1812     signal_simple_error ("Not a Gtk device", device);
1813
1814   if (!STRINGP (data) ||
1815       strncmp ("FONT ", (char *) XSTRING_DATA (data), 5))
1816     signal_simple_error ("Invalid font-glyph instantiator",
1817                          instantiator);
1818
1819   if (!(dest_mask & IMAGE_POINTER_MASK))
1820     incompatible_image_types (instantiator, dest_mask, IMAGE_POINTER_MASK);
1821
1822   foreground = find_keyword_in_vector (instantiator, Q_foreground);
1823   if (NILP (foreground))
1824     foreground = pointer_fg;
1825   background = find_keyword_in_vector (instantiator, Q_background);
1826   if (NILP (background))
1827     background = pointer_bg;
1828
1829   generate_cursor_fg_bg (device, &foreground, &background, &fg, &bg);
1830
1831   count = sscanf ((char *) XSTRING_DATA (data),
1832                   "FONT %s %d %s %d %c",
1833                   source_name, &source_char,
1834                   mask_name, &mask_char, &dummy);
1835   /* Allow "%s %d %d" as well... */
1836   if (count == 3 && (1 == sscanf (mask_name, "%d %c", &mask_char, &dummy)))
1837     count = 4, mask_name[0] = 0;
1838
1839   if (count != 2 && count != 4)
1840     signal_simple_error ("invalid cursor specification", data);
1841   source = gdk_font_load (source_name);
1842   if (! source)
1843     signal_simple_error_2 ("couldn't load font",
1844                            build_string (source_name),
1845                            data);
1846   if (count == 2)
1847     mask = 0;
1848   else if (!mask_name[0])
1849     mask = source;
1850   else
1851     {
1852       mask = gdk_font_load (mask_name);
1853       if (!mask)
1854         /* continuable */
1855         Fsignal (Qerror, list3 (build_string ("couldn't load font"),
1856                                 build_string (mask_name), data));
1857     }
1858   if (!mask)
1859     mask_char = 0;
1860
1861   /* #### call XQueryTextExtents() and check_pointer_sizes() here. */
1862
1863   gtk_initialize_pixmap_image_instance (ii, 1, IMAGE_POINTER);
1864
1865   IMAGE_INSTANCE_GTK_CURSOR (ii) = NULL;
1866
1867 #if 0
1868   /* #### BILL!!! There is no way to call this function from Gdk */
1869     XCreateGlyphCursor (dpy, source, mask, source_char, mask_char,
1870                         &fg, &bg);
1871 #endif
1872   XIMAGE_INSTANCE_PIXMAP_FG (image_instance) = foreground;
1873   XIMAGE_INSTANCE_PIXMAP_BG (image_instance) = background;
1874
1875   gdk_font_unref (source);
1876   if (mask && mask != source) gdk_font_unref (mask);
1877 }
1878
1879 \f
1880 /**********************************************************************
1881  *                           Cursor-Font                              *
1882  **********************************************************************/
1883
1884 static void
1885 cursor_font_validate (Lisp_Object instantiator)
1886 {
1887   data_must_be_present (instantiator);
1888 }
1889
1890 static int
1891 cursor_font_possible_dest_types (void)
1892 {
1893   return IMAGE_POINTER_MASK;
1894 }
1895
1896 static char *__downcase (const char *name)
1897 {
1898     char *converted = strdup(name);
1899     char *work = converted;
1900
1901     while (*work)
1902     {
1903         *work = tolower(*work);
1904         work++;
1905     }
1906     return(converted);
1907 }
1908
1909 /* This is basically the equivalent of XmuCursorNameToIndex */
1910 static gint
1911 cursor_name_to_index (const char *name)
1912 {
1913     int i;
1914     static char *the_gdk_cursors[GDK_NUM_GLYPHS];
1915
1916     if (!the_gdk_cursors[GDK_BASED_ARROW_UP])
1917     {
1918         /* Need to initialize the array */
1919         /* Supposedly since this array is static it should be
1920            initialized to NULLs for us, but I'm very paranoid. */
1921         for (i = 0; i < GDK_NUM_GLYPHS; i++)
1922         {
1923             the_gdk_cursors[i] = NULL;
1924         }
1925
1926 #define FROB_CURSOR(x) the_gdk_cursors[GDK_##x] = __downcase(#x)
1927         FROB_CURSOR(ARROW);                     FROB_CURSOR(BASED_ARROW_DOWN);
1928         FROB_CURSOR(BASED_ARROW_UP);            FROB_CURSOR(BOAT);
1929         FROB_CURSOR(BOGOSITY);                  FROB_CURSOR(BOTTOM_LEFT_CORNER);
1930         FROB_CURSOR(BOTTOM_RIGHT_CORNER);       FROB_CURSOR(BOTTOM_SIDE);
1931         FROB_CURSOR(BOTTOM_TEE);                FROB_CURSOR(BOX_SPIRAL);
1932         FROB_CURSOR(CENTER_PTR);                FROB_CURSOR(CIRCLE);
1933         FROB_CURSOR(CLOCK);                     FROB_CURSOR(COFFEE_MUG);
1934         FROB_CURSOR(CROSS);                     FROB_CURSOR(CROSS_REVERSE);
1935         FROB_CURSOR(CROSSHAIR);                 FROB_CURSOR(DIAMOND_CROSS);
1936         FROB_CURSOR(DOT);                       FROB_CURSOR(DOTBOX);
1937         FROB_CURSOR(DOUBLE_ARROW);              FROB_CURSOR(DRAFT_LARGE);
1938         FROB_CURSOR(DRAFT_SMALL);               FROB_CURSOR(DRAPED_BOX);
1939         FROB_CURSOR(EXCHANGE);                  FROB_CURSOR(FLEUR);
1940         FROB_CURSOR(GOBBLER);                   FROB_CURSOR(GUMBY);
1941         FROB_CURSOR(HAND1);                     FROB_CURSOR(HAND2);
1942         FROB_CURSOR(HEART);                     FROB_CURSOR(ICON);
1943         FROB_CURSOR(IRON_CROSS);                FROB_CURSOR(LEFT_PTR);
1944         FROB_CURSOR(LEFT_SIDE);                 FROB_CURSOR(LEFT_TEE);
1945         FROB_CURSOR(LEFTBUTTON);                FROB_CURSOR(LL_ANGLE);
1946         FROB_CURSOR(LR_ANGLE);                  FROB_CURSOR(MAN);
1947         FROB_CURSOR(MIDDLEBUTTON);              FROB_CURSOR(MOUSE);
1948         FROB_CURSOR(PENCIL);                    FROB_CURSOR(PIRATE);
1949         FROB_CURSOR(PLUS);                      FROB_CURSOR(QUESTION_ARROW);
1950         FROB_CURSOR(RIGHT_PTR);                 FROB_CURSOR(RIGHT_SIDE);
1951         FROB_CURSOR(RIGHT_TEE);                 FROB_CURSOR(RIGHTBUTTON);
1952         FROB_CURSOR(RTL_LOGO);                  FROB_CURSOR(SAILBOAT);
1953         FROB_CURSOR(SB_DOWN_ARROW);             FROB_CURSOR(SB_H_DOUBLE_ARROW);
1954         FROB_CURSOR(SB_LEFT_ARROW);             FROB_CURSOR(SB_RIGHT_ARROW);
1955         FROB_CURSOR(SB_UP_ARROW);               FROB_CURSOR(SB_V_DOUBLE_ARROW);
1956         FROB_CURSOR(SHUTTLE);                   FROB_CURSOR(SIZING);
1957         FROB_CURSOR(SPIDER);                    FROB_CURSOR(SPRAYCAN);
1958         FROB_CURSOR(STAR);                      FROB_CURSOR(TARGET);
1959         FROB_CURSOR(TCROSS);                    FROB_CURSOR(TOP_LEFT_ARROW);
1960         FROB_CURSOR(TOP_LEFT_CORNER);           FROB_CURSOR(TOP_RIGHT_CORNER);
1961         FROB_CURSOR(TOP_SIDE);                  FROB_CURSOR(TOP_TEE);
1962         FROB_CURSOR(TREK);                      FROB_CURSOR(UL_ANGLE);
1963         FROB_CURSOR(UMBRELLA);                  FROB_CURSOR(UR_ANGLE);
1964         FROB_CURSOR(WATCH);                     FROB_CURSOR(XTERM);
1965         FROB_CURSOR(X_CURSOR);
1966 #undef FROB_CURSOR
1967     }
1968
1969     for (i = 0; i < GDK_NUM_GLYPHS; i++)
1970     {
1971         if (!the_gdk_cursors[i]) continue;
1972         if (!strcmp (the_gdk_cursors[i], name))
1973         {
1974             return (i);
1975         }
1976     }
1977     return(-1);
1978 }
1979
1980 static void
1981 cursor_font_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1982                          Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1983                          int dest_mask, Lisp_Object domain)
1984 {
1985   /* This function can GC */
1986   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1987   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1988   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1989   int i;
1990   CONST char *name_ext;
1991   Lisp_Object foreground, background;
1992
1993   if (!DEVICE_GTK_P (XDEVICE (device)))
1994     signal_simple_error ("Not a Gtk device", device);
1995
1996   if (!(dest_mask & IMAGE_POINTER_MASK))
1997     incompatible_image_types (instantiator, dest_mask, IMAGE_POINTER_MASK);
1998
1999   TO_EXTERNAL_FORMAT (LISP_STRING, data,
2000                       C_STRING_ALLOCA, name_ext,
2001                       Qfile_name);
2002
2003   if ((i = cursor_name_to_index (name_ext)) == -1)
2004     signal_simple_error ("Unrecognized cursor-font name", data);
2005
2006   gtk_initialize_pixmap_image_instance (ii, 1, IMAGE_POINTER);
2007   IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new (i);
2008   foreground = find_keyword_in_vector (instantiator, Q_foreground);
2009   if (NILP (foreground))
2010     foreground = pointer_fg;
2011   background = find_keyword_in_vector (instantiator, Q_background);
2012   if (NILP (background))
2013     background = pointer_bg;
2014   maybe_recolor_cursor (image_instance, foreground, background);
2015 }
2016
2017 static int
2018 gtk_colorize_image_instance (Lisp_Object image_instance,
2019                              Lisp_Object foreground, Lisp_Object background);
2020
2021 \f
2022 /************************************************************************/
2023 /*                      subwindow and widget support                      */
2024 /************************************************************************/
2025
2026 /* unmap the image if it is a widget. This is used by redisplay via
2027    redisplay_unmap_subwindows */
2028 static void
2029 gtk_unmap_subwindow (Lisp_Image_Instance *p)
2030 {
2031   if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
2032     {
2033       /* We don't support subwindows, but we do support widgets... */
2034       abort ();
2035     }
2036   else                          /* must be a widget */
2037     {
2038       /* Since we are being unmapped we want the enclosing frame to
2039          get focus. The losing with simple scrolling but is the safest
2040          thing to do. */
2041       if (IMAGE_INSTANCE_GTK_CLIPWIDGET (p))
2042         gtk_widget_unmap (IMAGE_INSTANCE_GTK_CLIPWIDGET (p));
2043     }
2044 }
2045
2046 /* map the subwindow. This is used by redisplay via
2047    redisplay_output_subwindow */
2048 static void
2049 gtk_map_subwindow (Lisp_Image_Instance *p, int x, int y,
2050                  struct display_glyph_area* dga)
2051 {
2052   assert (dga->width > 0 && dga->height > 0);
2053
2054   if (IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
2055     {
2056       /* No subwindow support... */
2057       abort ();
2058     }
2059   else                          /* must be a widget */
2060     {
2061       struct frame *f = XFRAME (IMAGE_INSTANCE_FRAME (p));
2062       GtkWidget *wid = IMAGE_INSTANCE_GTK_CLIPWIDGET (p);
2063       GtkAllocation a;
2064
2065       if (!wid) return;
2066
2067       a.x = x + IMAGE_INSTANCE_GTK_WIDGET_XOFFSET (p);
2068       a.y = y + IMAGE_INSTANCE_GTK_WIDGET_YOFFSET (p);
2069       a.width = dga->width;
2070       a.height = dga->height;
2071
2072       if ((a.width  != wid->allocation.width)  ||
2073           (a.height != wid->allocation.height))
2074         {
2075           gtk_widget_size_allocate (IMAGE_INSTANCE_GTK_CLIPWIDGET (p), &a);
2076         }
2077
2078       /* #### FIXME DAMMIT */
2079       if ((wid->allocation.x != -dga->xoffset) ||
2080           (wid->allocation.y != -dga->yoffset))
2081         {
2082           guint32 old_flags = GTK_WIDGET_FLAGS (FRAME_GTK_TEXT_WIDGET (f));
2083
2084           /* Fucking GtkFixed widget queues a resize when you add a widget.
2085           ** But only if it is visible.
2086           ** losers.
2087           */
2088           GTK_WIDGET_FLAGS(FRAME_GTK_TEXT_WIDGET (f)) &= ~GTK_VISIBLE;
2089           if (IMAGE_INSTANCE_GTK_ALREADY_PUT(p))
2090             {
2091               gtk_fixed_move (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)),
2092                               wid,
2093                               -dga->xoffset, -dga->yoffset);
2094             }
2095           else
2096             {
2097               IMAGE_INSTANCE_GTK_ALREADY_PUT(p) = TRUE;
2098               gtk_fixed_put (GTK_FIXED (FRAME_GTK_TEXT_WIDGET (f)),
2099                              wid,
2100                              -dga->xoffset, -dga->yoffset);
2101             }
2102           GTK_WIDGET_FLAGS(FRAME_GTK_TEXT_WIDGET (f)) = old_flags;
2103         }
2104
2105       if (!IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (p))
2106         {
2107           gtk_widget_map (wid);
2108         }
2109
2110       gtk_widget_draw (wid, NULL);
2111     }
2112 }
2113
2114 /* when you click on a widget you may activate another widget this
2115    needs to be checked and all appropriate widgets updated */
2116 static void
2117 gtk_redisplay_subwindow (Lisp_Image_Instance *p)
2118 {
2119   /* Update the subwindow size if necessary. */
2120   if (IMAGE_INSTANCE_SIZE_CHANGED (p))
2121     {
2122 #if 0
2123       XResizeWindow (IMAGE_INSTANCE_X_SUBWINDOW_DISPLAY (p),
2124                      IMAGE_INSTANCE_X_SUBWINDOW_ID (p),
2125                      IMAGE_INSTANCE_WIDTH (p),
2126                      IMAGE_INSTANCE_HEIGHT (p));
2127 #endif
2128     }
2129 }
2130
2131 /* Update all attributes that have changed. */
2132 static void
2133 gtk_redisplay_widget (Lisp_Image_Instance *p)
2134 {
2135   /* This function can GC if IN_REDISPLAY is false. */
2136
2137   if (!IMAGE_INSTANCE_GTK_CLIPWIDGET (p))
2138     return;
2139
2140 #ifdef HAVE_WIDGETS
2141   /* First get the items if they have changed since this is a
2142      structural change. As such it will nuke all added values so we
2143      need to update most other things after the items have changed.*/
2144   gtk_widget_show_all (IMAGE_INSTANCE_GTK_CLIPWIDGET (p));
2145   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
2146     {
2147       Lisp_Object image_instance;
2148
2149       XSETIMAGE_INSTANCE (image_instance, p);
2150
2151       /* Need to update GtkArgs that might have changed... */
2152       /* #### FIXME!!! */
2153     }
2154   else
2155     {
2156       /* #### FIXME!!! */
2157       /* No items changed, so do nothing, right? */
2158     }
2159
2160   /* Possibly update the colors and font */
2161   if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p)
2162       ||
2163       /* #### This is not sufficient because it will not cope with widgets
2164          that are not currently visible. Once redisplay has done the
2165          visible ones it will clear this flag so that when new ones
2166          become visible they will not be updated. */
2167       XFRAME (IMAGE_INSTANCE_FRAME (p))->faces_changed
2168       ||
2169       XFRAME (IMAGE_INSTANCE_FRAME (p))->frame_changed
2170       ||
2171       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p))
2172     {
2173       /* #### Write this function BILL! */
2174       update_widget_face (NULL, p, IMAGE_INSTANCE_FRAME (p));
2175     }
2176
2177   /* Possibly update the text. */
2178   if (IMAGE_INSTANCE_TEXT_CHANGED (p))
2179     {
2180       char* str;
2181       Lisp_Object val = IMAGE_INSTANCE_WIDGET_TEXT (p);
2182       LISP_STRING_TO_EXTERNAL (val, str, Qnative);
2183
2184       /* #### Need to special case each type of GtkWidget here! */
2185     }
2186
2187   /* Possibly update the size. */
2188   if (IMAGE_INSTANCE_SIZE_CHANGED (p)
2189       ||
2190       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p)
2191       ||
2192       IMAGE_INSTANCE_TEXT_CHANGED (p))
2193     {
2194       assert (IMAGE_INSTANCE_GTK_WIDGET_ID (p) &&
2195               IMAGE_INSTANCE_GTK_CLIPWIDGET (p)) ;
2196
2197       /* #### Resize the widget! */
2198       /* gtk_widget_size_allocate () */
2199     }
2200
2201   /* Adjust offsets within the frame. */
2202   if (XFRAME (IMAGE_INSTANCE_FRAME (p))->size_changed)
2203     {
2204       /* I don't think we need to do anything for Gtk here... */
2205     }
2206
2207   /* now modify the widget */
2208 #endif
2209 }
2210
2211 /* instantiate and gtk type subwindow */
2212 static void
2213 gtk_subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2214                            Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2215                            int dest_mask, Lisp_Object domain)
2216 {
2217   /* This function can GC */
2218   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2219   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
2220   Lisp_Object frame = DOMAIN_FRAME (domain);
2221
2222   if (!DEVICE_GTK_P (XDEVICE (device)))
2223     signal_simple_error ("Not a GTK device", device);
2224
2225   IMAGE_INSTANCE_TYPE (ii) = IMAGE_SUBWINDOW;
2226
2227   ii->data = xnew_and_zero (struct gtk_subwindow_data);
2228
2229   /* Create a window for clipping */
2230   IMAGE_INSTANCE_GTK_CLIPWINDOW (ii) = NULL;
2231
2232   /* Now put the subwindow inside the clip window. */
2233   IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void *) NULL;
2234 }
2235
2236 #ifdef HAVE_WIDGETS
2237 \f
2238 /************************************************************************/
2239 /*                            widgets                            */
2240 /************************************************************************/
2241 static void
2242 update_widget_face (GtkWidget *w, Lisp_Image_Instance *ii,
2243                     Lisp_Object domain)
2244 {
2245   if (0)
2246     {
2247       GtkStyle *style = gtk_widget_get_style (w);
2248       Lisp_Object pixel = Qnil;
2249       GdkColor *fcolor, *bcolor;
2250
2251       style = gtk_style_copy (style);
2252   
2253       /* Update the foreground. */
2254       pixel = FACE_FOREGROUND (IMAGE_INSTANCE_WIDGET_FACE (ii), domain);
2255       fcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (pixel));
2256
2257       /* Update the background. */
2258       pixel = FACE_BACKGROUND (IMAGE_INSTANCE_WIDGET_FACE (ii), domain);
2259       bcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (pixel));
2260
2261       /* Update the font */
2262       /* #### FIXME!!! Need to copy the widgets style, dick with it, and
2263       ** set the widgets style to the new style...
2264       */
2265       gtk_widget_set_style (w, style);
2266
2267       /* #### Megahack - but its just getting too complicated to do this
2268          in the right place. */
2269 #if 0
2270       if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qtab_control))
2271         update_tab_widget_face (wv, ii, domain);
2272 #endif
2273     }
2274 }
2275
2276 #if 0
2277 static void
2278 update_tab_widget_face (GtkWidget *w, Lisp_Image_Instance *ii,
2279                         Lisp_Object domain)
2280 {
2281   if (wv->contents)
2282     {
2283       widget_value* val = wv->contents, *cur;
2284
2285       /* Give each child label the correct foreground color. */
2286       Lisp_Object pixel = FACE_FOREGROUND
2287         (IMAGE_INSTANCE_WIDGET_FACE (ii),
2288          domain);
2289       XColor fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (pixel));
2290       lw_add_widget_value_arg (val, XtNtabForeground, fcolor.pixel);
2291       wv->change = VISIBLE_CHANGE;
2292       val->change = VISIBLE_CHANGE;
2293
2294       for (cur = val->next; cur; cur = cur->next)
2295         {
2296           cur->change = VISIBLE_CHANGE;
2297           if (cur->value)
2298             {
2299               lw_copy_widget_value_args (val, cur);
2300             }
2301         }
2302     }
2303 }
2304 #endif
2305
2306 static Lisp_Object
2307 gtk_widget_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator,
2308                           Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2309                           Lisp_Object domain)
2310 {
2311   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2312   Lisp_Object widget = Qnil;
2313   char *nm = NULL;
2314   GtkWidget *w = NULL;
2315   struct gcpro gcpro1;
2316
2317   IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
2318
2319   if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
2320     {
2321       LISP_STRING_TO_EXTERNAL (IMAGE_INSTANCE_WIDGET_TEXT (ii), nm, Qnative);
2322     }
2323
2324   ii->data = xnew_and_zero (struct gtk_subwindow_data);
2325
2326   /* Create a clipping widget */
2327   IMAGE_INSTANCE_GTK_CLIPWIDGET (ii) = NULL;
2328   IMAGE_INSTANCE_GTK_ALREADY_PUT(ii) = FALSE;
2329
2330   /* Create the actual widget */
2331   GCPRO1 (widget);
2332   widget = call5 (Qgtk_widget_instantiate_internal,
2333                   image_instance, instantiator,
2334                   pointer_fg, pointer_bg,
2335                   domain);
2336
2337   if (!NILP (widget))
2338     {
2339       CHECK_GTK_OBJECT (widget);
2340       w = GTK_WIDGET (XGTK_OBJECT (widget)->object);
2341     }
2342   else
2343     {
2344       stderr_out ("Lisp-level creation of widget failed... falling back\n");
2345       w = gtk_label_new ("Widget Creation Failed...");
2346     }
2347
2348   UNGCPRO;
2349
2350   IMAGE_INSTANCE_SUBWINDOW_ID (ii) = (void *) w;
2351
2352   /* #### HACK!!!!  We should make this do the right thing if we
2353   ** really need a clip widget!
2354   */
2355   IMAGE_INSTANCE_GTK_CLIPWIDGET (ii) = w;
2356
2357   return (Qt);
2358 }
2359
2360 static void
2361 gtk_widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
2362                         Lisp_Object pointer_fg, Lisp_Object pointer_bg,
2363                         int dest_mask, Lisp_Object domain)
2364 {
2365   call_with_suspended_errors ((lisp_fn_t) gtk_widget_instantiate_1,
2366                               Qnil, Qimage,
2367                               ERROR_ME_WARN, 5,
2368                               image_instance, instantiator,
2369                               pointer_fg,
2370                               pointer_bg,
2371                               domain);
2372 }
2373
2374 /* get properties of a control */
2375 static Lisp_Object
2376 gtk_widget_property (Lisp_Object image_instance, Lisp_Object prop)
2377 {
2378   /* Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); */
2379
2380   /* get the text from a control */
2381   if (EQ (prop, Q_text))
2382     {
2383       return Qnil;
2384     }
2385   return Qunbound;
2386 }
2387
2388 #define FAKE_GTK_WIDGET_INSTANTIATOR(x)                                 \
2389 static void                                                             \
2390 gtk_##x##_instantiate (Lisp_Object image_instance,                      \
2391    Lisp_Object instantiator,                                            \
2392    Lisp_Object pointer_fg,                                              \
2393    Lisp_Object pointer_bg,                                              \
2394    int dest_mask, Lisp_Object domain)                                   \
2395 {                                                                       \
2396   gtk_widget_instantiate (image_instance, instantiator, pointer_fg,     \
2397                           pointer_bg, dest_mask, domain);               \
2398 }
2399
2400 FAKE_GTK_WIDGET_INSTANTIATOR(native_layout);
2401 FAKE_GTK_WIDGET_INSTANTIATOR(button);
2402 FAKE_GTK_WIDGET_INSTANTIATOR(progress_gauge);
2403 FAKE_GTK_WIDGET_INSTANTIATOR(edit_field);
2404 FAKE_GTK_WIDGET_INSTANTIATOR(combo_box);
2405 FAKE_GTK_WIDGET_INSTANTIATOR(tab_control);
2406 FAKE_GTK_WIDGET_INSTANTIATOR(label);
2407
2408 /* Update a button's clicked state. */
2409 static void
2410 gtk_button_redisplay (Lisp_Object image_instance)
2411 {
2412   /* This function can GC if IN_REDISPLAY is false. */
2413   Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
2414   GtkWidget *w = IMAGE_INSTANCE_GTK_CLIPWIDGET (p);
2415
2416   if (GTK_WIDGET_TYPE (w) == gtk_button_get_type ())
2417     {
2418     }
2419   else if (GTK_WIDGET_TYPE (w) == gtk_check_button_get_type ())
2420     {
2421     }
2422   else if (GTK_WIDGET_TYPE (w) == gtk_radio_button_get_type ())
2423     {
2424     }
2425   else
2426     {
2427       /* Unknown button type... */
2428       abort();
2429     }
2430 }
2431
2432 /* get properties of a button */
2433 static Lisp_Object
2434 gtk_button_property (Lisp_Object image_instance, Lisp_Object prop)
2435 {
2436   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2437
2438   /* check the state of a button */
2439   if (EQ (prop, Q_selected))
2440     {
2441       if (GTK_WIDGET_HAS_FOCUS (IMAGE_INSTANCE_SUBWINDOW_ID (ii)))
2442         return Qt;
2443       else
2444         return Qnil;
2445     }
2446   return Qunbound;
2447 }
2448
2449 /* set the properties of a progress gauge */
2450 static void
2451 gtk_progress_gauge_redisplay (Lisp_Object image_instance)
2452 {
2453   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2454
2455   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
2456     {
2457       gfloat f;
2458       Lisp_Object val;
2459
2460       val = XGUI_ITEM (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))->value;
2461       f = XFLOATINT (val);
2462
2463       gtk_progress_set_value (GTK_PROGRESS (IMAGE_INSTANCE_SUBWINDOW_ID (ii)),
2464                               f);
2465     }
2466 }
2467
2468 /* Set the properties of a tab control */
2469 static void
2470 gtk_tab_control_redisplay (Lisp_Object image_instance)
2471 {
2472   /* #### Convert this to GTK baby! */
2473   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
2474
2475   if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) ||
2476       IMAGE_INSTANCE_WIDGET_ACTION_OCCURRED (ii))
2477     {
2478       /* If only the order has changed then simply select the first
2479          one of the pending set. This stops horrendous rebuilding -
2480          and hence flicker - of the tabs each time you click on
2481          one. */
2482       if (tab_control_order_only_changed (image_instance))
2483         {
2484           Lisp_Object rest, selected =
2485             gui_item_list_find_selected
2486             (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)) ?
2487              XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)) :
2488              XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii)));
2489
2490           LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
2491             {
2492               if (gui_item_equal_sans_selected (XCAR (rest), selected, 0))
2493                 {
2494                   Lisp_Object old_selected =gui_item_list_find_selected
2495                     (XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)));
2496
2497                   /* Need to focus on the widget... */
2498                   stderr_out ("Hey, change the tab-focus you boob...\n");
2499
2500                   /* Pick up the new selected item. */
2501                   XGUI_ITEM (old_selected)->selected =
2502                     XGUI_ITEM (XCAR (rest))->selected;
2503                   XGUI_ITEM (XCAR (rest))->selected =
2504                     XGUI_ITEM (selected)->selected;
2505                   /* We're not actually changing the items anymore. */
2506                   IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 0;
2507                   IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
2508                   break;
2509                 }
2510             }
2511         }
2512       else
2513         {
2514           /* More than just the order has changed... let's get busy! */
2515           GtkNotebook *nb = GTK_NOTEBOOK (IMAGE_INSTANCE_GTK_CLIPWIDGET (ii));
2516           guint num_pages = g_list_length (nb->children);
2517           Lisp_Object rest;
2518
2519           if (num_pages >= 0)
2520             {
2521               int i;
2522               for (i = num_pages; i >= 0; --i)
2523                 {
2524                   gtk_notebook_remove_page (nb, i);
2525                 }
2526             }
2527
2528           LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
2529             {
2530               Lisp_Gui_Item *pgui = XGUI_ITEM (XCAR (rest));
2531               char *c_name = NULL;
2532
2533               if (!STRINGP (pgui->name))
2534                 pgui->name = Feval (pgui->name);
2535
2536               CHECK_STRING (pgui->name);
2537
2538               TO_EXTERNAL_FORMAT (LISP_STRING, pgui->name,
2539                                   C_STRING_ALLOCA, c_name,
2540                                   Qctext);
2541
2542               gtk_notebook_append_page (nb,
2543                                         gtk_vbox_new (FALSE, 3),
2544                                         gtk_label_new (c_name));
2545             }
2546
2547           /* Show all the new widgets we just added... */
2548           gtk_widget_show_all (GTK_WIDGET (nb));
2549         }
2550     }
2551
2552   /* Possibly update the face. */
2553 #if 0
2554   if (IMAGE_INSTANCE_WIDGET_FACE_CHANGED (ii)
2555       ||
2556       XFRAME (IMAGE_INSTANCE_FRAME (ii))->faces_changed
2557       ||
2558       IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii))
2559     {
2560       update_tab_widget_face (wv, ii,
2561                               IMAGE_INSTANCE_FRAME (ii));
2562     }
2563 #endif
2564 }
2565 #endif /* HAVE_WIDGETS */
2566
2567 \f
2568 /************************************************************************/
2569 /*                            initialization                            */
2570 /************************************************************************/
2571 void
2572 syms_of_glyphs_gtk (void)
2573 {
2574   defkeyword (&Q_resource_id, ":resource-id");
2575   defkeyword (&Q_resource_type, ":resource-type");
2576 #ifdef HAVE_WIDGETS
2577   defsymbol (&Qgtk_widget_instantiate_internal, "gtk-widget-instantiate-internal");
2578   defsymbol (&Qgtk_widget_property_internal, "gtk-widget-property-internal");
2579   defsymbol (&Qgtk_widget_redisplay_internal, "gtk-widget-redisplay-internal");
2580   defsymbol (&Qgtk_widget_set_style, "gtk-widget-set-style");
2581 #endif
2582 }
2583
2584 void
2585 console_type_create_glyphs_gtk (void)
2586 {
2587   /* image methods */
2588   CONSOLE_HAS_METHOD (gtk, print_image_instance);
2589   CONSOLE_HAS_METHOD (gtk, finalize_image_instance);
2590   CONSOLE_HAS_METHOD (gtk, image_instance_equal);
2591   CONSOLE_HAS_METHOD (gtk, image_instance_hash);
2592   CONSOLE_HAS_METHOD (gtk, colorize_image_instance);
2593   CONSOLE_HAS_METHOD (gtk, init_image_instance_from_eimage);
2594   CONSOLE_HAS_METHOD (gtk, locate_pixmap_file);
2595   CONSOLE_HAS_METHOD (gtk, unmap_subwindow);
2596   CONSOLE_HAS_METHOD (gtk, map_subwindow);
2597   CONSOLE_HAS_METHOD (gtk, redisplay_widget);
2598   CONSOLE_HAS_METHOD (gtk, redisplay_subwindow);
2599 }
2600
2601 void
2602 image_instantiator_format_create_glyphs_gtk (void)
2603 {
2604   IIFORMAT_VALID_CONSOLE (gtk, nothing);
2605   IIFORMAT_VALID_CONSOLE (gtk, string);
2606 #ifdef HAVE_WIDGETS
2607   IIFORMAT_VALID_CONSOLE (gtk, layout);
2608 #endif
2609   IIFORMAT_VALID_CONSOLE (gtk, formatted_string);
2610   IIFORMAT_VALID_CONSOLE (gtk, inherit);
2611 #ifdef HAVE_XPM
2612   INITIALIZE_DEVICE_IIFORMAT (gtk, xpm);
2613   IIFORMAT_HAS_DEVMETHOD (gtk, xpm, instantiate);
2614 #endif
2615 #ifdef HAVE_JPEG
2616   IIFORMAT_VALID_CONSOLE (gtk, jpeg);
2617 #endif
2618 #ifdef HAVE_TIFF
2619   IIFORMAT_VALID_CONSOLE (gtk, tiff);
2620 #endif
2621 #ifdef HAVE_PNG
2622   IIFORMAT_VALID_CONSOLE (gtk, png);
2623 #endif
2624 #ifdef HAVE_GIF
2625   IIFORMAT_VALID_CONSOLE (gtk, gif);
2626 #endif
2627
2628   INITIALIZE_DEVICE_IIFORMAT (gtk, subwindow);
2629   IIFORMAT_HAS_DEVMETHOD (gtk, subwindow, instantiate);
2630
2631 #ifdef HAVE_WIDGETS
2632   /* layout widget */
2633   INITIALIZE_DEVICE_IIFORMAT (gtk, native_layout);
2634   IIFORMAT_HAS_DEVMETHOD (gtk, native_layout, instantiate);
2635
2636   /* button widget */
2637   INITIALIZE_DEVICE_IIFORMAT (gtk, button);
2638   IIFORMAT_HAS_DEVMETHOD (gtk, button, property);
2639   IIFORMAT_HAS_DEVMETHOD (gtk, button, instantiate);
2640   IIFORMAT_HAS_DEVMETHOD (gtk, button, redisplay);
2641   /* general widget methods. */
2642   INITIALIZE_DEVICE_IIFORMAT (gtk, widget);
2643   IIFORMAT_HAS_DEVMETHOD (gtk, widget, property);
2644
2645   /* progress gauge */
2646   INITIALIZE_DEVICE_IIFORMAT (gtk, progress_gauge);
2647   IIFORMAT_HAS_DEVMETHOD (gtk, progress_gauge, redisplay);
2648   IIFORMAT_HAS_DEVMETHOD (gtk, progress_gauge, instantiate);
2649   /* text field */
2650   INITIALIZE_DEVICE_IIFORMAT (gtk, edit_field);
2651   IIFORMAT_HAS_DEVMETHOD (gtk, edit_field, instantiate);
2652   INITIALIZE_DEVICE_IIFORMAT (gtk, combo_box);
2653   IIFORMAT_HAS_DEVMETHOD (gtk, combo_box, instantiate);
2654   IIFORMAT_HAS_SHARED_DEVMETHOD (gtk, combo_box, redisplay, tab_control);
2655   /* tab control widget */
2656   INITIALIZE_DEVICE_IIFORMAT (gtk, tab_control);
2657   IIFORMAT_HAS_DEVMETHOD (gtk, tab_control, instantiate);
2658   IIFORMAT_HAS_DEVMETHOD (gtk, tab_control, redisplay);
2659   /* label */
2660   INITIALIZE_DEVICE_IIFORMAT (gtk, label);
2661   IIFORMAT_HAS_DEVMETHOD (gtk, label, instantiate);
2662 #endif
2663
2664   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (cursor_font, "cursor-font");
2665   IIFORMAT_VALID_CONSOLE (gtk, cursor_font);
2666
2667   IIFORMAT_HAS_METHOD (cursor_font, validate);
2668   IIFORMAT_HAS_METHOD (cursor_font, possible_dest_types);
2669   IIFORMAT_HAS_METHOD (cursor_font, instantiate);
2670
2671   IIFORMAT_VALID_KEYWORD (cursor_font, Q_data, check_valid_string);
2672   IIFORMAT_VALID_KEYWORD (cursor_font, Q_foreground, check_valid_string);
2673   IIFORMAT_VALID_KEYWORD (cursor_font, Q_background, check_valid_string);
2674
2675   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (font, "font");
2676   IIFORMAT_VALID_CONSOLE (gtk, font);
2677
2678   IIFORMAT_HAS_METHOD (font, validate);
2679   IIFORMAT_HAS_METHOD (font, possible_dest_types);
2680   IIFORMAT_HAS_METHOD (font, instantiate);
2681
2682   IIFORMAT_VALID_KEYWORD (font, Q_data, check_valid_string);
2683   IIFORMAT_VALID_KEYWORD (font, Q_foreground, check_valid_string);
2684   IIFORMAT_VALID_KEYWORD (font, Q_background, check_valid_string);
2685
2686 #ifdef HAVE_XPM
2687   INITIALIZE_DEVICE_IIFORMAT (gtk, xpm);
2688   IIFORMAT_HAS_DEVMETHOD (gtk, xpm, instantiate);
2689 #endif
2690
2691 #ifdef HAVE_XFACE
2692   INITIALIZE_DEVICE_IIFORMAT (gtk, xface);
2693   IIFORMAT_HAS_DEVMETHOD (gtk, xface, instantiate);
2694 #endif
2695
2696   INITIALIZE_DEVICE_IIFORMAT (gtk, xbm);
2697   IIFORMAT_HAS_DEVMETHOD (gtk, xbm, instantiate);
2698   IIFORMAT_VALID_CONSOLE (gtk, xbm);
2699
2700   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (gtk_resource, "gtk-resource");
2701   IIFORMAT_VALID_CONSOLE (gtk, gtk_resource);
2702
2703   IIFORMAT_HAS_METHOD (gtk_resource, validate);
2704   IIFORMAT_HAS_METHOD (gtk_resource, normalize);
2705   IIFORMAT_HAS_METHOD (gtk_resource, possible_dest_types);
2706   IIFORMAT_HAS_METHOD (gtk_resource, instantiate);
2707
2708   IIFORMAT_VALID_KEYWORD (gtk_resource, Q_resource_type, check_valid_resource_symbol);
2709   IIFORMAT_VALID_KEYWORD (gtk_resource, Q_resource_id, check_valid_resource_id);
2710   IIFORMAT_VALID_KEYWORD (gtk_resource, Q_file, check_valid_string);
2711
2712   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (autodetect, "autodetect");
2713   IIFORMAT_VALID_CONSOLE (gtk, autodetect);
2714
2715   IIFORMAT_HAS_METHOD (autodetect, validate);
2716   IIFORMAT_HAS_METHOD (autodetect, normalize);
2717   IIFORMAT_HAS_METHOD (autodetect, possible_dest_types);
2718   IIFORMAT_HAS_METHOD (autodetect, instantiate);
2719
2720   IIFORMAT_VALID_KEYWORD (autodetect, Q_data, check_valid_string);
2721 }
2722
2723 void
2724 vars_of_glyphs_gtk (void)
2725 {
2726 #ifdef HAVE_XFACE
2727   Fprovide (Qxface);
2728 #endif
2729
2730   DEFVAR_LISP ("gtk-bitmap-file-path", &Vgtk_bitmap_file_path /*
2731 A list of the directories in which X bitmap files may be found.
2732 If nil, this is initialized from the "*bitmapFilePath" resource.
2733 This is used by the `make-image-instance' function (however, note that if
2734 the environment variable XBMLANGPATH is set, it is consulted first).
2735 */ );
2736   Vgtk_bitmap_file_path = Qnil;
2737 }
2738
2739 void
2740 complex_vars_of_glyphs_gtk (void)
2741 {
2742 #define BUILD_GLYPH_INST(variable, name)                        \
2743   Fadd_spec_to_specifier                                        \
2744     (GLYPH_IMAGE (XGLYPH (variable)),                           \
2745      vector3 (Qxbm, Q_data,                                     \
2746               list3 (make_int (name##_width),                   \
2747                      make_int (name##_height),                  \
2748                      make_ext_string (name##_bits,              \
2749                                       sizeof (name##_bits),     \
2750                                       Qbinary))),               \
2751      Qglobal, Qgtk, Qnil)
2752
2753   BUILD_GLYPH_INST (Vtruncation_glyph, truncator);
2754   BUILD_GLYPH_INST (Vcontinuation_glyph, continuer);
2755   BUILD_GLYPH_INST (Vxemacs_logo, xemacs);
2756   BUILD_GLYPH_INST (Vhscroll_glyph, hscroll);
2757
2758 #undef BUILD_GLYPH_INST
2759 }
2760
2761 \f
2762 /* Ripped off from glyphs-msw.c */
2763 /*
2764  * The data returned by the following routine is always in left-most byte
2765  * first and left-most bit first.  If it doesn't return BitmapSuccess then
2766  * its arguments won't have been touched.  This routine should look as much
2767  * like the Xlib routine XReadBitmapfile as possible.
2768  */
2769 #define MAX_SIZE 1024
2770
2771 /* shared data for the image read/parse logic */
2772 static short hexTable[256];             /* conversion value */
2773 static int initialized = FALSE; /* easier to fill in at run time */
2774
2775 /*
2776  *      Table index for the hex values. Initialized once, first time.
2777  *      Used for translation value or delimiter significance lookup.
2778  */
2779 static void initHexTable()
2780 {
2781     /*
2782      * We build the table at run time for several reasons:
2783      *
2784      *     1.  portable to non-ASCII machines.
2785      *     2.  still reentrant since we set the init flag after setting table.
2786      *     3.  easier to extend.
2787      *     4.  less prone to bugs.
2788      */
2789     hexTable['0'] = 0;  hexTable['1'] = 1;
2790     hexTable['2'] = 2;  hexTable['3'] = 3;
2791     hexTable['4'] = 4;  hexTable['5'] = 5;
2792     hexTable['6'] = 6;  hexTable['7'] = 7;
2793     hexTable['8'] = 8;  hexTable['9'] = 9;
2794     hexTable['A'] = 10; hexTable['B'] = 11;
2795     hexTable['C'] = 12; hexTable['D'] = 13;
2796     hexTable['E'] = 14; hexTable['F'] = 15;
2797     hexTable['a'] = 10; hexTable['b'] = 11;
2798     hexTable['c'] = 12; hexTable['d'] = 13;
2799     hexTable['e'] = 14; hexTable['f'] = 15;
2800
2801     /* delimiters of significance are flagged w/ negative value */
2802     hexTable[' '] = -1; hexTable[','] = -1;
2803     hexTable['}'] = -1; hexTable['\n'] = -1;
2804     hexTable['\t'] = -1;
2805         
2806     initialized = TRUE;
2807 }
2808
2809 /*
2810  *      read next hex value in the input stream, return -1 if EOF
2811  */
2812 static int NextInt ( FILE *fstream )
2813 {
2814     int ch;
2815     int value = 0;
2816     int gotone = 0;
2817     int done = 0;
2818     
2819     /* loop, accumulate hex value until find delimiter  */
2820     /* skip any initial delimiters found in read stream */
2821
2822     while (!done) {
2823         ch = getc(fstream);
2824         if (ch == EOF) {
2825             value       = -1;
2826             done++;
2827         } else {
2828             /* trim high bits, check type and accumulate */
2829             ch &= 0xff;
2830             if (isascii(ch) && isxdigit(ch)) {
2831                 value = (value << 4) + hexTable[ch];
2832                 gotone++;
2833             } else if ((hexTable[ch]) < 0 && gotone)
2834               done++;
2835         }
2836     }
2837     return value;
2838 }
2839
2840 int read_bitmap_data (fstream, width, height, datap, x_hot, y_hot)
2841     FILE *fstream;                      /* handle on file  */
2842     unsigned int *width, *height;       /* RETURNED */
2843     unsigned char **datap;              /* RETURNED */
2844     int *x_hot, *y_hot;                 /* RETURNED */
2845 {
2846     unsigned char *data = NULL;         /* working variable */
2847     char line[MAX_SIZE];                /* input line from file */
2848     int size;                           /* number of bytes of data */
2849     char name_and_type[MAX_SIZE];       /* an input line */
2850     char *type;                         /* for parsing */
2851     int value;                          /* from an input line */
2852     int version10p;                     /* boolean, old format */
2853     int padding;                        /* to handle alignment */
2854     int bytes_per_line;                 /* per scanline of data */
2855     unsigned int ww = 0;                /* width */
2856     unsigned int hh = 0;                /* height */
2857     int hx = -1;                        /* x hotspot */
2858     int hy = -1;                        /* y hotspot */
2859
2860 #define Xmalloc(size) malloc(size)
2861
2862     /* first time initialization */
2863     if (initialized == FALSE) initHexTable();
2864
2865     /* error cleanup and return macro   */
2866 #define RETURN(code) { if (data) free (data); return code; }
2867
2868     while (fgets(line, MAX_SIZE, fstream)) {
2869         if (strlen(line) == MAX_SIZE-1) {
2870             RETURN (BitmapFileInvalid);
2871         }
2872         if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
2873             if (!(type = strrchr(name_and_type, '_')))
2874                 type = name_and_type;
2875             else
2876                 type++;
2877
2878             if (!strcmp("width", type))
2879                 ww = (unsigned int) value;
2880             if (!strcmp("height", type))
2881                 hh = (unsigned int) value;
2882             if (!strcmp("hot", type)) {
2883                 if (type-- == name_and_type || type-- == name_and_type)
2884                     continue;
2885                 if (!strcmp("x_hot", type))
2886                     hx = value;
2887                 if (!strcmp("y_hot", type))
2888                     hy = value;
2889             }
2890             continue;
2891         }
2892     
2893         if (sscanf(line, "static short %s = {", name_and_type) == 1)
2894             version10p = 1;
2895         else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
2896             version10p = 0;
2897         else if (sscanf(line, "static char %s = {", name_and_type) == 1)
2898             version10p = 0;
2899         else
2900             continue;
2901
2902         if (!(type = strrchr(name_and_type, '_')))
2903             type = name_and_type;
2904         else
2905             type++;
2906
2907         if (strcmp("bits[]", type))
2908             continue;
2909     
2910         if (!ww || !hh)
2911             RETURN (BitmapFileInvalid);
2912
2913         if ((ww % 16) && ((ww % 16) < 9) && version10p)
2914             padding = 1;
2915         else
2916             padding = 0;
2917
2918         bytes_per_line = (ww+7)/8 + padding;
2919
2920         size = bytes_per_line * hh;
2921         data = (unsigned char *) Xmalloc ((unsigned int) size);
2922         if (!data) 
2923             RETURN (BitmapNoMemory);
2924
2925         if (version10p) {
2926             unsigned char *ptr;
2927             int bytes;
2928
2929             for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
2930                 if ((value = NextInt(fstream)) < 0)
2931                     RETURN (BitmapFileInvalid);
2932                 *(ptr++) = value;
2933                 if (!padding || ((bytes+2) % bytes_per_line))
2934                     *(ptr++) = value >> 8;
2935             }
2936         } else {
2937             unsigned char *ptr;
2938             int bytes;
2939
2940             for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
2941                 if ((value = NextInt(fstream)) < 0) 
2942                     RETURN (BitmapFileInvalid);
2943                 *ptr=value;
2944             }
2945         }
2946         break;
2947     }                                   /* end while */
2948
2949     if (data == NULL) {
2950         RETURN (BitmapFileInvalid);
2951     }
2952
2953     *datap = data;
2954     data = NULL;
2955     *width = ww;
2956     *height = hh;
2957     if (x_hot) *x_hot = hx;
2958     if (y_hot) *y_hot = hy;
2959
2960     RETURN (BitmapSuccess);
2961 }
2962
2963
2964 int read_bitmap_data_from_file (CONST char *filename, unsigned int *width, 
2965                                 unsigned int *height, unsigned char **datap,
2966                                 int *x_hot, int *y_hot)
2967 {
2968     FILE *fstream;
2969     int rval;
2970
2971     if ((fstream = fopen (filename, "r")) == NULL) {
2972         return BitmapOpenFailed;
2973     }
2974     rval = read_bitmap_data (fstream, width, height, datap, x_hot, y_hot);
2975     fclose (fstream);
2976     return rval;
2977 }
2978
2979 /* X specific crap */
2980 #include <gdk/gdkx.h>
2981 /* #### Should remove all this X specific stuff when GTK/GDK matures a
2982    bit more and provides an abstraction for it. */
2983 static int
2984 gtk_colorize_image_instance (Lisp_Object image_instance,
2985                              Lisp_Object foreground, Lisp_Object background)
2986 {
2987   struct Lisp_Image_Instance *p;
2988
2989   p = XIMAGE_INSTANCE (image_instance);
2990
2991   switch (IMAGE_INSTANCE_TYPE (p))
2992     {
2993     case IMAGE_MONO_PIXMAP:
2994       IMAGE_INSTANCE_TYPE (p) = IMAGE_COLOR_PIXMAP;
2995       /* Make sure there aren't two pointers to the same mask, causing
2996          it to get freed twice. */
2997       IMAGE_INSTANCE_GTK_MASK (p) = 0;
2998       break;
2999
3000     default:
3001       return 0;
3002     }
3003
3004   {
3005     GdkWindow *draw = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (IMAGE_INSTANCE_DEVICE (p))));
3006     GdkPixmap *new_pxmp = gdk_pixmap_new (draw,
3007                                           IMAGE_INSTANCE_PIXMAP_WIDTH (p),
3008                                           IMAGE_INSTANCE_PIXMAP_HEIGHT (p),
3009                                           DEVICE_GTK_DEPTH (XDEVICE (IMAGE_INSTANCE_DEVICE (p))));
3010     GdkGCValues gcv;
3011     GdkGC *gc;
3012
3013     gcv.foreground = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (foreground));
3014     gcv.background = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (background));
3015     gc = gdk_gc_new_with_values (new_pxmp, &gcv, GDK_GC_BACKGROUND | GDK_GC_FOREGROUND);
3016
3017     XCopyPlane (GDK_WINDOW_XDISPLAY (draw),
3018                 GDK_WINDOW_XWINDOW (IMAGE_INSTANCE_GTK_PIXMAP (p)),
3019                 GDK_WINDOW_XWINDOW (new_pxmp),
3020                 GDK_GC_XGC (gc), 0, 0,
3021                 IMAGE_INSTANCE_PIXMAP_WIDTH (p),
3022                 IMAGE_INSTANCE_PIXMAP_HEIGHT (p),
3023                 0, 0, 1);
3024
3025     gdk_gc_destroy (gc);
3026     IMAGE_INSTANCE_GTK_PIXMAP (p) = new_pxmp;
3027     IMAGE_INSTANCE_PIXMAP_DEPTH (p) = DEVICE_GTK_DEPTH (XDEVICE (IMAGE_INSTANCE_DEVICE (p)));
3028     IMAGE_INSTANCE_PIXMAP_FG (p) = foreground;
3029     IMAGE_INSTANCE_PIXMAP_BG (p) = background;
3030     return 1;
3031   }
3032 }
3033