]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkimage-win32.c
gdk/gdkimage.h No need any longer on Win32 for the shared memory
[~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                             "???")));
222   
223   image = g_object_new (gdk_image_get_type (), NULL);
224   private = PRIVATE_DATA (image);
225
226   image->type = type;
227   image->visual = visual;
228   image->width = width;
229   image->height = height;
230   image->depth = visual->depth;
231   
232   xvisual = ((GdkVisualPrivate*) visual)->xvisual;
233   
234   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
235   bmi.bmiHeader.biWidth = width;
236   bmi.bmiHeader.biHeight = -height;
237   bmi.bmiHeader.biPlanes = 1;
238   if (image->depth == 15)
239     bmi.bmiHeader.biBitCount = 16;
240   else
241     bmi.bmiHeader.biBitCount = image->depth;
242   if (image->depth == 16)
243     bmi.bmiHeader.biCompression = BI_BITFIELDS;
244   else
245     bmi.bmiHeader.biCompression = BI_RGB;
246   bmi.bmiHeader.biSizeImage = 0;
247   bmi.bmiHeader.biXPelsPerMeter =
248     bmi.bmiHeader.biYPelsPerMeter = 0;
249   bmi.bmiHeader.biClrUsed = 0;
250   bmi.bmiHeader.biClrImportant = 0;
251
252   if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
253     {
254       iUsage = DIB_PAL_COLORS;
255       for (i = 0; i < 256; i++)
256         bmi.u.bmiIndices[i] = i;
257     }
258   else
259     {
260       iUsage = DIB_RGB_COLORS;
261       if (image->depth == 1)
262         {
263           bmi.u.bmiColors[0].rgbBlue = 
264             bmi.u.bmiColors[0].rgbGreen =
265             bmi.u.bmiColors[0].rgbRed = 0x00;
266           bmi.u.bmiColors[0].rgbReserved = 0x00;
267
268           bmi.u.bmiColors[1].rgbBlue = 
269             bmi.u.bmiColors[1].rgbGreen =
270             bmi.u.bmiColors[1].rgbRed = 0xFF;
271           bmi.u.bmiColors[1].rgbReserved = 0x00;
272
273         }
274       else if (image->depth == 16)
275         {
276           bmi.u.bmiMasks[0] = visual->red_mask;
277           bmi.u.bmiMasks[1] = visual->green_mask;
278           bmi.u.bmiMasks[2] = visual->blue_mask;
279         }
280     }
281
282   private->hbitmap = CreateDIBSection (gdk_display_hdc, (BITMAPINFO *) &bmi,
283                                        iUsage, &image->mem, NULL, 0);
284
285   if (private->hbitmap == NULL)
286     {
287       WIN32_GDI_FAILED ("CreateDIBSection");
288       g_free (image);
289       return NULL;
290     }
291
292   switch (image->depth)
293     {
294     case 1:
295     case 8:
296       image->bpp = 1;
297       break;
298     case 15:
299     case 16:
300       image->bpp = 2;
301       break;
302     case 24:
303       image->bpp = 3;
304       break;
305     case 32:
306       image->bpp = 4;
307       break;
308     default:
309       g_warning ("gdk_image_new: depth = %d", image->depth);
310       g_assert_not_reached ();
311     }
312   image->byte_order = GDK_LSB_FIRST;
313   if (image->depth == 1)
314     image->bpl = ((width-1)/32 + 1)*4;
315   else
316     image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
317
318   GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
319                            private->hbitmap, image->mem, image->bpl));
320
321   return image;
322 }
323
324 GdkImage*
325 gdk_image_get (GdkWindow *window,
326                gint       x,
327                gint       y,
328                gint       width,
329                gint       height)
330 {
331   GdkImage *image;
332   GdkImagePrivateWin32 *private;
333   HDC hdc, memdc;
334   struct {
335     BITMAPINFOHEADER bmiHeader;
336     union {
337       WORD bmiIndices[256];
338       DWORD bmiMasks[3];
339       RGBQUAD bmiColors[256];
340     } u;
341   } bmi;
342   HGDIOBJ oldbitmap1, oldbitmap2;
343   UINT iUsage;
344   BITMAP bm;
345   int i;
346
347   g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
348
349   if (GDK_WINDOW_DESTROYED (window))
350     return NULL;
351
352   GDK_NOTE (MISC, g_print ("gdk_image_get: %#x %dx%d@+%d+%d\n",
353                            GDK_DRAWABLE_HANDLE (window), width, height, x, y));
354
355   image = g_object_new (gdk_image_get_type (), NULL);
356   private = PRIVATE_DATA (image);
357
358   image->type = GDK_IMAGE_SHARED;
359   image->visual = gdk_drawable_get_visual (window);
360   image->width = width;
361   image->height = height;
362
363   /* This function is called both to blit from a window and from
364    * a pixmap.
365    */
366   if (GDK_IS_PIXMAP (window))
367     {
368       if ((hdc = CreateCompatibleDC (NULL)) == NULL)
369         {
370           WIN32_GDI_FAILED ("CreateCompatibleDC");
371           g_free (image);
372           return NULL;
373         }
374       if ((oldbitmap1 = SelectObject (hdc, GDK_PIXMAP_HBITMAP (window))) == NULL)
375         {
376           WIN32_GDI_FAILED ("SelectObject");
377           DeleteDC (hdc);
378           g_free (image);
379           return NULL;
380         }
381       GetObject (GDK_PIXMAP_HBITMAP (window), sizeof (BITMAP), &bm);
382       GDK_NOTE (MISC,
383                 g_print ("gdk_image_get: bmWidth = %d, bmHeight = %d, bmWidthBytes = %d, bmBitsPixel = %d\n",
384                          bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmBitsPixel));
385       image->depth = bm.bmBitsPixel;
386       if (image->depth <= 8)
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   else
396     {
397       if ((hdc = GetDC (GDK_WINDOW_HWND (window))) == NULL)
398         {
399           WIN32_GDI_FAILED ("GetDC");
400           g_free (image);
401           return NULL;
402         }
403       image->depth = gdk_visual_get_system ()->depth;
404       if (image->visual->type == GDK_VISUAL_PSEUDO_COLOR)
405         {
406           iUsage = DIB_PAL_COLORS;
407           for (i = 0; i < 256; i++)
408             bmi.u.bmiIndices[i] = i;
409         }
410       else
411         iUsage = DIB_RGB_COLORS;
412     }
413
414   if ((memdc = CreateCompatibleDC (hdc)) == NULL)
415     {
416       WIN32_GDI_FAILED ("CreateCompatibleDC");
417       if (GDK_IS_PIXMAP (window))
418         {
419           SelectObject (hdc, oldbitmap1);
420           DeleteDC (hdc);
421         }
422       else
423         {
424           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
425         }
426       g_free (image);
427       return NULL;
428     }
429
430   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
431   bmi.bmiHeader.biWidth = width;
432   bmi.bmiHeader.biHeight = -height;
433   bmi.bmiHeader.biPlanes = 1;
434   bmi.bmiHeader.biBitCount = image->depth;
435   if (image->depth == 16)
436     {
437       bmi.bmiHeader.biCompression = BI_BITFIELDS;
438       if (image->visual == NULL)
439         {
440           /* XXX ??? Is it always this if depth==16 and a pixmap? Guess so. */
441           bmi.u.bmiMasks[0] = 0xf800;
442           bmi.u.bmiMasks[1] = 0x07e0;
443           bmi.u.bmiMasks[2] = 0x001f;
444         }
445       else
446         {
447           bmi.u.bmiMasks[0] = image->visual->red_mask;
448           bmi.u.bmiMasks[1] = image->visual->green_mask;
449           bmi.u.bmiMasks[2] = image->visual->blue_mask;
450         }
451     }
452   else
453     bmi.bmiHeader.biCompression = BI_RGB;
454   bmi.bmiHeader.biSizeImage = 0;
455   bmi.bmiHeader.biXPelsPerMeter =
456     bmi.bmiHeader.biYPelsPerMeter = 0;
457   bmi.bmiHeader.biClrUsed = 0;
458   bmi.bmiHeader.biClrImportant = 0;
459
460   if ((private->hbitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bmi, iUsage,
461                                             &image->mem, NULL, 0)) == NULL)
462     {
463       WIN32_GDI_FAILED ("CreateDIBSection");
464       DeleteDC (memdc);
465       if (GDK_IS_PIXMAP (window))
466         {
467           SelectObject (hdc, oldbitmap1);
468           DeleteDC (hdc);
469         }
470       else
471         {
472           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
473         }
474       g_free (image);
475       return NULL;
476     }
477
478   if ((oldbitmap2 = SelectObject (memdc, private->hbitmap)) == NULL)
479     {
480       WIN32_GDI_FAILED ("SelectObject");
481       DeleteObject (private->hbitmap);
482       DeleteDC (memdc);
483       if (GDK_IS_PIXMAP (window))
484         {
485           SelectObject (hdc, oldbitmap1);
486           DeleteDC (hdc);
487         }
488       else
489         {
490           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
491         }
492       g_free (image);
493       return NULL;
494     }
495
496   if (!BitBlt (memdc, 0, 0, width, height, hdc, x, y, SRCCOPY))
497     {
498       WIN32_GDI_FAILED ("BitBlt");
499       SelectObject (memdc, oldbitmap2);
500       DeleteObject (private->hbitmap);
501       DeleteDC (memdc);
502       if (GDK_IS_PIXMAP (window))
503         {
504           SelectObject (hdc, oldbitmap1);
505           DeleteDC (hdc);
506         }
507       else
508         {
509           ReleaseDC (GDK_WINDOW_HWND (window), hdc);
510         }
511       g_free (image);
512       return NULL;
513     }
514
515   if (SelectObject (memdc, oldbitmap2) == NULL)
516     WIN32_GDI_FAILED ("SelectObject");
517
518   if (!DeleteDC (memdc))
519     WIN32_GDI_FAILED ("DeleteDC");
520
521   if (GDK_IS_PIXMAP (window))
522     {
523       SelectObject (hdc, oldbitmap1);
524       DeleteDC (hdc);
525     }
526   else
527     {
528       ReleaseDC (GDK_WINDOW_HWND (window), hdc);
529     }
530
531   switch (image->depth)
532     {
533     case 1:
534     case 8:
535       image->bpp = 1;
536       break;
537     case 15:
538     case 16:
539       image->bpp = 2;
540       break;
541     case 24:
542       image->bpp = 3;
543       break;
544     case 32:
545       image->bpp = 4;
546       break;
547     default:
548       g_warning ("gdk_image_get: image->depth = %d", image->depth);
549       g_assert_not_reached ();
550     }
551   image->byte_order = GDK_LSB_FIRST;
552   if (image->depth == 1)
553     image->bpl = ((width - 1)/32 + 1)*4;
554   else
555     image->bpl = ((width*image->bpp - 1)/4 + 1)*4;
556
557   GDK_NOTE (MISC, g_print ("... = %#x mem = %#x, bpl = %d\n",
558                            private->hbitmap, image->mem, image->bpl));
559
560   return image;
561 }
562
563 guint32
564 gdk_image_get_pixel (GdkImage *image,
565                      gint      x,
566                      gint      y)
567 {
568   guint32 pixel;
569
570   g_return_val_if_fail (GDK_IS_IMAGE (image), 0);
571
572   if (!(x >= 0 && x < image->width && y >= 0 && y < image->height))
573       return 0;
574
575   if (image->depth == 1)
576     pixel = (((char *) image->mem)[y * image->bpl + (x >> 3)] & (1 << (7 - (x & 0x7)))) != 0;
577   else
578     {
579       guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
580       
581       switch (image->bpp)
582         {
583         case 1:
584           pixel = *pixelp;
585           break;
586
587         /* Windows is always LSB, no need to check image->byte_order. */
588         case 2:
589           pixel = pixelp[0] | (pixelp[1] << 8);
590           break;
591
592         case 3:
593           pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
594           break;
595
596         case 4:
597           pixel = pixelp[0] | (pixelp[1] << 8) | (pixelp[2] << 16);
598           break;
599         }
600     }
601
602   return pixel;
603 }
604
605 void
606 gdk_image_put_pixel (GdkImage *image,
607                      gint       x,
608                      gint       y,
609                      guint32    pixel)
610 {
611   g_return_if_fail (image != NULL);
612
613   if  (!(x >= 0 && x < image->width && y >= 0 && y < image->height))
614     return;
615
616   if (image->depth == 1)
617     if (pixel & 1)
618       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] |= (1 << (7 - (x & 0x7)));
619     else
620       ((guchar *) image->mem)[y * image->bpl + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
621   else
622     {
623       guchar *pixelp = (guchar *) image->mem + y * image->bpl + x * image->bpp;
624       
625       /* Windows is always LSB, no need to check image->byte_order. */
626       switch (image->bpp)
627         {
628         case 4:
629           pixelp[3] = 0;
630         case 3:
631           pixelp[2] = ((pixel >> 16) & 0xFF);
632         case 2:
633           pixelp[1] = ((pixel >> 8) & 0xFF);
634         case 1:
635           pixelp[0] = (pixel & 0xFF);
636         }
637     }
638 }
639
640 static void
641 gdk_win32_image_destroy (GdkImage *image)
642 {
643   GdkImagePrivateWin32 *private;
644
645   g_return_if_fail (GDK_IS_IMAGE (image));
646
647   private = PRIVATE_DATA (image);
648
649   if (private == NULL) /* This means that gdk_image_exit() destroyed the
650                         * image already, and now we're called a second
651                         * time from _finalize()
652                         */
653     return;
654   
655   GDK_NOTE (MISC, g_print ("gdk_win32_image_destroy: %#x%s\n",
656                            private->hbitmap));
657   
658   switch (image->type)
659     {
660     case GDK_IMAGE_SHARED:
661       if (!DeleteObject (private->hbitmap))
662         WIN32_GDI_FAILED ("DeleteObject");
663       break;
664
665     default:
666       g_assert_not_reached ();
667     }
668
669   g_free (private);
670   image->windowing_data = NULL;
671 }
672