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