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