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