]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkpixmap-win32.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / gdk / win32 / gdkpixmap-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2002 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include <config.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "gdkpixmap.h"
34 #include "gdkdisplay.h"
35
36 #include "gdkprivate-win32.h"
37
38 static void gdk_pixmap_impl_win32_get_size   (GdkDrawable        *drawable,
39                                               gint               *width,
40                                               gint               *height);
41
42 static void gdk_pixmap_impl_win32_init       (GdkPixmapImplWin32      *pixmap);
43 static void gdk_pixmap_impl_win32_class_init (GdkPixmapImplWin32Class *klass);
44 static void gdk_pixmap_impl_win32_finalize   (GObject                 *object);
45
46 static gpointer parent_class = NULL;
47
48 GType
49 _gdk_pixmap_impl_win32_get_type (void)
50 {
51   static GType object_type = 0;
52
53   if (!object_type)
54     {
55       static const GTypeInfo object_info =
56       {
57         sizeof (GdkPixmapImplWin32Class),
58         (GBaseInitFunc) NULL,
59         (GBaseFinalizeFunc) NULL,
60         (GClassInitFunc) gdk_pixmap_impl_win32_class_init,
61         NULL,           /* class_finalize */
62         NULL,           /* class_data */
63         sizeof (GdkPixmapImplWin32),
64         0,              /* n_preallocs */
65         (GInstanceInitFunc) gdk_pixmap_impl_win32_init,
66       };
67       
68       object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_WIN32,
69                                             "GdkPixmapImplWin32",
70                                             &object_info, 0);
71     }
72   
73   return object_type;
74 }
75
76 GType
77 _gdk_pixmap_impl_get_type (void)
78 {
79   return _gdk_pixmap_impl_win32_get_type ();
80 }
81
82 static void
83 gdk_pixmap_impl_win32_init (GdkPixmapImplWin32 *impl)
84 {
85   impl->width = 1;
86   impl->height = 1;
87 }
88
89 static void
90 gdk_pixmap_impl_win32_class_init (GdkPixmapImplWin32Class *klass)
91 {
92   GObjectClass *object_class = G_OBJECT_CLASS (klass);
93   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
94   
95   parent_class = g_type_class_peek_parent (klass);
96
97   object_class->finalize = gdk_pixmap_impl_win32_finalize;
98
99   drawable_class->get_size = gdk_pixmap_impl_win32_get_size;
100 }
101
102 static void
103 gdk_pixmap_impl_win32_finalize (GObject *object)
104 {
105   GdkPixmapImplWin32 *impl = GDK_PIXMAP_IMPL_WIN32 (object);
106   GdkPixmap *wrapper = GDK_PIXMAP (GDK_DRAWABLE_IMPL_WIN32 (impl)->wrapper);
107
108   GDK_NOTE (PIXMAP, g_print ("gdk_pixmap_impl_win32_finalize: %p\n",
109                              GDK_PIXMAP_HBITMAP (wrapper)));
110
111   if (!DeleteObject (GDK_PIXMAP_HBITMAP (wrapper)))
112     WIN32_GDI_FAILED ("DeleteObject");
113
114   gdk_win32_handle_table_remove (GDK_PIXMAP_HBITMAP (wrapper));
115
116   G_OBJECT_CLASS (parent_class)->finalize (object);
117 }
118
119 static void
120 gdk_pixmap_impl_win32_get_size (GdkDrawable *drawable,
121                                 gint        *width,
122                                 gint        *height)
123 {
124   if (width)
125     *width = GDK_PIXMAP_IMPL_WIN32 (drawable)->width;
126   if (height)
127     *height = GDK_PIXMAP_IMPL_WIN32 (drawable)->height;
128 }
129
130 GdkPixmap*
131 gdk_pixmap_new (GdkDrawable *drawable,
132                 gint         width,
133                 gint         height,
134                 gint         depth)
135 {
136   struct {
137     BITMAPINFOHEADER bmiHeader;
138     union {
139       WORD bmiIndices[256];
140       DWORD bmiMasks[3];
141       RGBQUAD bmiColors[256];
142     } u;
143   } bmi;
144   UINT iUsage;
145   HDC hdc;
146   HWND hwnd;
147   HPALETTE holdpal = NULL;
148   HBITMAP hbitmap;
149   GdkPixmap *pixmap;
150   GdkDrawableImplWin32 *drawable_impl;
151   GdkPixmapImplWin32 *pixmap_impl;
152   GdkColormap *cmap;
153   guchar *bits;
154   gint i;
155   gint window_depth;
156
157   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
158   g_return_val_if_fail ((drawable != NULL) || (depth != -1), NULL);
159   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
160
161   if (!drawable)
162     drawable = _gdk_parent_root;
163
164   if (GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
165     return NULL;
166
167   window_depth = gdk_drawable_get_depth (GDK_DRAWABLE (drawable));
168   if (depth == -1)
169     depth = window_depth;
170
171   GDK_NOTE (PIXMAP, g_print ("gdk_pixmap_new: %dx%dx%d drawable=%p\n",
172                              width, height, depth, drawable));
173
174   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
175   drawable_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
176   pixmap_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
177   drawable_impl->wrapper = GDK_DRAWABLE (pixmap);
178   
179   pixmap_impl->is_foreign = FALSE;
180   pixmap_impl->width = width;
181   pixmap_impl->height = height;
182   GDK_PIXMAP_OBJECT (pixmap)->depth = depth;
183
184   if (depth == window_depth)
185     {
186       cmap = gdk_drawable_get_colormap (drawable);
187       if (cmap)
188         gdk_drawable_set_colormap (pixmap, cmap);
189     }
190   
191   if (GDK_IS_WINDOW (drawable))
192     hwnd = GDK_WINDOW_HWND (drawable);
193   else
194     hwnd = GDK_WINDOW_HWND (_gdk_parent_root);
195   if ((hdc = GetDC (hwnd)) == NULL)
196     {
197       WIN32_GDI_FAILED ("GetDC");
198       g_object_unref ((GObject *) pixmap);
199       return NULL;
200     }
201
202   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
203   bmi.bmiHeader.biWidth = width;
204   bmi.bmiHeader.biHeight = -height;
205   bmi.bmiHeader.biPlanes = 1;
206   switch (depth)
207     {
208     case 1:
209     case 24:
210     case 32:
211       bmi.bmiHeader.biBitCount = depth;
212       break;
213
214     case 4:
215       bmi.bmiHeader.biBitCount = 4;
216       break;
217       
218     case 5:
219     case 6:
220     case 7:
221     case 8:
222       bmi.bmiHeader.biBitCount = 8;
223       break;
224       
225     case 15:
226     case 16:
227       bmi.bmiHeader.biBitCount = 16;
228       break;
229
230     default:
231       g_warning ("gdk_win32_pixmap_new: depth = %d", depth);
232       g_assert_not_reached ();
233     }
234
235   if (bmi.bmiHeader.biBitCount == 16)
236     bmi.bmiHeader.biCompression = BI_BITFIELDS;
237   else
238     bmi.bmiHeader.biCompression = BI_RGB;
239
240   bmi.bmiHeader.biSizeImage = 0;
241   bmi.bmiHeader.biXPelsPerMeter =
242     bmi.bmiHeader.biYPelsPerMeter = 0;
243   bmi.bmiHeader.biClrUsed = 0;
244   bmi.bmiHeader.biClrImportant = 0;
245
246   iUsage = DIB_RGB_COLORS;
247   if (depth == 1)
248     {
249       bmi.u.bmiColors[0].rgbBlue =
250         bmi.u.bmiColors[0].rgbGreen =
251         bmi.u.bmiColors[0].rgbRed = 0x00;
252       bmi.u.bmiColors[0].rgbReserved = 0x00;
253
254       bmi.u.bmiColors[1].rgbBlue =
255         bmi.u.bmiColors[1].rgbGreen =
256         bmi.u.bmiColors[1].rgbRed = 0xFF;
257       bmi.u.bmiColors[1].rgbReserved = 0x00;
258     }
259   else
260     {
261       if (depth <= 8 && drawable_impl->colormap != NULL)
262         {
263           GdkColormapPrivateWin32 *cmapp =
264             GDK_WIN32_COLORMAP_DATA (drawable_impl->colormap);
265           gint k;
266
267           if ((holdpal = SelectPalette (hdc, cmapp->hpal, FALSE)) == NULL)
268             WIN32_GDI_FAILED ("SelectPalette");
269           else if ((k = RealizePalette (hdc)) == GDI_ERROR)
270             WIN32_GDI_FAILED ("RealizePalette");
271           else if (k > 0)
272             GDK_NOTE (PIXMAP_OR_COLORMAP, g_print ("_gdk_win32_pixmap_new: realized %p: %d colors\n",
273                                                    cmapp->hpal, k));
274
275           iUsage = DIB_PAL_COLORS;
276           for (i = 0; i < 256; i++)
277             bmi.u.bmiIndices[i] = i;
278         }
279       else if (bmi.bmiHeader.biBitCount == 16)
280         {
281           GdkVisual *visual = gdk_visual_get_system ();
282
283           bmi.u.bmiMasks[0] = visual->red_mask;
284           bmi.u.bmiMasks[1] = visual->green_mask;
285           bmi.u.bmiMasks[2] = visual->blue_mask;
286         }
287     }
288
289   hbitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
290                               iUsage, (PVOID *) &bits, NULL, 0);
291   if (holdpal != NULL)
292     SelectPalette (hdc, holdpal, FALSE);
293
294   if (!ReleaseDC (hwnd, hdc))
295     WIN32_GDI_FAILED ("ReleaseDC");
296
297   GDK_NOTE (PIXMAP, g_print ("...=%p bits=%p pixmap=%p\n", hbitmap, bits, pixmap));
298
299   if (hbitmap == NULL)
300     {
301       WIN32_GDI_FAILED ("CreateDIBSection");
302       g_object_unref ((GObject *) pixmap);
303       return NULL;
304     }
305
306   drawable_impl->handle = hbitmap;
307   /* initialize */
308   memset (bits, 0, (bmi.bmiHeader.biBitCount * width * height) / 8);
309   pixmap_impl->bits = bits;
310
311   gdk_win32_handle_table_insert (&GDK_PIXMAP_HBITMAP (pixmap), pixmap);
312
313   return pixmap;
314 }
315
316 static unsigned char mirror[256] = {
317   0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
318   0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
319   0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
320   0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
321   0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
322   0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
323   0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
324   0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
325   0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
326   0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
327   0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
328   0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
329   0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
330   0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
331   0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
332   0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
333   0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
334   0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
335   0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
336   0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
337   0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
338   0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
339   0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
340   0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
341   0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
342   0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
343   0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
344   0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
345   0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
346   0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
347   0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
348   0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
349 };
350
351 GdkPixmap *
352 gdk_bitmap_create_from_data (GdkDrawable *drawable,
353                              const gchar *data,
354                              gint         width,
355                              gint         height)
356 {
357   GdkPixmap *pixmap;
358   GdkPixmapImplWin32 *pixmap_impl;
359   gint i, j, data_bpl, pixmap_bpl;
360   guchar *bits;
361
362   g_return_val_if_fail (data != NULL, NULL);
363   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
364   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
365
366   if (!drawable)
367     drawable = _gdk_parent_root;
368
369   if (GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
370     return NULL;
371
372   pixmap = gdk_pixmap_new (drawable, width, height, 1);
373
374   if (pixmap == NULL)
375     return NULL;
376
377   pixmap_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
378   bits = pixmap_impl->bits;
379   data_bpl = ((width - 1) / 8 + 1);
380   pixmap_bpl = ((width - 1)/32 + 1)*4;
381
382   for (i = 0; i < height; i++)
383     for (j = 0; j < data_bpl; j++)
384       bits[i*pixmap_bpl + j] = mirror[(guchar) data[i*data_bpl + j]];
385
386   GDK_NOTE (PIXMAP, g_print ("gdk_bitmap_create_from_data: %dx%d=%p\n",
387                              width, height, GDK_PIXMAP_HBITMAP (pixmap)));
388
389   return pixmap;
390 }
391
392 GdkPixmap*
393 gdk_pixmap_create_from_data (GdkDrawable    *drawable,
394                              const gchar    *data,
395                              gint            width,
396                              gint            height,
397                              gint            depth,
398                              const GdkColor *fg,
399                              const GdkColor *bg)
400 {
401   /* Oh wow. I struggled with dozens of lines of code trying to get
402    * this right using a monochrome Win32 bitmap created from data, and
403    * a colour DIB section as the result, trying setting pens,
404    * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
405    * realized it's much easier to do it using gdk...:
406    */
407
408   GdkPixmap *result;
409   GdkPixmap *source;
410   GdkGC *gc;
411
412   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
413   g_return_val_if_fail (data != NULL, NULL);
414   g_return_val_if_fail (fg != NULL, NULL);
415   g_return_val_if_fail (bg != NULL, NULL);
416   g_return_val_if_fail ((drawable != NULL) || (depth != -1), NULL);
417   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
418
419   if (GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
420     return NULL;
421
422   result = gdk_pixmap_new (drawable, width, height, depth);
423   source = gdk_bitmap_create_from_data (drawable, data, width, height);
424   gc = gdk_gc_new (result);
425
426   gdk_gc_set_foreground (gc, fg);
427   gdk_gc_set_background (gc, bg);
428   _gdk_win32_blit
429     (TRUE,
430      GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (result)->impl),
431      gc, source, 0, 0, 0, 0, width, height);
432   g_object_unref (source);
433   gdk_gc_unref (gc);
434
435   GDK_NOTE (PIXMAP, g_print ("gdk_pixmap_create_from_data: %dx%dx%d=%p\n",
436                              width, height, depth,
437                              GDK_PIXMAP_HBITMAP (result)));
438
439   return result;
440 }
441
442 GdkPixmap *
443 gdk_pixmap_foreign_new_for_display (GdkDisplay      *display,
444                                     GdkNativeWindow  anid)
445 {
446   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
447   g_return_val_if_fail (display == _gdk_display, NULL);
448
449   return gdk_pixmap_foreign_new (anid);
450 }
451
452 GdkPixmap*
453 gdk_pixmap_foreign_new (GdkNativeWindow anid)
454 {
455   GdkPixmap *pixmap;
456   GdkDrawableImplWin32 *draw_impl;
457   GdkPixmapImplWin32 *pix_impl;
458   HBITMAP hbitmap;
459   SIZE size;
460
461   /* Check to make sure we were passed a HBITMAP */
462   g_return_val_if_fail (GetObjectType ((HGDIOBJ) anid) == OBJ_BITMAP, NULL);
463
464   hbitmap = (HBITMAP) anid;
465
466   /* Get information about the bitmap to fill in the structure for the
467    * GDK window.
468    */
469   GetBitmapDimensionEx (hbitmap, &size);
470
471   /* Allocate a new GDK pixmap */
472   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
473   draw_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
474   pix_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
475   draw_impl->wrapper = GDK_DRAWABLE (pixmap);
476   
477   draw_impl->handle = hbitmap;
478   draw_impl->colormap = NULL;
479   pix_impl->width = size.cx;
480   pix_impl->height = size.cy;
481   pix_impl->bits = NULL;
482
483   gdk_win32_handle_table_insert (&GDK_PIXMAP_HBITMAP (pixmap), pixmap);
484
485   return pixmap;
486 }
487
488 GdkPixmap*
489 gdk_pixmap_lookup (GdkNativeWindow anid)
490 {
491   return (GdkPixmap*) gdk_win32_handle_table_lookup (anid);
492 }
493
494 GdkPixmap*
495 gdk_pixmap_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid)
496 {
497   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
498   g_return_val_if_fail (display == _gdk_display, NULL);
499
500   return gdk_pixmap_lookup (anid);
501 }