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