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