]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkimage-win32.c
Corresponding changes as in X11 backend.
[~andy/gtk] / gdk / win32 / gdkimage-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include "gdk.h"                /* For gdk_error_trap_* / gdk_flush_* */
30 #include "gdkimage.h"
31 #include "gdkprivate.h"
32 #include "gdkx.h"
33
34 static void gdk_image_put_normal (GdkDrawable *drawable,
35                                   GdkGC       *gc,
36                                   GdkImage    *image,
37                                   gint         xsrc,
38                                   gint         ysrc,
39                                   gint         xdest,
40                                   gint         ydest,
41                                   gint         width,
42                                   gint         height);
43 static GList *image_list = NULL;
44
45 void
46 gdk_image_exit (void)
47 {
48   GdkImage *image;
49
50   while (image_list)
51     {
52       image = image_list->data;
53       gdk_image_destroy (image);
54     }
55 }
56
57 GdkImage *
58 gdk_image_new_bitmap (GdkVisual *visual, gpointer data, gint w, gint h)
59 /*
60  * Desc: create a new bitmap image
61  */
62 {
63   Visual *xvisual;
64   GdkImage *image;
65   GdkImagePrivate *private;
66   struct {
67     BITMAPINFOHEADER bmiHeader;
68     union {
69       WORD bmiIndices[2];
70       RGBQUAD bmiColors[2];
71     } u;
72   } bmi;
73   char *bits;
74   int bpl = (w-1)/8 + 1;
75   int bpl32 = ((w-1)/32 + 1)*4;
76
77   private = g_new(GdkImagePrivate, 1);
78   image = (GdkImage *) private;
79   private->image_put = gdk_image_put_normal;
80   image->type = GDK_IMAGE_SHARED;
81   image->visual = visual;
82   image->width = w;
83   image->height = h;
84   image->depth = 1;
85   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
86
87   GDK_NOTE (MISC, g_print ("gdk_image_new_bitmap: %dx%d\n", w, h));
88   
89   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
90   bmi.bmiHeader.biWidth = w;
91   bmi.bmiHeader.biHeight = -h;
92   bmi.bmiHeader.biPlanes = 1;
93   bmi.bmiHeader.biBitCount = 1;
94   bmi.bmiHeader.biCompression = BI_RGB;
95   bmi.bmiHeader.biSizeImage = 0;
96   bmi.bmiHeader.biXPelsPerMeter =
97     bmi.bmiHeader.biYPelsPerMeter = 0;
98   bmi.bmiHeader.biClrUsed = 0;
99   bmi.bmiHeader.biClrImportant = 0;
100   
101   bmi.u.bmiColors[0].rgbBlue = 
102     bmi.u.bmiColors[0].rgbGreen = 
103     bmi.u.bmiColors[0].rgbRed = 0x00;
104   bmi.u.bmiColors[0].rgbReserved = 0x00;
105
106   bmi.u.bmiColors[1].rgbBlue = 
107     bmi.u.bmiColors[1].rgbGreen = 
108     bmi.u.bmiColors[1].rgbRed = 0xFF;
109   bmi.u.bmiColors[1].rgbReserved = 0x00;
110   
111   private->ximage = CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi,
112                                       DIB_RGB_COLORS, &bits, NULL, 0);
113   if (bpl != bpl32)
114     {
115       /* Win32 expects scanlines in DIBs to be 32 bit aligned */
116       int i;
117       for (i = 0; i < h; i++)
118         memmove (bits + i*bpl32, ((char *) data) + i*bpl, bpl);
119     }
120   else
121     memmove (bits, data, bpl*h);
122   image->mem = bits;
123   image->bpl = bpl32;
124   image->byte_order = GDK_MSB_FIRST;
125
126   image->bpp = 1;
127   return(image);
128 } /* gdk_image_new_bitmap() */
129
130 void
131 gdk_image_init (void)
132 {
133 }
134
135 static GdkImage*
136 gdk_image_new_with_depth (GdkImageType  type,
137                           GdkVisual    *visual,
138                           gint          width,
139                           gint          height,
140                           gint          depth)
141 {
142   GdkImage *image;
143   GdkImagePrivate *private;
144   Visual *xvisual;
145   struct {
146     BITMAPINFOHEADER bmiHeader;
147     union {
148       WORD bmiIndices[256];
149       DWORD bmiMasks[3];
150       RGBQUAD bmiColors[256];
151     } u;
152   } bmi;
153   UINT iUsage;
154   int i;
155
156   if (type == GDK_IMAGE_FASTEST || type == GDK_IMAGE_NORMAL)
157     type = GDK_IMAGE_SHARED;
158
159   GDK_NOTE (MISC, g_print ("gdk_image_new_with_depth: %dx%dx%d %s\n",
160                            width, height, depth,
161                            (type == GDK_IMAGE_SHARED ? "shared" :
162                             (type == GDK_IMAGE_SHARED_PIXMAP ? "shared_pixmap" :
163                              "???"))));
164
165   private = g_new (GdkImagePrivate, 1);
166   image = (GdkImage*) private;
167
168   private->image_put = NULL;
169
170   image->type = type;
171   image->visual = visual;
172   image->width = width;
173   image->height = height;
174   image->depth = depth;
175   
176   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
177   
178   private->image_put = gdk_image_put_normal;
179       
180   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
181   bmi.bmiHeader.biWidth = width;
182   bmi.bmiHeader.biHeight = -height;
183   bmi.bmiHeader.biPlanes = 1;
184   if (depth == 15)
185     bmi.bmiHeader.biBitCount = 16;
186   else
187     bmi.bmiHeader.biBitCount = depth;
188 #if 1
189   if (depth == 16)
190     bmi.bmiHeader.biCompression = BI_BITFIELDS;
191   else
192 #endif
193     bmi.bmiHeader.biCompression = BI_RGB;
194   bmi.bmiHeader.biSizeImage = 0;
195   bmi.bmiHeader.biXPelsPerMeter =
196     bmi.bmiHeader.biYPelsPerMeter = 0;
197   bmi.bmiHeader.biClrUsed = 0;
198   bmi.bmiHeader.biClrImportant = 0;
199
200   if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
201     {
202       iUsage = DIB_PAL_COLORS;
203       for (i = 0; i < 256; i++)
204         bmi.u.bmiIndices[i] = i;
205     }
206   else
207     {
208       if (depth == 1)
209         {
210           bmi.u.bmiColors[0].rgbBlue = 
211             bmi.u.bmiColors[0].rgbGreen =
212             bmi.u.bmiColors[0].rgbRed = 0x00;
213           bmi.u.bmiColors[0].rgbReserved = 0x00;
214
215           bmi.u.bmiColors[1].rgbBlue = 
216             bmi.u.bmiColors[1].rgbGreen =
217             bmi.u.bmiColors[1].rgbRed = 0xFF;
218           bmi.u.bmiColors[1].rgbReserved = 0x00;
219
220         }
221 #if 1
222       else if (depth == 16)
223         {
224           bmi.u.bmiMasks[0] = visual->red_mask;
225           bmi.u.bmiMasks[1] = visual->green_mask;
226           bmi.u.bmiMasks[2] = visual->blue_mask;
227         }
228 #endif
229       iUsage = DIB_RGB_COLORS;
230     }
231
232   private->ximage =
233     CreateDIBSection (gdk_DC, (BITMAPINFO *) &bmi, iUsage,
234                       &image->mem, NULL, 0);
235
236   if (private->ximage == NULL)
237     {
238       g_warning ("gdk_image_new_with_depth: CreateDIBSection failed");
239       g_free (image);
240       return NULL;
241     }
242
243   switch (depth)
244     {
245     case 1:
246     case 8:
247       image->bpp = 1;
248       break;
249     case 15:
250     case 16:
251       image->bpp = 2;
252       break;
253     case 24:
254       image->bpp = 3;
255       break;
256     case 32:
257       image->bpp = 4;
258       break;
259     default:
260       g_warning ("gdk_image_new_with_depth: depth = %d", depth);
261       g_assert_not_reached ();
262     }
263   image->byte_order = GDK_LSB_FIRST;
264   if (depth == 1)
265     image->bpl = ((width-1)/32 + 1)*4;
266   else
267     image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
268
269   GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
270                            private->ximage, image->mem, image->bpl));
271
272   return image;
273 }
274
275 GdkImage*
276 gdk_image_new (GdkImageType  type,
277                GdkVisual    *visual,
278                gint          width,
279                gint          height)
280 {
281   GdkVisualPrivate *visual_private = (GdkVisualPrivate *) visual;
282   return gdk_image_new_with_depth (type, visual, width, height,
283                                    visual_private->xvisual->bitspixel);
284 }
285
286 GdkImage*
287 gdk_image_bitmap_new (GdkImageType  type,
288                       GdkVisual    *visual,
289                       gint          width,
290                       gint          height)
291 {
292   return gdk_image_new_with_depth (type, visual, width, height, 1);
293 }
294
295 GdkImage*
296 gdk_image_get (GdkWindow *window,
297                gint       x,
298                gint       y,
299                gint       width,
300                gint       height)
301 {
302   GdkImage *image;
303   GdkImagePrivate *private;
304   HDC hdc, memdc;
305   struct {
306     BITMAPINFOHEADER bmiHeader;
307     union {
308       WORD bmiIndices[256];
309       DWORD bmiMasks[3];
310       RGBQUAD bmiColors[256];
311     } u;
312   } bmi;
313   HGDIOBJ oldbitmap1, oldbitmap2;
314   UINT iUsage;
315   BITMAP bm;
316   int i;
317
318   g_return_val_if_fail (window != NULL, NULL);
319
320   if (GDK_DRAWABLE_DESTROYED (window))
321     return NULL;
322
323   GDK_NOTE (MISC, g_print ("gdk_image_get: %#x %dx%d@+%d+%d\n",
324                            GDK_DRAWABLE_XID (window), width, height, x, y));
325
326   private = g_new (GdkImagePrivate, 1);
327   image = (GdkImage*) private;
328
329   private->image_put = gdk_image_put_normal;
330
331   image->type = GDK_IMAGE_SHARED;
332   image->visual = gdk_window_get_visual (window);
333   image->width = width;
334   image->height = height;
335
336   /* This function is called both to blit from a window and from
337    * a pixmap.
338    */
339   if (GDK_DRAWABLE_TYPE (window) == GDK_DRAWABLE_PIXMAP)
340     {
341       if ((hdc = CreateCompatibleDC (NULL)) == NULL)
342         {
343           g_warning ("gdk_image_get: CreateCompatibleDC #1 failed");
344           g_free (image);
345           return NULL;
346         }
347       if ((oldbitmap1 = SelectObject (hdc, GDK_DRAWABLE_XID (window))) == NULL)
348         {
349           g_warning ("gdk_image_get: SelectObject #1 failed");
350           DeleteDC (hdc);
351           g_free (image);
352           return NULL;
353         }
354       GetObject (GDK_DRAWABLE_XID (window), sizeof (BITMAP), &bm);
355       GDK_NOTE (MISC,
356                 g_print ("gdk_image_get: bmWidth = %d, bmHeight = %d, bmWidthBytes = %d, bmBitsPixel = %d\n",
357                          bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmBitsPixel));
358       image->depth = bm.bmBitsPixel;
359       if (image->depth <= 8)
360         {
361           iUsage = DIB_PAL_COLORS;
362           for (i = 0; i < 256; i++)
363             bmi.u.bmiIndices[i] = i;
364         }
365       else
366         iUsage = DIB_RGB_COLORS;
367     }
368   else
369     {
370       if ((hdc = GetDC (GDK_DRAWABLE_XID (window))) == NULL)
371         {
372           g_warning ("gdk_image_get: GetDC failed");
373           g_free (image);
374           return NULL;
375         }
376       image->depth = gdk_visual_get_system ()->depth;
377       if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
378         {
379           iUsage = DIB_PAL_COLORS;
380           for (i = 0; i < 256; i++)
381             bmi.u.bmiIndices[i] = i;
382         }
383       else
384         iUsage = DIB_RGB_COLORS;
385     }
386
387   if ((memdc = CreateCompatibleDC (hdc)) == NULL)
388     {
389       g_warning ("gdk_image_get: CreateCompatibleDC #2 failed");
390       if (GDK_DRAWABLE_TYPE (window) == GDK_DRAWABLE_PIXMAP)
391         {
392           SelectObject (hdc, oldbitmap1);
393           DeleteDC (hdc);
394         }
395       else
396         {
397           ReleaseDC (GDK_DRAWABLE_XID (window), hdc);
398         }
399       g_free (image);
400       return NULL;
401     }
402
403   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
404   bmi.bmiHeader.biWidth = width;
405   bmi.bmiHeader.biHeight = -height;
406   bmi.bmiHeader.biPlanes = 1;
407   bmi.bmiHeader.biBitCount = image->depth;
408   if (image->depth == 16)
409     {
410       bmi.bmiHeader.biCompression = BI_BITFIELDS;
411       if (image->visual == NULL)
412         {
413           /* XXX ??? Is it always this if depth==16 and a pixmap? Guess so. */
414           bmi.u.bmiMasks[0] = 0xf800;
415           bmi.u.bmiMasks[1] = 0x07e0;
416           bmi.u.bmiMasks[2] = 0x001f;
417         }
418       else
419         {
420           bmi.u.bmiMasks[0] = image->visual->red_mask;
421           bmi.u.bmiMasks[1] = image->visual->green_mask;
422           bmi.u.bmiMasks[2] = image->visual->blue_mask;
423         }
424     }
425   else
426     bmi.bmiHeader.biCompression = BI_RGB;
427   bmi.bmiHeader.biSizeImage = 0;
428   bmi.bmiHeader.biXPelsPerMeter =
429     bmi.bmiHeader.biYPelsPerMeter = 0;
430   bmi.bmiHeader.biClrUsed = 0;
431   bmi.bmiHeader.biClrImportant = 0;
432
433   if ((private->ximage =
434        CreateDIBSection (hdc, (BITMAPINFO *) &bmi, iUsage,
435                          &image->mem, NULL, 0)) == NULL)
436     {
437       g_warning ("gdk_image_get: CreateDIBSection failed");
438       DeleteDC (memdc);
439       if (GDK_DRAWABLE_TYPE (window) == GDK_DRAWABLE_PIXMAP)
440         {
441           SelectObject (hdc, oldbitmap1);
442           DeleteDC (hdc);
443         }
444       else
445         {
446           ReleaseDC (GDK_DRAWABLE_XID (window), hdc);
447         }
448       g_free (image);
449       return NULL;
450     }
451
452   if ((oldbitmap2 = SelectObject (memdc, private->ximage)) == NULL)
453     {
454       g_warning ("gdk_image_get: SelectObject #2 failed");
455       DeleteObject (private->ximage);
456       DeleteDC (memdc);
457       if (GDK_DRAWABLE_TYPE (window) == GDK_DRAWABLE_PIXMAP)
458         {
459           SelectObject (hdc, oldbitmap1);
460           DeleteDC (hdc);
461         }
462       else
463         {
464           ReleaseDC (GDK_DRAWABLE_XID (window), hdc);
465         }
466       g_free (image);
467       return NULL;
468     }
469
470   if (!BitBlt (memdc, 0, 0, width, height, hdc, x, y, SRCCOPY))
471     {
472       g_warning ("gdk_image_get: BitBlt failed");
473       SelectObject (memdc, oldbitmap2);
474       DeleteObject (private->ximage);
475       DeleteDC (memdc);
476       if (GDK_DRAWABLE_TYPE (window) == GDK_DRAWABLE_PIXMAP)
477         {
478           SelectObject (hdc, oldbitmap1);
479           DeleteDC (hdc);
480         }
481       else
482         {
483           ReleaseDC (GDK_DRAWABLE_XID (window), hdc);
484         }
485       g_free (image);
486       return NULL;
487     }
488
489   if (SelectObject (memdc, oldbitmap2) == NULL)
490     g_warning ("gdk_image_get: SelectObject #3 failed");
491
492   if (!DeleteDC (memdc))
493     g_warning ("gdk_image_get: DeleteDC failed");
494
495   if (GDK_DRAWABLE_TYPE (window) == GDK_DRAWABLE_PIXMAP)
496     {
497       SelectObject (hdc, oldbitmap1);
498       DeleteDC (hdc);
499     }
500   else
501     {
502       ReleaseDC (GDK_DRAWABLE_XID (window), hdc);
503     }
504
505   switch (image->depth)
506     {
507     case 1:
508     case 8:
509       image->bpp = 1;
510       break;
511     case 15:
512     case 16:
513       image->bpp = 2;
514       break;
515     case 24:
516       image->bpp = 3;
517       break;
518     case 32:
519       image->bpp = 4;
520       break;
521     default:
522       g_warning ("gdk_image_get: image->depth = %d", image->depth);
523       g_assert_not_reached ();
524     }
525   image->byte_order = GDK_LSB_FIRST;
526   if (image->depth == 1)
527     image->bpl = ((width - 1)/32 + 1)*4;
528   else
529     image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
530
531   GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
532                            private->ximage, image->mem, image->bpl));
533
534   return image;
535 }
536
537 guint32
538 gdk_image_get_pixel (GdkImage *image,
539                      gint x,
540                      gint y)
541 {
542   guint32 pixel;
543   GdkImagePrivate *private;
544
545   g_return_val_if_fail (image != NULL, 0);
546
547   private = (GdkImagePrivate *) image;
548
549   g_return_val_if_fail (x >= 0 && x < image->width
550                         && y >= 0 && y < image->height, 0);
551
552   if (image->depth == 1)
553     pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
554   else
555     {
556       guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
557       
558       switch (image->bpp)
559         {
560         case 1:
561           pixel = *pixelp;
562           break;
563
564         /* Windows is always LSB, no need to check image->byte_order. */
565         case 2:
566           pixel = pixelp[0] | (pixelp[1] << 8);
567           break;
568
569         case 3:
570           pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
571           break;
572
573         case 4:
574           pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
575           break;
576         }
577     }
578
579   return pixel;
580 }
581
582 void
583 gdk_image_put_pixel (GdkImage *image,
584                      gint x,
585                      gint y,
586                      guint32 pixel)
587 {
588   GdkImagePrivate *private;
589
590   g_return_if_fail (image != NULL);
591
592   private = (GdkImagePrivate *) image;
593
594   g_return_if_fail (x >= 0 && x < image->width && y >= 0 && y < image->height);
595
596   if (image->depth == 1)
597     if (pixel & 1)
598       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
599     else
600       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
601   else
602     {
603       guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
604       
605       /* Windows is always LSB, no need to check image->byte_order. */
606       switch (image->bpp)
607         {
608         case 4:
609           pixelp[3] = 0;
610         case 3:
611           pixelp[2] = ((pixel >> 16) & 0xFF);
612         case 2:
613           pixelp[1] = ((pixel >> 8) & 0xFF);
614         case 1:
615           pixelp[0] = (pixel & 0xFF);
616         }
617     }
618 }
619
620 void
621 gdk_image_destroy (GdkImage *image)
622 {
623   GdkImagePrivate *private;
624
625   g_return_if_fail (image != NULL);
626
627   private = (GdkImagePrivate*) image;
628
629   GDK_NOTE (MISC, g_print ("gdk_image_destroy: %#x%s\n",
630                            private->ximage,
631                            (image->type == GDK_IMAGE_SHARED_PIXMAP ?
632                             " (shared pixmap)" : "")));
633   
634   switch (image->type)
635     {
636     case GDK_IMAGE_SHARED_PIXMAP:
637       break;                    /* The Windows bitmap has already been
638                                  * (or will be) deleted when freeing
639                                  * the corresponding pixmap.
640                                  */
641
642     case GDK_IMAGE_SHARED:
643       if (!DeleteObject (private->ximage))
644         g_warning ("gdk_image_destroy: DeleteObject failed");
645       break;
646
647     default:
648       g_assert_not_reached ();
649     }
650
651   g_free (image);
652 }
653
654 static void
655 gdk_image_put_normal (GdkDrawable *drawable,
656                       GdkGC       *gc,
657                       GdkImage    *image,
658                       gint         xsrc,
659                       gint         ysrc,
660                       gint         xdest,
661                       gint         ydest,
662                       gint         width,
663                       gint         height)
664 {
665   GdkDrawablePrivate *drawable_private;
666   GdkImagePrivate *image_private;
667   GdkGCPrivate *gc_private;
668   HDC hdc;
669   GdkColormapPrivate *colormap_private;
670
671   g_return_if_fail (drawable != NULL);
672   g_return_if_fail (image != NULL);
673   g_return_if_fail (gc != NULL);
674
675   if (GDK_DRAWABLE_DESTROYED (drawable))
676     return;
677   image_private = (GdkImagePrivate*) image;
678   drawable_private = (GdkDrawablePrivate*) drawable;
679   gc_private = (GdkGCPrivate*) gc;
680
681   /* The image can in fact be "shared", so don't test */
682
683   hdc = gdk_gc_predraw (drawable_private, gc_private);
684   colormap_private = (GdkColormapPrivate *) drawable_private->colormap;
685   if (colormap_private && colormap_private->xcolormap->rc_palette)
686     {
687       DIBSECTION ds;
688       static struct {
689         BITMAPINFOHEADER bmiHeader;
690         WORD bmiIndices[256];
691       } bmi;
692       static gboolean bmi_inited = FALSE;
693       int i;
694
695       if (!bmi_inited)
696         {
697           for (i = 0; i < 256; i++)
698             bmi.bmiIndices[i] = i;
699           bmi_inited = TRUE;
700         }
701
702       if (GetObject (image_private->ximage, sizeof (DIBSECTION),
703                      &ds) != sizeof (DIBSECTION))
704         {
705           g_warning ("gdk_image_put_normal: GetObject failed");
706         }
707 #if 0
708       g_print("xdest = %d, ydest = %d, xsrc = %d, ysrc = %d, width = %d, height = %d\n",
709               xdest, ydest, xsrc, ysrc, width, height);
710       g_print("bmWidth = %d, bmHeight = %d, bmBitsPixel = %d, bmBits = %p\n",
711               ds.dsBm.bmWidth, ds.dsBm.bmHeight, ds.dsBm.bmBitsPixel, ds.dsBm.bmBits);
712       g_print("biWidth = %d, biHeight = %d, biBitCount = %d, biClrUsed = %d\n",
713               ds.dsBmih.biWidth, ds.dsBmih.biHeight, ds.dsBmih.biBitCount, ds.dsBmih.biClrUsed);
714 #endif
715       bmi.bmiHeader = ds.dsBmih;
716       /* I have spent hours on getting the parameters to
717        * SetDIBitsToDevice right. I wonder what drugs the guys in
718        * Redmond were on when they designed this API.
719        */
720       if (SetDIBitsToDevice (hdc,
721                              xdest, ydest,
722                              width, height,
723                              xsrc, (-ds.dsBmih.biHeight)-height-ysrc,
724                              0, -ds.dsBmih.biHeight,
725                              ds.dsBm.bmBits,
726                              (CONST BITMAPINFO *) &bmi,
727                              DIB_PAL_COLORS) == 0)
728         g_warning ("SetDIBitsToDevice failed");
729     }
730   else
731     {
732       HDC memdc;
733       HGDIOBJ oldbitmap;
734
735       if ((memdc = CreateCompatibleDC (hdc)) == NULL)
736         {
737           g_warning ("gdk_image_put_normal: CreateCompatibleDC failed");
738           gdk_gc_postdraw (drawable_private, gc_private);
739           return;
740         }
741
742       if ((oldbitmap = SelectObject (memdc, image_private->ximage)) == NULL)
743         {
744           g_warning ("gdk_image_put_normal: SelectObject #1 failed");
745           gdk_gc_postdraw (drawable_private, gc_private);
746           return;
747         }
748       if (!BitBlt (hdc, xdest, ydest, width, height,
749                    memdc, xsrc, ysrc, SRCCOPY))
750         g_warning ("gdk_image_put_normal: BitBlt failed");
751
752       if (SelectObject (memdc, oldbitmap) == NULL)
753         g_warning ("gdk_image_put_normal: SelectObject #2 failed");
754
755       if (!DeleteDC (memdc))
756         g_warning ("gdk_image_put_normal: DeleteDC failed");
757     }
758   gdk_gc_postdraw (drawable_private, gc_private);
759 }