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