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