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