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