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