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