XEmacs 21.2.5
[chise/xemacs-chise.git.1] / src / glyphs-msw.c
1 /* mswindows-specific Lisp objects.
2    Copyright (C) 1998 Andy Piper.
3    
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* Synched up with: Not in FSF. */
22
23 /* written by Andy Piper <andyp@parallax.co.uk> plagerising buts from
24    glyphs-x.c */
25
26 #include <config.h>
27 #include "lisp.h"
28 #include "lstream.h"
29
30 #define OEMRESOURCE /* Define OCR_ and friend constants */
31 #include "console-msw.h"
32 #include "glyphs-msw.h"
33 #include "objects-msw.h"
34
35 #include "buffer.h"
36 #include "frame.h"
37 #include "insdel.h"
38 #include "opaque.h"
39 #include "sysfile.h"
40 #include "faces.h"
41 #include "imgproc.h"
42
43 #ifdef FILE_CODING
44 #include "file-coding.h"
45 #endif
46 #include <stdio.h>
47 #include <ctype.h>
48
49
50 DEFINE_IMAGE_INSTANTIATOR_FORMAT (bmp);
51 Lisp_Object Qbmp;
52 Lisp_Object Vmswindows_bitmap_file_path;
53 static  COLORREF transparent_color = RGB (1,1,1);
54
55 DEFINE_IMAGE_INSTANTIATOR_FORMAT (mswindows_resource);
56 Lisp_Object Q_resource_type, Q_resource_id;
57 Lisp_Object Qmswindows_resource;
58
59 static void
60 mswindows_initialize_dibitmap_image_instance (struct Lisp_Image_Instance *ii,
61                                             enum image_instance_type type);
62 static void
63 mswindows_initialize_image_instance_mask (struct Lisp_Image_Instance* image, 
64                                           struct frame* f);
65
66 COLORREF mswindows_string_to_color (CONST char *name);
67
68 #define BPLINE(width) ((int)(~3UL & (unsigned long)((width) +3)))
69
70 /************************************************************************/
71 /* convert from a series of RGB triples to a BITMAPINFO formated for the*/
72 /* proper display                                                       */
73 /************************************************************************/
74 static BITMAPINFO* convert_EImage_to_DIBitmap (Lisp_Object device,
75                                                int width, int height,
76                                                unsigned char *pic,
77                                                int *bit_count,
78                                                unsigned char** bmp_data)
79 {
80   struct device *d = XDEVICE (device);
81   int i,j;
82   RGBQUAD* colortbl;
83   int           ncolors;
84   BITMAPINFO*   bmp_info;
85   unsigned char *ip, *dp;
86
87   if (DEVICE_MSWINDOWS_BITSPIXEL (d) > 0)
88     {
89       int bpline = BPLINE(width * 3);
90       /* FIXME: we can do this because 24bpp implies no color table, once
91        * we start palettizing this is no longer true. The X versions of
92        * this function quantises to 256 colors or bit masks down to a
93        * long. Windows can actually handle rgb triples in the raw so I
94        * don't see much point trying to optimize down to the best
95        * structure - unless it has memory / color allocation implications
96        * .... */
97       bmp_info=xnew_and_zero (BITMAPINFO);
98       
99       if (!bmp_info)
100         {
101           return NULL;
102         }
103
104       bmp_info->bmiHeader.biBitCount=24; /* just RGB triples for now */
105       bmp_info->bmiHeader.biCompression=BI_RGB; /* just RGB triples for now */
106       bmp_info->bmiHeader.biSizeImage=width*height*3; 
107
108       /* bitmap data needs to be in blue, green, red triples - in that
109          order, eimage is in RGB format so we need to convert */
110       *bmp_data = xnew_array_and_zero (unsigned char, bpline * height);
111       *bit_count = bpline * height;
112
113       if (!bmp_data)
114         {
115           xfree (bmp_info);
116           return NULL;
117         }
118
119       ip = pic;
120       for (i = height-1; i >= 0; i--) {
121         dp = (*bmp_data) + (i * bpline);
122         for (j = 0; j < width; j++) {
123           dp[2] =*ip++;
124           dp[1] =*ip++;
125           *dp   =*ip++;
126           dp += 3;
127         }
128       }
129     }
130   else                          /* scale to 256 colors */
131     {
132       int rd,gr,bl;
133       quant_table *qtable;
134       int bpline = BPLINE (width * 3);
135       /* Quantize the image and get a histogram while we're at it.
136          Do this first to save memory */
137       qtable = build_EImage_quantable(pic, width, height, 256);
138       if (qtable == NULL) return NULL;
139
140       /* use our quantize table to allocate the colors */
141       ncolors = qtable->num_active_colors;
142       bmp_info=(BITMAPINFO*)xmalloc_and_zero (sizeof(BITMAPINFOHEADER) + 
143                                              sizeof(RGBQUAD) * ncolors);
144       if (!bmp_info)
145         {
146           xfree (qtable);
147           return NULL;
148         }
149
150       colortbl=(RGBQUAD*)(((unsigned char*)bmp_info)+sizeof(BITMAPINFOHEADER));
151
152       bmp_info->bmiHeader.biBitCount=8; 
153       bmp_info->bmiHeader.biCompression=BI_RGB; 
154       bmp_info->bmiHeader.biSizeImage=bpline*height;
155       bmp_info->bmiHeader.biClrUsed=ncolors; 
156       bmp_info->bmiHeader.biClrImportant=ncolors; 
157       
158       *bmp_data = (unsigned char *) xmalloc_and_zero (bpline * height);
159       *bit_count = bpline * height;
160
161       if (!*bmp_data)
162         {
163           xfree (qtable);
164           xfree (bmp_info);
165           return NULL;
166         }
167       
168       /* build up an RGBQUAD colortable */
169       for (i = 0; i < qtable->num_active_colors; i++) {
170         colortbl[i].rgbRed = (BYTE) qtable->rm[i];
171         colortbl[i].rgbGreen = (BYTE) qtable->gm[i];
172         colortbl[i].rgbBlue = (BYTE) qtable->bm[i];
173         colortbl[i].rgbReserved = 0;
174       }
175
176       /* now build up the data. picture has to be upside-down and
177          back-to-front for msw bitmaps */
178       ip = pic;
179       for (i = height-1; i >= 0; i--) {
180         dp = (*bmp_data) + (i * bpline);
181         for (j = 0; j < width; j++) {
182           rd = *ip++;
183           gr = *ip++;
184           bl = *ip++;
185           *dp++ = QUANT_GET_COLOR (qtable,rd,gr,bl);
186         }
187       }
188       xfree (qtable);
189     } 
190   /* fix up the standard stuff */
191   bmp_info->bmiHeader.biWidth=width;
192   bmp_info->bmiHeader.biHeight=height;
193   bmp_info->bmiHeader.biPlanes=1;
194   bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
195   bmp_info->bmiHeader.biXPelsPerMeter=0; /* unless you know better */
196   bmp_info->bmiHeader.biYPelsPerMeter=0; 
197
198   return bmp_info;
199 }
200
201 /* Given a pixmap filename, look through all of the "standard" places
202    where the file might be located.  Return a full pathname if found;
203    otherwise, return Qnil. */
204
205 static Lisp_Object
206 mswindows_locate_pixmap_file (Lisp_Object name)
207 {
208   /* This function can GC if IN_REDISPLAY is false */
209   Lisp_Object found;
210
211   /* Check non-absolute pathnames with a directory component relative to
212      the search path; that's the way Xt does it. */
213   if (IS_DIRECTORY_SEP(XSTRING_BYTE (name, 0)) ||
214       (XSTRING_BYTE (name, 0) == '.' &&
215        (IS_DIRECTORY_SEP(XSTRING_BYTE (name, 1)) ||
216         (XSTRING_BYTE (name, 1) == '.' &&
217          (IS_DIRECTORY_SEP(XSTRING_BYTE (name, 2)))))))
218     {
219       if (!NILP (Ffile_readable_p (name)))
220         return name;
221       else
222         return Qnil;
223     }
224
225   if (locate_file (Vmswindows_bitmap_file_path, name, "", &found, R_OK) < 0)
226     {
227       Lisp_Object temp = list1 (Vdata_directory);
228       struct gcpro gcpro1;
229
230       GCPRO1 (temp);
231       locate_file (temp, name, "", &found, R_OK);
232       UNGCPRO;
233     }
234     
235   return found;
236 }
237
238 \f
239 /* Initialize an image instance from a bitmap
240
241    DEST_MASK specifies the mask of allowed image types.
242
243    If this fails, signal an error.  INSTANTIATOR is only used
244    in the error message. */
245
246 static void
247 init_image_instance_from_dibitmap (struct Lisp_Image_Instance *ii,
248                                    BITMAPINFO *bmp_info,
249                                    int dest_mask,
250                                    void *bmp_data,
251                                    int bmp_bits,
252                                    Lisp_Object instantiator, 
253                                    int x_hot, int y_hot,
254                                    int create_mask)
255 {
256   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
257   struct device *d = XDEVICE (device);
258   struct frame *f;
259   void* bmp_buf=0;
260   int type;
261   HBITMAP bitmap;
262   HDC hdc;
263
264   if (!DEVICE_MSWINDOWS_P (d))
265     signal_simple_error ("Not an mswindows device", device);
266
267   if (NILP (DEVICE_SELECTED_FRAME (d)))
268     signal_simple_error ("No selected frame on mswindows device", device);
269
270   f = XFRAME (DEVICE_SELECTED_FRAME (d));
271   
272   if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
273     type = IMAGE_COLOR_PIXMAP;
274   else if (dest_mask & IMAGE_POINTER_MASK)
275     type = IMAGE_POINTER;
276   else 
277     incompatible_image_types (instantiator, dest_mask,
278                               IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK);
279   hdc = FRAME_MSWINDOWS_CDC (f);
280
281   bitmap=CreateDIBSection (hdc,  
282                           bmp_info,
283                           DIB_RGB_COLORS,
284                           &bmp_buf, 
285                           0,0);
286
287   if (!bitmap || !bmp_buf)
288     signal_simple_error ("Unable to create bitmap", instantiator);
289
290   /* copy in the actual bitmap */
291   memcpy (bmp_buf, bmp_data, bmp_bits);
292
293   mswindows_initialize_dibitmap_image_instance (ii, type);
294
295   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
296     find_keyword_in_vector (instantiator, Q_file);
297
298   IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = bitmap;
299   IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = NULL;
300   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = bmp_info->bmiHeader.biWidth;
301   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = bmp_info->bmiHeader.biHeight;
302   IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = bmp_info->bmiHeader.biBitCount;
303   XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), x_hot);
304   XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), y_hot);
305
306   if (create_mask)
307     {
308       mswindows_initialize_image_instance_mask (ii, f);
309     }
310   
311   if (type == IMAGE_POINTER)
312     {
313       mswindows_initialize_image_instance_icon(ii, TRUE);
314     }
315 }
316
317 static void
318 mswindows_init_image_instance_from_eimage (struct Lisp_Image_Instance *ii,
319                                            int width, int height,
320                                            unsigned char *eimage, 
321                                            int dest_mask,
322                                            Lisp_Object instantiator,
323                                            Lisp_Object domain)
324 {
325   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
326   BITMAPINFO*           bmp_info;
327   unsigned char*        bmp_data;
328   int                   bmp_bits;
329   COLORREF              bkcolor;
330   
331   if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
332     signal_simple_error ("Not an mswindows device", device);
333
334   /* this is a hack but MaskBlt and TransparentBlt are not supported
335      on most windows variants */
336   bkcolor = COLOR_INSTANCE_MSWINDOWS_COLOR 
337     (XCOLOR_INSTANCE (FACE_BACKGROUND (Vdefault_face, domain)));
338
339   /* build a bitmap from the eimage */
340   if (!(bmp_info=convert_EImage_to_DIBitmap (device, width, height, eimage,
341                                              &bmp_bits, &bmp_data)))
342     {
343       signal_simple_error ("EImage to DIBitmap conversion failed",
344                            instantiator);
345     }
346
347   /* Now create the pixmap and set up the image instance */
348   init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
349                                      bmp_data, bmp_bits, instantiator,
350                                      0, 0, 0);
351
352   xfree (bmp_info);
353   xfree (bmp_data);
354 }
355
356 static void set_mono_pixel ( unsigned char* bits, 
357                              int bpline, int height, 
358                              int x, int y, int white ) 
359
360   int index;
361   unsigned char    bitnum;  
362   /* Find the byte on which this scanline begins */
363   index = (height - y - 1) * bpline; 
364   /* Find the byte containing this pixel */
365   index += (x >> 3); 
366   /* Which bit is it? */
367   bitnum = (unsigned char)( 7 - (x % 8) );  
368   if( white )         /* Turn it on */
369     bits[index] |= (1<<bitnum);
370   else         /* Turn it off */
371     bits[index] &= ~(1<<bitnum); 
372
373
374 static void
375 mswindows_initialize_image_instance_mask (struct Lisp_Image_Instance* image, 
376                                           struct frame* f)
377 {
378   HBITMAP mask;
379   HGDIOBJ old = NULL;
380   HDC hcdc = FRAME_MSWINDOWS_CDC (f);
381   unsigned char* dibits;
382   BITMAPINFO* bmp_info = 
383     xmalloc_and_zero (sizeof(BITMAPINFO) + sizeof(RGBQUAD));
384   int i, j;
385   int height = IMAGE_INSTANCE_PIXMAP_HEIGHT (image);
386   
387   void* and_bits; 
388   int maskbpline = BPLINE (((IMAGE_INSTANCE_PIXMAP_WIDTH (image)+7)/8));
389   int bpline = BPLINE (IMAGE_INSTANCE_PIXMAP_WIDTH (image) * 3); 
390
391   if (!bmp_info)
392     return;
393
394   bmp_info->bmiHeader.biWidth=IMAGE_INSTANCE_PIXMAP_WIDTH (image);
395   bmp_info->bmiHeader.biHeight = height;
396   bmp_info->bmiHeader.biPlanes=1;
397   bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
398   bmp_info->bmiHeader.biBitCount=1; 
399   bmp_info->bmiHeader.biCompression=BI_RGB; 
400   bmp_info->bmiHeader.biClrUsed = 2; 
401   bmp_info->bmiHeader.biClrImportant = 2; 
402   bmp_info->bmiHeader.biSizeImage = height * maskbpline; 
403   bmp_info->bmiColors[0].rgbRed = 0;
404   bmp_info->bmiColors[0].rgbGreen = 0;
405   bmp_info->bmiColors[0].rgbBlue = 0;
406   bmp_info->bmiColors[0].rgbReserved = 0;
407   bmp_info->bmiColors[1].rgbRed = 255;
408   bmp_info->bmiColors[1].rgbGreen = 255;
409   bmp_info->bmiColors[1].rgbBlue = 255;
410   bmp_info->bmiColors[0].rgbReserved = 0;
411     
412   if (!(mask = CreateDIBSection (hcdc,  
413                                  bmp_info,
414                                  DIB_RGB_COLORS,
415                                  &and_bits, 
416                                  0,0)))
417     {
418       xfree (bmp_info);
419       return;
420     }
421
422   old = SelectObject (hcdc, IMAGE_INSTANCE_MSWINDOWS_BITMAP (image));
423   /* build up an in-memory set of bits to mess with */
424   xzero (*bmp_info);
425
426   bmp_info->bmiHeader.biWidth=IMAGE_INSTANCE_PIXMAP_WIDTH (image);
427   bmp_info->bmiHeader.biHeight = -height;
428   bmp_info->bmiHeader.biPlanes=1;
429   bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
430   bmp_info->bmiHeader.biBitCount=24; 
431   bmp_info->bmiHeader.biCompression=BI_RGB; 
432   bmp_info->bmiHeader.biClrUsed = 0; 
433   bmp_info->bmiHeader.biClrImportant = 0; 
434   bmp_info->bmiHeader.biSizeImage = height * bpline;
435
436   dibits = xmalloc_and_zero (bpline * height);
437   if (GetDIBits (hcdc,
438                  IMAGE_INSTANCE_MSWINDOWS_BITMAP (image),
439                  0,
440                  height,
441                  dibits,
442                  bmp_info,
443                  DIB_RGB_COLORS) <= 0)
444     {
445       xfree (bmp_info);
446       return;
447     }
448
449   /* now set the colored bits in the mask and transparent ones to
450      black in the original */
451   for(i=0; i<IMAGE_INSTANCE_PIXMAP_WIDTH (image); i++)     
452     { 
453       for(j=0; j<height; j++)         
454         { 
455           unsigned char* idx = &dibits[j * bpline + i * 3];
456
457           if( RGB (idx[2], idx[1], idx[0]) == transparent_color )
458             { 
459               idx[0] = idx[1] = idx[2] = 0;
460               set_mono_pixel( and_bits, maskbpline, height, i, j, TRUE );
461             }
462           else             
463             { 
464               set_mono_pixel( and_bits, maskbpline, height, i, j, FALSE );
465             }
466         }
467     }
468
469   SetDIBits (hcdc,
470              IMAGE_INSTANCE_MSWINDOWS_BITMAP (image),
471              0,
472              height,
473              dibits,
474              bmp_info,
475              DIB_RGB_COLORS);
476
477   xfree (bmp_info);
478   xfree (dibits);
479   
480   SelectObject(hcdc, old);
481
482   IMAGE_INSTANCE_MSWINDOWS_MASK (image) = mask;
483 }
484
485 void
486 mswindows_initialize_image_instance_icon (struct Lisp_Image_Instance* image,
487                                           int cursor)
488 {
489   ICONINFO x_icon;
490
491   /* we rely on windows to do any resizing necessary */
492   x_icon.fIcon=cursor ? FALSE : TRUE;
493   x_icon.xHotspot=XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (image));
494   x_icon.yHotspot=XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (image));
495   x_icon.hbmMask=IMAGE_INSTANCE_MSWINDOWS_MASK (image);
496   x_icon.hbmColor=IMAGE_INSTANCE_MSWINDOWS_BITMAP (image);
497   
498   IMAGE_INSTANCE_MSWINDOWS_ICON (image)=
499     CreateIconIndirect (&x_icon);
500 }
501
502 HBITMAP
503 mswindows_create_resized_bitmap (struct Lisp_Image_Instance* ii,
504                                  struct frame* f,
505                                  int newx, int newy)
506 {
507   HBITMAP newbmp;
508   HGDIOBJ old1, old2;
509   HDC hcdc = FRAME_MSWINDOWS_CDC (f);
510   HDC hdcDst = CreateCompatibleDC (hcdc);  
511   
512   old1 = SelectObject (hcdc, IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii)); 
513   
514   newbmp = CreateCompatibleBitmap (hcdc, newx, newy);
515
516   old2 = SelectObject (hdcDst, newbmp);
517   
518   if (!StretchBlt (hdcDst, 0, 0, newx, newy,
519                    hcdc, 0, 0, 
520                    IMAGE_INSTANCE_PIXMAP_WIDTH (ii), 
521                    IMAGE_INSTANCE_PIXMAP_HEIGHT (ii), 
522                    SRCCOPY))
523     {
524       DeleteObject (newbmp);
525       DeleteDC (hdcDst);
526       return 0;
527     }
528
529   SelectObject (hdcDst, old2);
530   SelectObject (hcdc, old1);
531   DeleteDC (hdcDst);
532
533   return newbmp;
534 }
535
536 HBITMAP
537 mswindows_create_resized_mask (struct Lisp_Image_Instance* ii,
538                                struct frame* f,
539                                int newx, int newy)
540 {
541   if (IMAGE_INSTANCE_MSWINDOWS_MASK (ii))
542     {
543       HBITMAP newmask;
544       HGDIOBJ old1, old2;
545       HDC hcdc = FRAME_MSWINDOWS_CDC (f);
546       HDC hdcDst = CreateCompatibleDC (hcdc);  
547   
548       old1 = SelectObject (hcdc, IMAGE_INSTANCE_MSWINDOWS_MASK (ii)); 
549       newmask = CreateCompatibleBitmap(hcdc, newx, newy);
550       old2 = SelectObject (hdcDst, newmask);
551
552       if (!StretchBlt(hdcDst, 0, 0, newx, newy,
553                       hcdc, 0, 0, 
554                       IMAGE_INSTANCE_PIXMAP_WIDTH (ii), 
555                       IMAGE_INSTANCE_PIXMAP_HEIGHT (ii), 
556                       SRCCOPY))
557         {
558           DeleteObject (newmask);
559           DeleteDC (hdcDst);
560           return NULL;
561         }
562       
563       SelectObject (hdcDst, old2);
564       SelectObject (hcdc, old1);
565
566       DeleteDC (hdcDst);
567
568       return newmask;
569     }
570
571   return NULL;
572 }
573
574 int
575 mswindows_resize_dibitmap_instance (struct Lisp_Image_Instance* ii,
576                                     struct frame* f,
577                                     int newx, int newy)
578 {
579   HBITMAP newbmp = mswindows_create_resized_bitmap (ii, f, newx, newy);
580   HBITMAP newmask = mswindows_create_resized_mask (ii, f, newx, newy);
581
582   if (!newbmp)
583     return FALSE;
584   
585   if (IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii))
586     DeleteObject (IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii));
587   if (IMAGE_INSTANCE_MSWINDOWS_MASK (ii))
588     DeleteObject (IMAGE_INSTANCE_MSWINDOWS_MASK (ii));
589
590   IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = newbmp;
591   IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = newmask;
592   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = newx;
593   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = newy;
594
595   return TRUE;
596 }
597
598 /**********************************************************************
599  *                               XPM                                  *
600  **********************************************************************/
601
602 #ifdef HAVE_XPM
603
604 struct color_symbol
605 {
606   char*         name;
607   COLORREF      color;
608 };
609
610 static struct color_symbol*
611 extract_xpm_color_names (Lisp_Object device,
612                          Lisp_Object domain,
613                          Lisp_Object color_symbol_alist,
614                          int* nsymbols)
615 {
616   /* This function can GC */
617   Lisp_Object rest;
618   Lisp_Object results = Qnil;
619   int i, j;
620   struct color_symbol *colortbl;
621   struct gcpro gcpro1, gcpro2;
622
623   GCPRO2 (results, device);
624
625   /* We built up results to be (("name" . #<color>) ...) so that if an
626      error happens we don't lose any malloc()ed data, or more importantly,
627      leave any pixels allocated in the server. */
628   i = 0;
629   LIST_LOOP (rest, color_symbol_alist)
630     {
631       Lisp_Object cons = XCAR (rest);
632       Lisp_Object name = XCAR (cons);
633       Lisp_Object value = XCDR (cons);
634       if (NILP (value))
635         continue;
636       if (STRINGP (value))
637         value =
638           Fmake_color_instance
639           (value, device, encode_error_behavior_flag (ERROR_ME_NOT));
640       else
641         {
642           assert (COLOR_SPECIFIERP (value));
643           value = Fspecifier_instance (value, domain, Qnil, Qnil);
644         }
645       if (NILP (value))
646         continue;
647       results = noseeum_cons (noseeum_cons (name, value), results);
648       i++;
649     }
650   UNGCPRO;                      /* no more evaluation */
651
652   *nsymbols=i;
653   if (i == 0) return 0;
654
655   colortbl = xnew_array_and_zero (struct color_symbol, i);
656
657   for (j=0; j<i; j++)
658     {
659       Lisp_Object cons = XCAR (results);
660       colortbl[j].color = 
661         COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (XCDR (cons)));
662
663       colortbl[j].name = (char *) XSTRING_DATA (XCAR (cons));
664       free_cons (XCONS (cons));
665       cons = results;
666       results = XCDR (results);
667       free_cons (XCONS (cons));
668     }
669   return colortbl;
670 }
671
672 static int xpm_to_eimage (Lisp_Object image, CONST Extbyte *buffer,
673                           unsigned char** data,
674                           int* width, int* height,
675                           int* x_hot, int* y_hot,
676                           int* transp,
677                           struct color_symbol* color_symbols,
678                           int nsymbols)
679 {
680   XpmImage xpmimage;
681   XpmInfo xpminfo;
682   int result, i, j, transp_idx, maskbpline;
683   unsigned char* dptr;
684   unsigned int* sptr;
685   COLORREF color; /* the american spelling virus hits again .. */
686   COLORREF* colortbl; 
687
688   xzero (xpmimage);
689   xzero (xpminfo);
690   xpminfo.valuemask=XpmHotspot;
691   *transp=FALSE;
692
693   result = XpmCreateXpmImageFromBuffer ((char*)buffer,
694                                        &xpmimage,
695                                        &xpminfo);
696   switch (result)
697     {
698     case XpmSuccess:
699       break;
700     case XpmFileInvalid:
701       {
702         signal_simple_error ("Invalid XPM data", image);
703       }
704     case XpmNoMemory:
705       {
706         signal_double_file_error ("Parsing pixmap data",
707                                   "out of memory", image);
708       }
709     default:
710       {
711         signal_double_file_error_2 ("Parsing pixmap data",
712                                     "unknown error code",
713                                     make_int (result), image);
714       }
715     }
716   
717   *width = xpmimage.width;
718   *height = xpmimage.height;
719   maskbpline = BPLINE (((~7UL & (unsigned long)(*width + 7)) / 8));
720   
721   *data = xnew_array_and_zero (unsigned char, *width * *height * 3);
722
723   if (!*data)
724     {
725       XpmFreeXpmImage (&xpmimage);
726       XpmFreeXpmInfo (&xpminfo);
727       return 0;
728     }
729
730   /* build a color table to speed things up */
731   colortbl = xnew_array_and_zero (COLORREF, xpmimage.ncolors);
732   if (!colortbl)
733     {
734       xfree (*data);
735       XpmFreeXpmImage (&xpmimage);
736       XpmFreeXpmInfo (&xpminfo);
737       return 0;
738     }
739
740   for (i=0; i<xpmimage.ncolors; i++)
741     {
742       /* goto alert!!!! */
743       /* pick up symbolic colors in preference */
744       if (xpmimage.colorTable[i].symbolic)
745         {
746           if (!strcasecmp (xpmimage.colorTable[i].symbolic,"BgColor")
747               ||
748               !strcasecmp (xpmimage.colorTable[i].symbolic,"None"))
749             {
750               *transp=TRUE;
751               colortbl[i]=transparent_color; 
752               transp_idx=i;
753               goto label_found_color;
754             }
755           else if (color_symbols)
756             {
757               for (j = 0; j<nsymbols; j++)
758                 {
759                   if (!strcmp (xpmimage.colorTable[i].symbolic,
760                                color_symbols[j].name ))
761                     {
762                       colortbl[i]=color_symbols[j].color;
763                       goto label_found_color;
764                     }
765                 }
766             }
767           else if (xpmimage.colorTable[i].c_color == 0)
768             {
769               goto label_no_color;
770             }
771         }
772       /* pick up transparencies */
773       if (!strcasecmp (xpmimage.colorTable[i].c_color,"None"))
774         {
775           *transp=TRUE;
776           colortbl[i]=transparent_color; 
777           transp_idx=i;
778           goto label_found_color;
779         }
780       /* finally pick up a normal color spec */
781       if (xpmimage.colorTable[i].c_color)
782         {
783           colortbl[i]=
784             mswindows_string_to_color (xpmimage.colorTable[i].c_color);
785           goto label_found_color;
786         }
787       
788     label_no_color:
789       xfree (*data);
790       xfree (colortbl);
791       XpmFreeXpmImage (&xpmimage);
792       XpmFreeXpmInfo (&xpminfo);
793       return 0;
794       
795     label_found_color:;
796     }
797
798   /* convert the image */
799   sptr=xpmimage.data;
800   dptr=*data;
801   for (i = 0; i< *width * *height; i++)
802     {
803       color = colortbl[*sptr++];
804
805       /* split out the 0x02bbggrr colorref into an rgb triple */
806       *dptr++=GetRValue (color); /* red */
807       *dptr++=GetGValue (color); /* green */
808       *dptr++=GetBValue (color); /* blue */
809     }
810
811   *x_hot=xpminfo.x_hotspot;
812   *y_hot=xpminfo.y_hotspot;
813
814   XpmFreeXpmImage (&xpmimage);
815   XpmFreeXpmInfo (&xpminfo);
816   xfree (colortbl);
817   return TRUE;
818 }
819
820 static void
821 mswindows_xpm_instantiate (Lisp_Object image_instance,
822                            Lisp_Object instantiator,
823                            Lisp_Object pointer_fg, Lisp_Object pointer_bg,
824                            int dest_mask, Lisp_Object domain)
825 {
826   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
827   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
828   CONST Extbyte         *bytes;
829   Extcount              len;
830   unsigned char         *eimage;
831   int                   width, height, x_hot, y_hot;
832   BITMAPINFO*           bmp_info;
833   unsigned char*        bmp_data;
834   int                   bmp_bits;
835   int                   nsymbols=0, transp;
836   struct color_symbol*  color_symbols=NULL;
837   
838   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
839   Lisp_Object color_symbol_alist = find_keyword_in_vector (instantiator,
840                                                            Q_color_symbols);
841
842   if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
843     signal_simple_error ("Not an mswindows device", device);
844
845   assert (!NILP (data));
846
847   GET_STRING_BINARY_DATA_ALLOCA (data, bytes, len);
848
849   /* in case we have color symbols */
850   color_symbols = extract_xpm_color_names (device, domain,
851                                            color_symbol_alist, &nsymbols);
852
853   /* convert to an eimage to make processing easier */
854   if (!xpm_to_eimage (image_instance, bytes, &eimage, &width, &height,
855                       &x_hot, &y_hot, &transp, color_symbols, nsymbols))
856     {
857       signal_simple_error ("XPM to EImage conversion failed", 
858                            image_instance);
859     }
860   
861   if (color_symbols)
862     xfree(color_symbols);
863   
864   /* build a bitmap from the eimage */
865   if (!(bmp_info=convert_EImage_to_DIBitmap (device, width, height, eimage,
866                                              &bmp_bits, &bmp_data)))
867     {
868       signal_simple_error ("XPM to EImage conversion failed",
869                            image_instance);
870     }
871   xfree (eimage);
872
873   /* Now create the pixmap and set up the image instance */
874   init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
875                                      bmp_data, bmp_bits, instantiator,
876                                      x_hot, y_hot, transp);
877
878   xfree (bmp_info);
879   xfree (bmp_data);
880 }
881 #endif /* HAVE_XPM */
882
883 /**********************************************************************
884  *                               BMP                                  *
885  **********************************************************************/
886
887 static void
888 bmp_validate (Lisp_Object instantiator)
889 {
890   file_or_data_must_be_present (instantiator);
891 }
892
893 static Lisp_Object
894 bmp_normalize (Lisp_Object inst, Lisp_Object console_type)
895 {
896   return simple_image_type_normalize (inst, console_type, Qbmp);
897 }
898
899 static int
900 bmp_possible_dest_types (void)
901 {
902   return IMAGE_COLOR_PIXMAP_MASK;
903 }
904
905 static void
906 bmp_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
907                  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
908                  int dest_mask, Lisp_Object domain)
909 {
910   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
911   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
912   CONST Extbyte         *bytes;
913   Extcount              len;
914   BITMAPFILEHEADER*     bmp_file_header;
915   BITMAPINFO*           bmp_info;
916   void*                 bmp_data;
917   int                   bmp_bits;
918   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
919
920   if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
921     signal_simple_error ("Not an mswindows device", device);
922
923   assert (!NILP (data));
924
925   GET_STRING_BINARY_DATA_ALLOCA (data, bytes, len);
926   
927   /* Then slurp the image into memory, decoding along the way.
928      The result is the image in a simple one-byte-per-pixel
929      format. */
930   
931   bmp_file_header=(BITMAPFILEHEADER*)bytes;
932   bmp_info = (BITMAPINFO*)(bytes + sizeof(BITMAPFILEHEADER));
933   bmp_data = (Extbyte*)bytes + bmp_file_header->bfOffBits;
934   bmp_bits = bmp_file_header->bfSize - bmp_file_header->bfOffBits;
935
936   /* Now create the pixmap and set up the image instance */
937   init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
938                                      bmp_data, bmp_bits, instantiator,
939                                      0, 0, 0);
940 }
941
942 \f
943 /**********************************************************************
944  *                             RESOURCES                              *
945  **********************************************************************/
946
947 static void
948 mswindows_resource_validate (Lisp_Object instantiator)
949 {
950   if ((NILP (find_keyword_in_vector (instantiator, Q_file)) 
951        &&
952        NILP (find_keyword_in_vector (instantiator, Q_resource_id))) 
953       ||
954       NILP (find_keyword_in_vector (instantiator, Q_resource_type)))
955     signal_simple_error ("Must supply :file, :resource-id and :resource-type",
956                          instantiator);
957 }
958
959 static Lisp_Object
960 mswindows_resource_normalize (Lisp_Object inst, Lisp_Object console_type)
961 {
962   /* This function can call lisp */
963   Lisp_Object file = Qnil;
964   struct gcpro gcpro1, gcpro2;
965   Lisp_Object alist = Qnil;
966
967   GCPRO2 (file, alist);
968
969   file = potential_pixmap_file_instantiator (inst, Q_file, Q_data, 
970                                              console_type);
971
972   if (CONSP (file)) /* failure locating filename */
973     signal_double_file_error ("Opening pixmap file",
974                               "no such file or directory",
975                               Fcar (file));
976
977   if (NILP (file)) /* no conversion necessary */
978     RETURN_UNGCPRO (inst);
979
980   alist = tagged_vector_to_alist (inst);
981
982   {
983     alist = remassq_no_quit (Q_file, alist);
984     alist = Fcons (Fcons (Q_file, file), alist);
985   }
986
987   {
988     Lisp_Object result = alist_to_tagged_vector (Qmswindows_resource, alist);
989     free_alist (alist);
990     RETURN_UNGCPRO (result);
991   }
992 }
993
994 static int
995 mswindows_resource_possible_dest_types (void)
996 {
997   return IMAGE_POINTER_MASK | IMAGE_COLOR_PIXMAP_MASK;
998 }
999
1000 typedef struct 
1001 {
1002   char *name;
1003   int   resource_id;
1004 } resource_t;
1005
1006 #ifndef OCR_ICOCUR
1007 #define OCR_ICOCUR          32647
1008 #define OIC_SAMPLE          32512
1009 #define OIC_HAND            32513
1010 #define OIC_QUES            32514
1011 #define OIC_BANG            32515
1012 #define OIC_NOTE            32516
1013 #define OIC_WINLOGO         32517
1014 #define LR_SHARED           0x8000
1015 #endif
1016
1017 static CONST resource_t bitmap_table[] = 
1018 {
1019   /* bitmaps */
1020   { "close", OBM_CLOSE },
1021   { "uparrow", OBM_UPARROW },
1022   { "dnarrow", OBM_DNARROW },
1023   { "rgarrow", OBM_RGARROW },
1024   { "lfarrow", OBM_LFARROW },
1025   { "reduce", OBM_REDUCE },
1026   { "zoom", OBM_ZOOM },
1027   { "restore", OBM_RESTORE },
1028   { "reduced", OBM_REDUCED },
1029   { "zoomd", OBM_ZOOMD },
1030   { "restored", OBM_RESTORED },
1031   { "uparrowd", OBM_UPARROWD },
1032   { "dnarrowd", OBM_DNARROWD },
1033   { "rgarrowd", OBM_RGARROWD },
1034   { "lfarrowd", OBM_LFARROWD },
1035   { "mnarrow", OBM_MNARROW },
1036   { "combo", OBM_COMBO },
1037   { "uparrowi", OBM_UPARROWI },
1038   { "dnarrowi", OBM_DNARROWI },
1039   { "rgarrowi", OBM_RGARROWI },
1040   { "lfarrowi", OBM_LFARROWI },
1041   { "size", OBM_SIZE },
1042   { "btsize", OBM_BTSIZE },
1043   { "check", OBM_CHECK },
1044   { "checkboxes", OBM_CHECKBOXES },
1045   { "btncorners" , OBM_BTNCORNERS },
1046   {0}
1047 };
1048
1049 static CONST resource_t cursor_table[] = 
1050 {
1051   /* cursors */
1052   { "normal", OCR_NORMAL },
1053   { "ibeam", OCR_IBEAM },
1054   { "wait", OCR_WAIT },
1055   { "cross", OCR_CROSS },
1056   { "up", OCR_UP },
1057   /* { "icon", OCR_ICON }, */
1058   { "sizenwse", OCR_SIZENWSE },
1059   { "sizenesw", OCR_SIZENESW },
1060   { "sizewe", OCR_SIZEWE },
1061   { "sizens", OCR_SIZENS },
1062   { "sizeall", OCR_SIZEALL },
1063   /* { "icour", OCR_ICOCUR }, */
1064   { "no", OCR_NO },
1065   { 0 }
1066 };
1067
1068 static CONST resource_t icon_table[] = 
1069 {
1070   /* icons */
1071   { "sample", OIC_SAMPLE },
1072   { "hand", OIC_HAND },
1073   { "ques", OIC_QUES },
1074   { "bang", OIC_BANG },
1075   { "note", OIC_NOTE },
1076   { "winlogo", OIC_WINLOGO },
1077   {0}
1078 };
1079
1080 static int resource_name_to_resource (Lisp_Object name, int type)
1081 {
1082   CONST resource_t* res = (type == IMAGE_CURSOR ? cursor_table 
1083                            : type == IMAGE_ICON ? icon_table 
1084                            : bitmap_table);
1085
1086   if (INTP (name))
1087     {
1088       return XINT (name);
1089     }
1090   else if (!STRINGP (name))
1091     {
1092       signal_simple_error ("invalid resource identifier", name);
1093     }
1094   
1095   do {
1096     if (!strcasecmp ((char*)res->name, XSTRING_DATA (name)))
1097       return res->resource_id;
1098   } while ((++res)->name);
1099   return 0;
1100 }
1101
1102 static int
1103 resource_symbol_to_type (Lisp_Object data)
1104 {
1105   if (EQ (data, Qcursor))
1106     return IMAGE_CURSOR;
1107   else if (EQ (data, Qicon))
1108     return IMAGE_ICON;
1109   else if (EQ (data, Qbitmap))
1110     return IMAGE_BITMAP;
1111   else
1112     return 0;
1113 }
1114
1115 static void
1116 mswindows_resource_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
1117                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1118                     int dest_mask, Lisp_Object domain)
1119 {
1120   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1121   unsigned int type = 0;
1122   HANDLE himage = NULL;
1123   LPCTSTR resid=0;
1124   HINSTANCE hinst = NULL;
1125   ICONINFO iconinfo;
1126   int iitype=0;
1127   char* fname=0;
1128   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1129
1130   Lisp_Object file = find_keyword_in_vector (instantiator, Q_file);
1131   Lisp_Object resource_type = find_keyword_in_vector (instantiator, 
1132                                                       Q_resource_type);
1133   Lisp_Object resource_id = find_keyword_in_vector (instantiator, 
1134                                                     Q_resource_id);
1135
1136   xzero (iconinfo);
1137
1138   if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
1139     signal_simple_error ("Not an mswindows device", device);
1140
1141   type = resource_symbol_to_type (resource_type);
1142
1143   if (dest_mask & IMAGE_POINTER_MASK && type == IMAGE_CURSOR)
1144     iitype = IMAGE_POINTER;
1145   else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1146     iitype = IMAGE_COLOR_PIXMAP;
1147   else 
1148     incompatible_image_types (instantiator, dest_mask,
1149                               IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK);
1150
1151   /* mess with the keyword info we were provided with */
1152   if (!NILP (file))
1153     {
1154 #ifdef __CYGWIN32__
1155       CYGWIN_WIN32_PATH (XSTRING_DATA (file), fname);
1156 #else
1157       /* #### FIXME someone who knows ... */
1158       fname = XSTRING_DATA (file);
1159 #endif
1160       
1161       if (NILP (resource_id))
1162         resid = (LPCTSTR)fname;
1163       else
1164         {
1165           hinst = LoadLibraryEx (fname, NULL,
1166                                  LOAD_LIBRARY_AS_DATAFILE);
1167           resid = MAKEINTRESOURCE (resource_name_to_resource (resource_id,
1168                                                            type));
1169           
1170           if (!resid)
1171             resid = XSTRING_DATA (resource_id);
1172         }
1173     }
1174   else if (!(resid = MAKEINTRESOURCE (resource_name_to_resource (resource_id,
1175                                                                type))))
1176     signal_simple_error ("Invalid resource identifier", resource_id);
1177   
1178   /* load the image */
1179   if (!(himage = LoadImage (hinst, resid, type, 0, 0,
1180                             LR_CREATEDIBSECTION | LR_DEFAULTSIZE | 
1181                             LR_SHARED |      
1182                             (!NILP (file) ? LR_LOADFROMFILE : 0))))
1183     {
1184       signal_simple_error ("Cannot load image", instantiator);
1185     }
1186
1187   if (hinst)
1188     FreeLibrary (hinst);
1189
1190   mswindows_initialize_dibitmap_image_instance (ii, iitype);
1191
1192   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = file;
1193   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = 
1194     GetSystemMetrics (type == IMAGE_CURSOR ? SM_CXCURSOR : SM_CXICON);
1195   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = 
1196     GetSystemMetrics (type == IMAGE_CURSOR ? SM_CYCURSOR : SM_CYICON);
1197   IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = 1;
1198
1199   /* hey, we've got an icon type thing so we can reverse engineer the
1200      bitmap and mask */
1201   if (type != IMAGE_BITMAP)
1202     {
1203       GetIconInfo (himage, &iconinfo);
1204       IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = iconinfo.hbmColor;
1205       IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = iconinfo.hbmMask;
1206       XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), iconinfo.xHotspot);
1207       XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), iconinfo.yHotspot);
1208       IMAGE_INSTANCE_MSWINDOWS_ICON (ii) = himage;
1209     }
1210   else
1211     {
1212       IMAGE_INSTANCE_MSWINDOWS_ICON (ii) = NULL;
1213       IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = himage;
1214       IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = NULL;
1215       XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), 0);
1216       XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), 0);
1217     }
1218 }
1219
1220 static void
1221 check_valid_resource_symbol (Lisp_Object data)
1222 {
1223   CHECK_SYMBOL (data);
1224   if (!resource_symbol_to_type (data))
1225     signal_simple_error ("invalid resource type", data);
1226 }
1227
1228 static void
1229 check_valid_resource_id (Lisp_Object data)
1230 {
1231   if (!resource_name_to_resource (data, IMAGE_CURSOR)
1232       &&
1233       !resource_name_to_resource (data, IMAGE_ICON)
1234       &&
1235       !resource_name_to_resource (data, IMAGE_BITMAP))
1236     signal_simple_error ("invalid resource identifier", data);
1237 }
1238
1239 void
1240 check_valid_string_or_int (Lisp_Object data)
1241 {
1242   if (!INTP (data))
1243     CHECK_STRING (data);
1244   else
1245     CHECK_INT (data);
1246 }
1247
1248 /**********************************************************************
1249  *                             XBM                                    *
1250  **********************************************************************/
1251 #ifndef HAVE_X_WINDOWS
1252 /* $XConsortium: RdBitF.c,v 1.10 94/04/17 20:16:13 kaleb Exp $ */
1253
1254 /*
1255
1256 Copyright (c) 1988  X Consortium
1257
1258 Permission is hereby granted, free of charge, to any person obtaining a copy
1259 of this software and associated documentation files (the "Software"), to deal
1260 in the Software without restriction, including without limitation the rights
1261 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1262 copies of the Software, and to permit persons to whom the Software is
1263 furnished to do so, subject to the following conditions:
1264
1265 The above copyright notice and this permission notice shall be included in
1266 all copies or substantial portions of the Software.
1267
1268 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1269 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1270 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1271 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1272 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1273 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1274
1275 Except as contained in this notice, the name of the X Consortium shall not be
1276 used in advertising or otherwise to promote the sale, use or other dealings
1277 in this Software without prior written authorization from the X Consortium.
1278
1279 */
1280
1281 /*
1282  * This file contains miscellaneous utility routines and is not part of the
1283  * Xlib standard.
1284  *
1285  * Public entry points:
1286  *
1287  *     XmuReadBitmapData                read data from FILE descriptor
1288  *     XmuReadBitmapDataFromFile        read X10 or X11 format bitmap files
1289  *                                      and return data
1290  *
1291  * Note that this file and ../X/XRdBitF.c look very similar....  Keep them
1292  * that way (but don't use common source code so that people can have one 
1293  * without the other).
1294  */
1295
1296
1297 /*
1298  * Based on an optimized version provided by Jim Becker, August 5, 1988.
1299  */
1300 #ifndef BitmapSuccess
1301 #define BitmapSuccess           0
1302 #define BitmapOpenFailed        1
1303 #define BitmapFileInvalid       2
1304 #define BitmapNoMemory          3
1305 #endif
1306 #define MAX_SIZE 255
1307
1308 /* shared data for the image read/parse logic */
1309 static short hexTable[256];             /* conversion value */
1310 static int initialized = FALSE; /* easier to fill in at run time */
1311
1312 /*
1313  *      Table index for the hex values. Initialized once, first time.
1314  *      Used for translation value or delimiter significance lookup.
1315  */
1316 static void initHexTable()
1317 {
1318     /*
1319      * We build the table at run time for several reasons:
1320      *
1321      *     1.  portable to non-ASCII machines.
1322      *     2.  still reentrant since we set the init flag after setting table.
1323      *     3.  easier to extend.
1324      *     4.  less prone to bugs.
1325      */
1326     hexTable['0'] = 0;  hexTable['1'] = 1;
1327     hexTable['2'] = 2;  hexTable['3'] = 3;
1328     hexTable['4'] = 4;  hexTable['5'] = 5;
1329     hexTable['6'] = 6;  hexTable['7'] = 7;
1330     hexTable['8'] = 8;  hexTable['9'] = 9;
1331     hexTable['A'] = 10; hexTable['B'] = 11;
1332     hexTable['C'] = 12; hexTable['D'] = 13;
1333     hexTable['E'] = 14; hexTable['F'] = 15;
1334     hexTable['a'] = 10; hexTable['b'] = 11;
1335     hexTable['c'] = 12; hexTable['d'] = 13;
1336     hexTable['e'] = 14; hexTable['f'] = 15;
1337
1338     /* delimiters of significance are flagged w/ negative value */
1339     hexTable[' '] = -1; hexTable[','] = -1;
1340     hexTable['}'] = -1; hexTable['\n'] = -1;
1341     hexTable['\t'] = -1;
1342         
1343     initialized = TRUE;
1344 }
1345
1346 /*
1347  *      read next hex value in the input stream, return -1 if EOF
1348  */
1349 static int NextInt ( FILE *fstream )
1350 {
1351     int ch;
1352     int value = 0;
1353     int gotone = 0;
1354     int done = 0;
1355     
1356     /* loop, accumulate hex value until find delimiter  */
1357     /* skip any initial delimiters found in read stream */
1358
1359     while (!done) {
1360         ch = getc(fstream);
1361         if (ch == EOF) {
1362             value       = -1;
1363             done++;
1364         } else {
1365             /* trim high bits, check type and accumulate */
1366             ch &= 0xff;
1367             if (isascii(ch) && isxdigit(ch)) {
1368                 value = (value << 4) + hexTable[ch];
1369                 gotone++;
1370             } else if ((hexTable[ch]) < 0 && gotone)
1371               done++;
1372         }
1373     }
1374     return value;
1375 }
1376
1377
1378 /*
1379  * The data returned by the following routine is always in left-most byte
1380  * first and left-most bit first.  If it doesn't return BitmapSuccess then
1381  * its arguments won't have been touched.  This routine should look as much
1382  * like the Xlib routine XReadBitmapfile as possible.
1383  */
1384 int read_bitmap_data (fstream, width, height, datap, x_hot, y_hot)
1385     FILE *fstream;                      /* handle on file  */
1386     unsigned int *width, *height;       /* RETURNED */
1387     unsigned char **datap;              /* RETURNED */
1388     int *x_hot, *y_hot;                 /* RETURNED */
1389 {
1390     unsigned char *data = NULL;         /* working variable */
1391     char line[MAX_SIZE];                /* input line from file */
1392     int size;                           /* number of bytes of data */
1393     char name_and_type[MAX_SIZE];       /* an input line */
1394     char *type;                         /* for parsing */
1395     int value;                          /* from an input line */
1396     int version10p;                     /* boolean, old format */
1397     int padding;                        /* to handle alignment */
1398     int bytes_per_line;                 /* per scanline of data */
1399     unsigned int ww = 0;                /* width */
1400     unsigned int hh = 0;                /* height */
1401     int hx = -1;                        /* x hotspot */
1402     int hy = -1;                        /* y hotspot */
1403
1404 #define Xmalloc(size) malloc(size)
1405
1406     /* first time initialization */
1407     if (initialized == FALSE) initHexTable();
1408
1409     /* error cleanup and return macro   */
1410 #define RETURN(code) { if (data) free (data); return code; }
1411
1412     while (fgets(line, MAX_SIZE, fstream)) {
1413         if (strlen(line) == MAX_SIZE-1) {
1414             RETURN (BitmapFileInvalid);
1415         }
1416         if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
1417             if (!(type = strrchr(name_and_type, '_')))
1418               type = name_and_type;
1419             else
1420               type++;
1421
1422             if (!strcmp("width", type))
1423               ww = (unsigned int) value;
1424             if (!strcmp("height", type))
1425               hh = (unsigned int) value;
1426             if (!strcmp("hot", type)) {
1427                 if (type-- == name_and_type || type-- == name_and_type)
1428                   continue;
1429                 if (!strcmp("x_hot", type))
1430                   hx = value;
1431                 if (!strcmp("y_hot", type))
1432                   hy = value;
1433             }
1434             continue;
1435         }
1436     
1437         if (sscanf(line, "static short %s = {", name_and_type) == 1)
1438           version10p = 1;
1439         else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
1440           version10p = 0;
1441         else if (sscanf(line, "static char %s = {", name_and_type) == 1)
1442           version10p = 0;
1443         else
1444           continue;
1445
1446         if (!(type = strrchr(name_and_type, '_')))
1447           type = name_and_type;
1448         else
1449           type++;
1450
1451         if (strcmp("bits[]", type))
1452           continue;
1453     
1454         if (!ww || !hh)
1455           RETURN (BitmapFileInvalid);
1456
1457         if ((ww % 16) && ((ww % 16) < 9) && version10p)
1458           padding = 1;
1459         else
1460           padding = 0;
1461
1462         bytes_per_line = (ww+7)/8 + padding;
1463
1464         size = bytes_per_line * hh;
1465         data = (unsigned char *) Xmalloc ((unsigned int) size);
1466         if (!data) 
1467           RETURN (BitmapNoMemory);
1468
1469         if (version10p) {
1470             unsigned char *ptr;
1471             int bytes;
1472
1473             for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
1474                 if ((value = NextInt(fstream)) < 0)
1475                   RETURN (BitmapFileInvalid);
1476                 *(ptr++) = value;
1477                 if (!padding || ((bytes+2) % bytes_per_line))
1478                   *(ptr++) = value >> 8;
1479             }
1480         } else {
1481             unsigned char *ptr;
1482             int bytes;
1483
1484             for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
1485                 if ((value = NextInt(fstream)) < 0) 
1486                   RETURN (BitmapFileInvalid);
1487                 *ptr=value;
1488             }
1489         }
1490         break;
1491     }                                   /* end while */
1492
1493     if (data == NULL) {
1494         RETURN (BitmapFileInvalid);
1495     }
1496
1497     *datap = data;
1498     data = NULL;
1499     *width = ww;
1500     *height = hh;
1501     if (x_hot) *x_hot = hx;
1502     if (y_hot) *y_hot = hy;
1503
1504     RETURN (BitmapSuccess);
1505 }
1506
1507
1508 int read_bitmap_data_from_file (CONST char *filename, unsigned int *width, 
1509                                 unsigned int *height, unsigned char **datap,
1510                                 int *x_hot, int *y_hot)
1511 {
1512     FILE *fstream;
1513     int status;
1514
1515     if ((fstream = fopen (filename, "r")) == NULL) {
1516         return BitmapOpenFailed;
1517     }
1518     status = read_bitmap_data (fstream, width, height, datap, x_hot, y_hot);
1519     fclose (fstream);
1520     return status;
1521 }
1522 #endif /* HAVE_X_WINDOWS */
1523
1524 /* this table flips four bits around. */
1525 static int flip_table[] =
1526 {
1527   0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
1528 };
1529
1530 /* the bitmap data comes in the following format: Widths are padded to
1531    a multiple of 8.  Scan lines are stored in increasing byte order
1532    from left to right, little-endian within a byte.  0 = white, 1 =
1533    black.  It must be converted to the following format: Widths are
1534    padded to a multiple of 16.  Scan lines are stored in increasing
1535    byte order from left to right, big-endian within a byte.  0 =
1536    black, 1 = white.  */
1537 HBITMAP
1538 xbm_create_bitmap_from_data (HDC hdc, char *data,
1539                              unsigned int width, unsigned int height,
1540                              int mask, COLORREF fg, COLORREF bg)
1541 {
1542   int old_width = (width + 7)/8;
1543   int new_width = 2*((width + 15)/16);
1544   unsigned char *offset;
1545   void *bmp_buf = 0;
1546   unsigned char *new_data, *new_offset;
1547   int i, j;
1548   BITMAPINFO* bmp_info = 
1549     xmalloc_and_zero (sizeof(BITMAPINFO) + sizeof(RGBQUAD));
1550   HBITMAP bitmap;
1551
1552   if (!bmp_info)
1553     return NULL;
1554   
1555   new_data = (unsigned char *) xmalloc (height * new_width);
1556       
1557   if (!new_data)
1558     {
1559       xfree (bmp_info);
1560       return NULL;
1561     }
1562   
1563   for (i=0; i<height; i++)
1564     {
1565       offset = data + i*old_width;
1566       new_offset = new_data + i*new_width;
1567
1568       new_offset[new_width - 1] = 0; /* there may be an extra byte
1569                                         that needs to be padded */
1570       for (j=0; j<old_width; j++)
1571         {
1572           int byte = offset[j];
1573           new_offset[j] = ~ (unsigned char)
1574             ((flip_table[byte & 0xf] << 4) + flip_table[byte >> 4]);
1575         }
1576     }
1577
1578   /* if we want a mask invert the bits */
1579   if (!mask)
1580     {
1581       new_offset = &new_data[height * new_width];
1582       while (new_offset-- != new_data)
1583         {
1584           *new_offset ^= 0xff;
1585         }
1586     }
1587
1588   bmp_info->bmiHeader.biWidth=width;
1589   bmp_info->bmiHeader.biHeight=-height;
1590   bmp_info->bmiHeader.biPlanes=1;
1591   bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
1592   bmp_info->bmiHeader.biBitCount=1; 
1593   bmp_info->bmiHeader.biCompression=BI_RGB;
1594   bmp_info->bmiHeader.biClrUsed = 2; 
1595   bmp_info->bmiHeader.biClrImportant = 2; 
1596   bmp_info->bmiHeader.biSizeImage = height * new_width; 
1597   bmp_info->bmiColors[0].rgbRed = GetRValue (fg);
1598   bmp_info->bmiColors[0].rgbGreen = GetGValue (fg);
1599   bmp_info->bmiColors[0].rgbBlue = GetBValue (fg);
1600   bmp_info->bmiColors[0].rgbReserved = 0;
1601   bmp_info->bmiColors[1].rgbRed = GetRValue (bg);
1602   bmp_info->bmiColors[1].rgbGreen = GetGValue (bg);
1603   bmp_info->bmiColors[1].rgbBlue = GetBValue (bg);
1604   bmp_info->bmiColors[1].rgbReserved = 0;
1605   
1606   bitmap = CreateDIBSection (hdc,  
1607                              bmp_info,
1608                              DIB_RGB_COLORS,
1609                              &bmp_buf, 
1610                              0,0);
1611
1612   xfree (bmp_info);
1613   
1614   if (!bitmap || !bmp_buf)
1615     {
1616       xfree (new_data);
1617       return NULL;
1618     }
1619   
1620   /* copy in the actual bitmap */
1621   memcpy (bmp_buf, new_data, height * new_width);
1622   xfree (new_data);
1623
1624   return bitmap;
1625 }
1626
1627 /* Given inline data for a mono pixmap, initialize the given
1628    image instance accordingly. */
1629
1630 static void
1631 init_image_instance_from_xbm_inline (struct Lisp_Image_Instance *ii,
1632                                      int width, int height,
1633                                      /* Note that data is in ext-format! */
1634                                      CONST char *bits,
1635                                      Lisp_Object instantiator,
1636                                      Lisp_Object pointer_fg,
1637                                      Lisp_Object pointer_bg,
1638                                      int dest_mask,
1639                                      HBITMAP mask,
1640                                      Lisp_Object mask_filename)
1641 {
1642   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
1643   struct frame* f = XFRAME (DEVICE_SELECTED_FRAME (XDEVICE (device)));
1644   Lisp_Object foreground = find_keyword_in_vector (instantiator, Q_foreground);
1645   Lisp_Object background = find_keyword_in_vector (instantiator, Q_background);
1646   enum image_instance_type type;
1647   COLORREF black = PALETTERGB (0,0,0);
1648   COLORREF white = PALETTERGB (255,255,255);
1649
1650   HDC hdc = FRAME_MSWINDOWS_CDC (f);
1651
1652   if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
1653     signal_simple_error ("Not an MS-Windows device", device);
1654
1655   if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) &&
1656       (dest_mask & IMAGE_COLOR_PIXMAP_MASK))
1657     {
1658       if (!NILP (foreground) || !NILP (background))
1659         type = IMAGE_COLOR_PIXMAP;
1660       else
1661         type = IMAGE_MONO_PIXMAP;
1662     }
1663   else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
1664     type = IMAGE_MONO_PIXMAP;
1665   else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
1666     type = IMAGE_COLOR_PIXMAP;
1667   else if (dest_mask & IMAGE_POINTER_MASK)
1668     type = IMAGE_POINTER;
1669   else
1670     incompatible_image_types (instantiator, dest_mask,
1671                               IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
1672                               | IMAGE_POINTER_MASK);
1673
1674   mswindows_initialize_dibitmap_image_instance (ii, type);
1675   
1676   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
1677     find_keyword_in_vector (instantiator, Q_file);
1678   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = width;
1679   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = height;
1680   IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = 1;
1681   XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), 0);
1682   XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), 0);
1683   IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = mask ? mask :
1684     xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
1685                                  TRUE, black, white);
1686
1687   switch (type)
1688     {
1689     case IMAGE_MONO_PIXMAP:
1690       IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = 
1691         xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
1692                                      FALSE, black, black);
1693       break;
1694
1695     case IMAGE_COLOR_PIXMAP:
1696       {
1697         COLORREF fg = black;
1698         COLORREF bg = white;
1699
1700         if (!NILP (foreground) && !COLOR_INSTANCEP (foreground))
1701           foreground =
1702             Fmake_color_instance (foreground, device,
1703                                   encode_error_behavior_flag (ERROR_ME));
1704
1705         if (COLOR_INSTANCEP (foreground))
1706           fg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (foreground));
1707
1708         if (!NILP (background) && !COLOR_INSTANCEP (background))
1709           background =
1710             Fmake_color_instance (background, device,
1711                                   encode_error_behavior_flag (ERROR_ME));
1712
1713         if (COLOR_INSTANCEP (background))
1714           bg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (background));
1715
1716         IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
1717         IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
1718
1719         IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = 
1720           xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
1721                                        FALSE, fg, black);
1722       }
1723       break;
1724
1725     case IMAGE_POINTER:
1726       {
1727         COLORREF fg = black;
1728         COLORREF bg = white;
1729
1730         if (NILP (foreground))
1731           foreground = pointer_fg;
1732         if (NILP (background))
1733           background = pointer_bg;
1734
1735         XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), 
1736                  find_keyword_in_vector (instantiator, Q_hotspot_x));
1737         XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), 
1738                  find_keyword_in_vector (instantiator, Q_hotspot_y));
1739         IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
1740         IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
1741         if (COLOR_INSTANCEP (foreground))
1742           fg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (foreground));
1743         if (COLOR_INSTANCEP (background))
1744           bg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (background));
1745
1746         IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = 
1747           xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
1748                                        TRUE, fg, black);
1749         mswindows_initialize_image_instance_icon (ii, TRUE);
1750       }
1751       break;
1752
1753     default:
1754       abort ();
1755     }
1756 }
1757
1758 static void
1759 xbm_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator,
1760                    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1761                    int dest_mask, int width, int height,
1762                    /* Note that data is in ext-format! */
1763                    CONST char *bits)
1764 {
1765   Lisp_Object mask_data = find_keyword_in_vector (instantiator, Q_mask_data);
1766   Lisp_Object mask_file = find_keyword_in_vector (instantiator, Q_mask_file);
1767   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
1768   struct frame* f = XFRAME (DEVICE_SELECTED_FRAME 
1769                             (XDEVICE (IMAGE_INSTANCE_DEVICE (ii))));
1770   HDC hdc = FRAME_MSWINDOWS_CDC (f);
1771   HBITMAP mask = 0;
1772   CONST char *gcc_may_you_rot_in_hell;
1773
1774   if (!NILP (mask_data))
1775     {
1776       GET_C_STRING_BINARY_DATA_ALLOCA (XCAR (XCDR (XCDR (mask_data))),
1777                                        gcc_may_you_rot_in_hell);
1778       mask =
1779         xbm_create_bitmap_from_data ( hdc,
1780                                       (unsigned char *)
1781                                       gcc_may_you_rot_in_hell,
1782                                       XINT (XCAR (mask_data)),
1783                                       XINT (XCAR (XCDR (mask_data))), FALSE,
1784                                       PALETTERGB (0,0,0),
1785                                       PALETTERGB (255,255,255));
1786     }
1787
1788   init_image_instance_from_xbm_inline (ii, width, height, bits,
1789                                        instantiator, pointer_fg, pointer_bg,
1790                                        dest_mask, mask, mask_file);
1791 }
1792
1793 /* Instantiate method for XBM's. */
1794
1795 static void
1796 mswindows_xbm_instantiate (Lisp_Object image_instance, 
1797                            Lisp_Object instantiator,
1798                            Lisp_Object pointer_fg, Lisp_Object pointer_bg,
1799                            int dest_mask, Lisp_Object domain)
1800 {
1801   Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
1802   CONST char *gcc_go_home;
1803
1804   assert (!NILP (data));
1805
1806   GET_C_STRING_BINARY_DATA_ALLOCA (XCAR (XCDR (XCDR (data))),
1807                                    gcc_go_home);
1808
1809   xbm_instantiate_1 (image_instance, instantiator, pointer_fg,
1810                      pointer_bg, dest_mask, XINT (XCAR (data)),
1811                      XINT (XCAR (XCDR (data))), gcc_go_home);
1812 }
1813
1814 \f
1815 /************************************************************************/
1816 /*                      image instance methods                          */
1817 /************************************************************************/
1818
1819 static void
1820 mswindows_print_image_instance (struct Lisp_Image_Instance *p,
1821                                 Lisp_Object printcharfun,
1822                                 int escapeflag)
1823 {
1824   char buf[100];
1825
1826   switch (IMAGE_INSTANCE_TYPE (p))
1827     {
1828     case IMAGE_MONO_PIXMAP:
1829     case IMAGE_COLOR_PIXMAP:
1830     case IMAGE_POINTER:
1831       sprintf (buf, " (0x%lx", 
1832                (unsigned long) IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
1833       write_c_string (buf, printcharfun);
1834       if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
1835         {
1836           sprintf (buf, "/0x%lx", 
1837                    (unsigned long) IMAGE_INSTANCE_MSWINDOWS_MASK (p));
1838           write_c_string (buf, printcharfun);
1839         }
1840       write_c_string (")", printcharfun);
1841       break;
1842     default:
1843       break;
1844     }
1845 }
1846
1847 static void
1848 mswindows_finalize_image_instance (struct Lisp_Image_Instance *p)
1849 {
1850   if (!p->data)
1851     return;
1852
1853   if (DEVICE_LIVE_P (XDEVICE (p->device)))
1854     {
1855       if (IMAGE_INSTANCE_MSWINDOWS_BITMAP (p))
1856         DeleteObject (IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
1857       IMAGE_INSTANCE_MSWINDOWS_BITMAP (p) = 0;
1858       if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
1859         DeleteObject (IMAGE_INSTANCE_MSWINDOWS_MASK (p));
1860       IMAGE_INSTANCE_MSWINDOWS_MASK (p) = 0;
1861       if (IMAGE_INSTANCE_MSWINDOWS_ICON (p))
1862         DestroyIcon (IMAGE_INSTANCE_MSWINDOWS_ICON (p));
1863       IMAGE_INSTANCE_MSWINDOWS_ICON (p) = 0;
1864     }
1865
1866   xfree (p->data);
1867   p->data = 0;
1868 }
1869
1870 static int
1871 mswindows_image_instance_equal (struct Lisp_Image_Instance *p1,
1872                                 struct Lisp_Image_Instance *p2, int depth)
1873 {
1874   switch (IMAGE_INSTANCE_TYPE (p1))
1875     {
1876     case IMAGE_MONO_PIXMAP:
1877     case IMAGE_COLOR_PIXMAP:
1878     case IMAGE_POINTER:
1879       if (IMAGE_INSTANCE_MSWINDOWS_BITMAP (p1) 
1880           != IMAGE_INSTANCE_MSWINDOWS_BITMAP (p2))
1881         return 0;
1882       break;
1883     default:
1884       break;
1885     }
1886
1887   return 1;
1888 }
1889
1890 static unsigned long
1891 mswindows_image_instance_hash (struct Lisp_Image_Instance *p, int depth)
1892 {
1893   switch (IMAGE_INSTANCE_TYPE (p))
1894     {
1895     case IMAGE_MONO_PIXMAP:
1896     case IMAGE_COLOR_PIXMAP:
1897     case IMAGE_POINTER:
1898       return (unsigned long) IMAGE_INSTANCE_MSWINDOWS_BITMAP (p);
1899     default:
1900       return 0;
1901     }
1902 }
1903
1904 /* Set all the slots in an image instance structure to reasonable
1905    default values.  This is used somewhere within an instantiate
1906    method.  It is assumed that the device slot within the image
1907    instance is already set -- this is the case when instantiate
1908    methods are called. */
1909
1910 static void
1911 mswindows_initialize_dibitmap_image_instance (struct Lisp_Image_Instance *ii,
1912                                             enum image_instance_type type)
1913 {
1914   ii->data = xnew_and_zero (struct mswindows_image_instance_data);
1915   IMAGE_INSTANCE_TYPE (ii) = type;
1916   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = Qnil;
1917   IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (ii) = Qnil;
1918   IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = Qnil;
1919   IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = Qnil;
1920   IMAGE_INSTANCE_PIXMAP_FG (ii) = Qnil;
1921   IMAGE_INSTANCE_PIXMAP_BG (ii) = Qnil;
1922 }
1923
1924 \f
1925 /************************************************************************/
1926 /*                            initialization                            */
1927 /************************************************************************/
1928
1929 void
1930 syms_of_glyphs_mswindows (void)
1931 {
1932   defkeyword (&Q_resource_id, ":resource-id");
1933   defkeyword (&Q_resource_type, ":resource-type");
1934 }
1935
1936 void
1937 console_type_create_glyphs_mswindows (void)
1938 {
1939   /* image methods */
1940
1941   CONSOLE_HAS_METHOD (mswindows, print_image_instance);
1942   CONSOLE_HAS_METHOD (mswindows, finalize_image_instance);
1943   CONSOLE_HAS_METHOD (mswindows, image_instance_equal);
1944   CONSOLE_HAS_METHOD (mswindows, image_instance_hash);
1945   CONSOLE_HAS_METHOD (mswindows, init_image_instance_from_eimage);
1946   CONSOLE_HAS_METHOD (mswindows, locate_pixmap_file);
1947 #ifdef HAVE_XPM
1948   CONSOLE_HAS_METHOD (mswindows, xpm_instantiate);
1949 #endif
1950   CONSOLE_HAS_METHOD (mswindows, xbm_instantiate);
1951 }
1952
1953 void
1954 image_instantiator_format_create_glyphs_mswindows (void)
1955 {
1956   /* image-instantiator types */
1957
1958   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (bmp, "bmp");
1959
1960   IIFORMAT_HAS_METHOD (bmp, validate);
1961   IIFORMAT_HAS_METHOD (bmp, normalize);
1962   IIFORMAT_HAS_METHOD (bmp, possible_dest_types);
1963   IIFORMAT_HAS_METHOD (bmp, instantiate);
1964
1965   IIFORMAT_VALID_KEYWORD (bmp, Q_data, check_valid_string);
1966   IIFORMAT_VALID_KEYWORD (bmp, Q_file, check_valid_string);
1967
1968   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (mswindows_resource,
1969                                         "mswindows-resource");
1970
1971   IIFORMAT_HAS_METHOD (mswindows_resource, validate);
1972   IIFORMAT_HAS_METHOD (mswindows_resource, normalize);
1973   IIFORMAT_HAS_METHOD (mswindows_resource, possible_dest_types);
1974   IIFORMAT_HAS_METHOD (mswindows_resource, instantiate);
1975
1976   IIFORMAT_VALID_KEYWORD (mswindows_resource, Q_resource_type, 
1977                           check_valid_resource_symbol);
1978   IIFORMAT_VALID_KEYWORD (mswindows_resource, Q_resource_id, check_valid_resource_id);
1979   IIFORMAT_VALID_KEYWORD (mswindows_resource, Q_file, check_valid_string);
1980 }
1981
1982 void
1983 vars_of_glyphs_mswindows (void)
1984 {
1985   Fprovide (Qbmp);
1986   Fprovide (Qmswindows_resource);
1987   DEFVAR_LISP ("mswindows-bitmap-file-path", &Vmswindows_bitmap_file_path /*
1988 A list of the directories in which mswindows bitmap files may be found.
1989 This is used by the `make-image-instance' function.
1990 */ );
1991   Vmswindows_bitmap_file_path = Qnil;
1992 }
1993
1994 void
1995 complex_vars_of_glyphs_mswindows (void)
1996 {
1997 }