]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkimage-win32.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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-2000.  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 "gdkimage.h"
30 #include "gdkpixmap.h"
31 #include "gdkinternals.h"
32 #include "gdkprivate-win32.h"
33 #include "gdkdrawable-win32.h"
34 #include "gdkwindow-win32.h"
35 #include "gdkpixmap-win32.h"
36
37 static GList *image_list = NULL;
38 static gpointer parent_class = NULL;
39
40 static void gdk_win32_image_destroy (GdkImage      *image);
41 static void gdk_image_init          (GdkImage      *image);
42 static void gdk_image_class_init    (GdkImageClass *klass);
43 static void gdk_image_finalize      (GObject       *object);
44
45 #define PRIVATE_DATA(image) ((GdkImagePrivateWin32 *) GDK_IMAGE (image)->windowing_data)
46
47 GType
48 gdk_image_get_type (void)
49 {
50   static GType object_type = 0;
51
52   if (!object_type)
53     {
54       static const GTypeInfo object_info =
55       {
56         sizeof (GdkImageClass),
57         (GBaseInitFunc) NULL,
58         (GBaseFinalizeFunc) NULL,
59         (GClassInitFunc) gdk_image_class_init,
60         NULL,           /* class_finalize */
61         NULL,           /* class_data */
62         sizeof (GdkImage),
63         0,              /* n_preallocs */
64         (GInstanceInitFunc) gdk_image_init,
65       };
66       
67       object_type = g_type_register_static (G_TYPE_OBJECT,
68                                             "GdkImage",
69                                             &object_info);
70     }
71   
72   return object_type;
73 }
74
75 static void
76 gdk_image_init (GdkImage *image)
77 {
78   image->windowing_data = g_new0 (GdkImagePrivateWin32, 1);
79 }
80
81 static void
82 gdk_image_class_init (GdkImageClass *klass)
83 {
84   GObjectClass *object_class = G_OBJECT_CLASS (klass);
85
86   parent_class = g_type_class_peek_parent (klass);
87
88   object_class->finalize = gdk_image_finalize;
89 }
90
91 static void
92 gdk_image_finalize (GObject *object)
93 {
94   GdkImage *image = GDK_IMAGE (object);
95
96   gdk_win32_image_destroy (image);
97   
98   G_OBJECT_CLASS (parent_class)->finalize (object);
99 }
100
101 void
102 gdk_image_exit (void)
103 {
104   GdkImage *image;
105
106   while (image_list)
107     {
108       image = image_list->data;
109       gdk_win32_image_destroy (image);
110     }
111 }
112
113 GdkImage *
114 gdk_image_new_bitmap (GdkVisual *visual,
115                       gpointer   data,
116                       gint       w,
117                       gint       h)
118 /*
119  * Desc: create a new bitmap image
120  */
121 {
122   Visual *xvisual;
123   GdkImage *image;
124   GdkImagePrivateWin32 *private;
125   struct {
126     BITMAPINFOHEADER bmiHeader;
127     union {
128       WORD bmiIndices[2];
129       RGBQUAD bmiColors[2];
130     } u;
131   } bmi;
132   char *bits;
133   int bpl = (w-1)/8 + 1;
134   int bpl32 = ((w-1)/32 + 1)*4;
135
136   image = g_object_new (gdk_image_get_type (), NULL);
137   private = PRIVATE_DATA (image);
138
139   image->type = GDK_IMAGE_SHARED;
140   image->visual = visual;
141   image->width = w;
142   image->height = h;
143   image->depth = 1;
144   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
145
146   GDK_NOTE (MISC, g_print ("gdk_image_new_bitmap: %dx%d\n", w, h));
147   
148   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
149   bmi.bmiHeader.biWidth = w;
150   bmi.bmiHeader.biHeight = -h;
151   bmi.bmiHeader.biPlanes = 1;
152   bmi.bmiHeader.biBitCount = 1;
153   bmi.bmiHeader.biCompression = BI_RGB;
154   bmi.bmiHeader.biSizeImage = 0;
155   bmi.bmiHeader.biXPelsPerMeter =
156     bmi.bmiHeader.biYPelsPerMeter = 0;
157   bmi.bmiHeader.biClrUsed = 0;
158   bmi.bmiHeader.biClrImportant = 0;
159   
160   bmi.u.bmiColors[0].rgbBlue = 
161     bmi.u.bmiColors[0].rgbGreen = 
162     bmi.u.bmiColors[0].rgbRed = 0x00;
163   bmi.u.bmiColors[0].rgbReserved = 0x00;
164
165   bmi.u.bmiColors[1].rgbBlue = 
166     bmi.u.bmiColors[1].rgbGreen = 
167     bmi.u.bmiColors[1].rgbRed = 0xFF;
168   bmi.u.bmiColors[1].rgbReserved = 0x00;
169   
170   private->hbitmap = CreateDIBSection (gdk_display_hdc, (BITMAPINFO *) &bmi,
171                                        DIB_RGB_COLORS, &bits, NULL, 0);
172   if (bpl != bpl32)
173     {
174       /* Win32 expects scanlines in DIBs to be 32 bit aligned */
175       int i;
176       for (i = 0; i < h; i++)
177         memmove (bits + i*bpl32, ((char *) data) + i*bpl, bpl);
178     }
179   else
180     memmove (bits, data, bpl*h);
181   image->mem = bits;
182   image->bpl = bpl32;
183   image->byte_order = GDK_MSB_FIRST;
184
185   image->bpp = 1;
186   return(image);
187 } /* gdk_image_new_bitmap() */
188
189 void
190 _gdk_windowing_image_init (void)
191 {
192   /* Nothing needed AFAIK */
193 }
194
195 GdkImage*
196 gdk_image_new (GdkImageType  type,
197                GdkVisual    *visual,
198                gint          width,
199                gint          height)
200 {
201   GdkImage *image;
202   GdkImagePrivateWin32 *private;
203   Visual *xvisual;
204   struct {
205     BITMAPINFOHEADER bmiHeader;
206     union {
207       WORD bmiIndices[256];
208       DWORD bmiMasks[3];
209       RGBQUAD bmiColors[256];
210     } u;
211   } bmi;
212   UINT iUsage;
213   int i;
214
215   if (type == GDK_IMAGE_FASTEST || type == GDK_IMAGE_NORMAL)
216     type = GDK_IMAGE_SHARED;
217
218   GDK_NOTE (MISC, g_print ("gdk_image_new: %dx%d %s\n",
219                            width, height,
220                            (type == GDK_IMAGE_SHARED ? "shared" :
221                             (type == GDK_IMAGE_SHARED_PIXMAP ? "shared_pixmap" :
222                              "???"))));
223
224   image = g_object_new (gdk_image_get_type (), NULL);
225   private = PRIVATE_DATA (image);
226
227   image->type = type;
228   image->visual = visual;
229   image->width = width;
230   image->height = height;
231   image->depth = visual->depth;
232   
233   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
234   
235   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
236   bmi.bmiHeader.biWidth = width;
237   bmi.bmiHeader.biHeight = -height;
238   bmi.bmiHeader.biPlanes = 1;
239   if (image->depth == 15)
240     bmi.bmiHeader.biBitCount = 16;
241   else
242     bmi.bmiHeader.biBitCount = image->depth;
243   if (image->depth == 16)
244     bmi.bmiHeader.biCompression = BI_BITFIELDS;
245   else
246     bmi.bmiHeader.biCompression = BI_RGB;
247   bmi.bmiHeader.biSizeImage = 0;
248   bmi.bmiHeader.biXPelsPerMeter =
249     bmi.bmiHeader.biYPelsPerMeter = 0;
250   bmi.bmiHeader.biClrUsed = 0;
251   bmi.bmiHeader.biClrImportant = 0;
252
253   if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
254     {
255       iUsage = DIB_PAL_COLORS;
256       for (i = 0; i < 256; i++)
257         bmi.u.bmiIndices[i] = i;
258     }
259   else
260     {
261       iUsage = DIB_RGB_COLORS;
262       if (image->depth == 1)
263         {
264           bmi.u.bmiColors[0].rgbBlue = 
265             bmi.u.bmiColors[0].rgbGreen =
266             bmi.u.bmiColors[0].rgbRed = 0x00;
267           bmi.u.bmiColors[0].rgbReserved = 0x00;
268
269           bmi.u.bmiColors[1].rgbBlue = 
270             bmi.u.bmiColors[1].rgbGreen =
271             bmi.u.bmiColors[1].rgbRed = 0xFF;
272           bmi.u.bmiColors[1].rgbReserved = 0x00;
273
274         }
275       else if (image->depth == 16)
276         {
277           bmi.u.bmiMasks[0] = visual->red_mask;
278           bmi.u.bmiMasks[1] = visual->green_mask;
279           bmi.u.bmiMasks[2] = visual->blue_mask;
280         }
281     }
282
283   private->hbitmap = CreateDIBSection (gdk_display_hdc, (BITMAPINFO *) &bmi,
284                                        iUsage, &image->mem, NULL, 0);
285
286   if (private->hbitmap == NULL)
287     {
288       WIN32_GDI_FAILED ("CreateDIBSection");
289       g_free (image);
290       return NULL;
291     }
292
293   switch (image->depth)
294     {
295     case 1:
296     case 8:
297       image->bpp = 1;
298       break;
299     case 15:
300     case 16:
301       image->bpp = 2;
302       break;
303     case 24:
304       image->bpp = 3;
305       break;
306     case 32:
307       image->bpp = 4;
308       break;
309     default:
310       g_warning ("gdk_image_new: depth = %d", image->depth);
311       g_assert_not_reached ();
312     }
313   image->byte_order = GDK_LSB_FIRST;
314   if (image->depth == 1)
315     image->bpl = ((width-1)/32 + 1)*4;
316   else
317     image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
318
319   GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
320                            private->hbitmap, image->mem, image->bpl));
321
322   return image;
323 }
324
325 GdkImage*
326 gdk_image_get (GdkWindow *window,
327                gint       x,
328                gint       y,
329                gint       width,
330                gint       height)
331 {
332   GdkImage *image;
333   GdkImagePrivateWin32 *private;
334   HDC hdc, memdc;
335   struct {
336     BITMAPINFOHEADER bmiHeader;
337     union {
338       WORD bmiIndices[256];
339       DWORD bmiMasks[3];
340       RGBQUAD bmiColors[256];
341     } u;
342   } bmi;
343   HGDIOBJ oldbitmap1, oldbitmap2;
344   UINT iUsage;
345   BITMAP bm;
346   int i;
347
348   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
349
350   if (GDK_WINDOW_DESTROYED (window))
351     return NULL;
352
353   GDK_NOTE (MISC, g_print ("gdk_image_get: %#x %dx%d@+%d+%d\n",
354                            GDK_DRAWABLE_HANDLE (window), width, height, x, y));
355
356   image = g_object_new (gdk_image_get_type (), NULL);
357   private = PRIVATE_DATA (image);
358
359   image->type = GDK_IMAGE_SHARED;
360   image->visual = gdk_drawable_get_visual (window);
361   image->width = width;
362   image->height = height;
363
364   /* This function is called both to blit from a window and from
365    * a pixmap.
366    */
367   if (GDK_IS_PIXMAP (window))
368     {
369       if ((hdc = CreateCompatibleDC (NULL)) == NULL)
370         {
371           WIN32_GDI_FAILED ("CreateCompatibleDC");
372           g_free (image);
373           return NULL;
374         }
375       if ((oldbitmap1 = SelectObject (hdc, GDK_PIXMAP_HBITMAP (window))) == NULL)
376         {
377           WIN32_GDI_FAILED ("SelectObject");
378           DeleteDC (hdc);
379           g_free (image);
380           return NULL;
381         }
382       GetObject (GDK_PIXMAP_HBITMAP (window), sizeof (BITMAP), &bm);
383       GDK_NOTE (MISC,
384                 g_print ("gdk_image_get: bmWidth = %d, bmHeight = %d, bmWidthBytes = %d, bmBitsPixel = %d\n",
385                          bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmBitsPixel));
386       image->depth = bm.bmBitsPixel;
387       if (image->depth <= 8)
388         {
389           iUsage = DIB_PAL_COLORS;
390           for (i = 0; i < 256; i++)
391             bmi.u.bmiIndices[i] = i;
392         }
393       else
394         iUsage = DIB_RGB_COLORS;
395     }
396   else
397     {
398       if ((hdc = GetDC (GDK_WINDOW_HWND (window))) == NULL)
399         {
400           WIN32_GDI_FAILED ("GetDC");
401           g_free (image);
402           return NULL;
403         }
404       image->depth = gdk_visual_get_system ()->depth;
405       if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
406         {
407           iUsage = DIB_PAL_COLORS;
408           for (i = 0; i < 256; i++)
409             bmi.u.bmiIndices[i] = i;
410         }
411       else
412         iUsage = DIB_RGB_COLORS;
413     }
414
415   if ((memdc = CreateCompatibleDC (hdc)) == NULL)
416     {
417       WIN32_GDI_FAILED ("CreateCompatibleDC");
418       if (GDK_IS_PIXMAP (window))
419         {
420           SelectObject (hdc, oldbitmap1);
421           DeleteDC (hdc);
422         }
423       else
424         {
425           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
426         }
427       g_free (image);
428       return NULL;
429     }
430
431   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
432   bmi.bmiHeader.biWidth = width;
433   bmi.bmiHeader.biHeight = -height;
434   bmi.bmiHeader.biPlanes = 1;
435   bmi.bmiHeader.biBitCount = image->depth;
436   if (image->depth == 16)
437     {
438       bmi.bmiHeader.biCompression = BI_BITFIELDS;
439       if (image->visual == NULL)
440         {
441           /* XXX ??? Is it always this if depth==16 and a pixmap? Guess so. */
442           bmi.u.bmiMasks[0] = 0xf800;
443           bmi.u.bmiMasks[1] = 0x07e0;
444           bmi.u.bmiMasks[2] = 0x001f;
445         }
446       else
447         {
448           bmi.u.bmiMasks[0] = image->visual->red_mask;
449           bmi.u.bmiMasks[1] = image->visual->green_mask;
450           bmi.u.bmiMasks[2] = image->visual->blue_mask;
451         }
452     }
453   else
454     bmi.bmiHeader.biCompression = BI_RGB;
455   bmi.bmiHeader.biSizeImage = 0;
456   bmi.bmiHeader.biXPelsPerMeter =
457     bmi.bmiHeader.biYPelsPerMeter = 0;
458   bmi.bmiHeader.biClrUsed = 0;
459   bmi.bmiHeader.biClrImportant = 0;
460
461   if ((private->hbitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bmi, iUsage,
462                                             &image->mem, NULL, 0)) == NULL)
463     {
464       WIN32_GDI_FAILED ("CreateDIBSection");
465       DeleteDC (memdc);
466       if (GDK_IS_PIXMAP (window))
467         {
468           SelectObject (hdc, oldbitmap1);
469           DeleteDC (hdc);
470         }
471       else
472         {
473           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
474         }
475       g_free (image);
476       return NULL;
477     }
478
479   if ((oldbitmap2 = SelectObject (memdc, private->hbitmap)) == NULL)
480     {
481       WIN32_GDI_FAILED ("SelectObject");
482       DeleteObject (private->hbitmap);
483       DeleteDC (memdc);
484       if (GDK_IS_PIXMAP (window))
485         {
486           SelectObject (hdc, oldbitmap1);
487           DeleteDC (hdc);
488         }
489       else
490         {
491           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
492         }
493       g_free (image);
494       return NULL;
495     }
496
497   if (!BitBlt (memdc, 0, 0, width, height, hdc, x, y, SRCCOPY))
498     {
499       WIN32_GDI_FAILED ("BitBlt");
500       SelectObject (memdc, oldbitmap2);
501       DeleteObject (private->hbitmap);
502       DeleteDC (memdc);
503       if (GDK_IS_PIXMAP (window))
504         {
505           SelectObject (hdc, oldbitmap1);
506           DeleteDC (hdc);
507         }
508       else
509         {
510           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
511         }
512       g_free (image);
513       return NULL;
514     }
515
516   if (SelectObject (memdc, oldbitmap2) == NULL)
517     WIN32_GDI_FAILED ("SelectObject");
518
519   if (!DeleteDC (memdc))
520     WIN32_GDI_FAILED ("DeleteDC");
521
522   if (GDK_IS_PIXMAP (window))
523     {
524       SelectObject (hdc, oldbitmap1);
525       DeleteDC (hdc);
526     }
527   else
528     {
529       ReleaseDC (GDK_WINDOW_HWND (window), hdc);
530     }
531
532   switch (image->depth)
533     {
534     case 1:
535     case 8:
536       image->bpp = 1;
537       break;
538     case 15:
539     case 16:
540       image->bpp = 2;
541       break;
542     case 24:
543       image->bpp = 3;
544       break;
545     case 32:
546       image->bpp = 4;
547       break;
548     default:
549       g_warning ("gdk_image_get: image->depth = %d", image->depth);
550       g_assert_not_reached ();
551     }
552   image->byte_order = GDK_LSB_FIRST;
553   if (image->depth == 1)
554     image->bpl = ((width - 1)/32 + 1)*4;
555   else
556     image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
557
558   GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
559                            private->hbitmap, image->mem, image->bpl));
560
561   return image;
562 }
563
564 guint32
565 gdk_image_get_pixel (GdkImage *image,
566                      gint      x,
567                      gint      y)
568 {
569   guint32 pixel;
570
571   g_return_val_if_fail (GDK_IS_IMAGE (image), 0);
572
573   if (!(x >= 0 && x < image->width && y >= 0 && y < image->height))
574       return 0;
575
576   if (image->depth == 1)
577     pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
578   else
579     {
580       guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
581       
582       switch (image->bpp)
583         {
584         case 1:
585           pixel = *pixelp;
586           break;
587
588         /* Windows is always LSB, no need to check image->byte_order. */
589         case 2:
590           pixel = pixelp[0] | (pixelp[1] << 8);
591           break;
592
593         case 3:
594           pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
595           break;
596
597         case 4:
598           pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
599           break;
600         }
601     }
602
603   return pixel;
604 }
605
606 void
607 gdk_image_put_pixel (GdkImage *image,
608                      gint       x,
609                      gint       y,
610                      guint32    pixel)
611 {
612   g_return_if_fail (image != NULL);
613
614   if  (!(x >= 0 && x < image->width && y >= 0 && y < image->height))
615     return;
616
617   if (image->depth == 1)
618     if (pixel & 1)
619       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
620     else
621       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
622   else
623     {
624       guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
625       
626       /* Windows is always LSB, no need to check image->byte_order. */
627       switch (image->bpp)
628         {
629         case 4:
630           pixelp[3] = 0;
631         case 3:
632           pixelp[2] = ((pixel >> 16) & 0xFF);
633         case 2:
634           pixelp[1] = ((pixel >> 8) & 0xFF);
635         case 1:
636           pixelp[0] = (pixel & 0xFF);
637         }
638     }
639 }
640
641 static void
642 gdk_win32_image_destroy (GdkImage *image)
643 {
644   GdkImagePrivateWin32 *private;
645
646   g_return_if_fail (GDK_IS_IMAGE (image));
647
648   private = PRIVATE_DATA (image);
649
650   if (private == NULL) /* This means that gdk_image_exit() destroyed the
651                         * image already, and now we're called a second
652                         * time from _finalize()
653                         */
654     return;
655   
656   GDK_NOTE (MISC, g_print ("gdk_win32_image_destroy: %#x%s\n",
657                            private->hbitmap,
658                            (image->type == GDK_IMAGE_SHARED_PIXMAP ?
659                             " (shared pixmap)" : "")));
660   
661   switch (image->type)
662     {
663     case GDK_IMAGE_SHARED_PIXMAP:
664       break;                    /* The Windows bitmap has already been
665                                  * (or will be) deleted when freeing
666                                  * the corresponding pixmap.
667                                  */
668
669     case GDK_IMAGE_SHARED:
670       if (!DeleteObject (private->hbitmap))
671         WIN32_GDI_FAILED ("DeleteObject");
672       break;
673
674     default:
675       g_assert_not_reached ();
676     }
677
678   g_free (private);
679   image->windowing_data = NULL;
680 }
681