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