]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkpixmap-win32.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~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-1999 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
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33
34 #include "gdkpixmap.h"
35 #include "gdkinternals.h"
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);
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 (MISC, g_print ("gdk_pixmap_impl_win32_finalize: %#x\n",
109                            GDK_PIXMAP_HBITMAP (object)));
110
111   if (!DeleteObject (GDK_PIXMAP_HBITMAP (object)))
112     WIN32_GDI_FAILED ("DeleteObject");
113
114   gdk_win32_handle_table_remove (GDK_PIXMAP_HBITMAP (object));
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 (GdkWindow *window,
132                 gint       width,
133                 gint       height,
134                 gint       depth)
135 {
136   GdkPixmap *pixmap;
137   GdkDrawableImplWin32 *draw_impl;
138   GdkPixmapImplWin32 *pix_impl;
139   GdkVisual *visual;
140
141   struct {
142     BITMAPINFOHEADER bmiHeader;
143     union {
144       WORD bmiIndices[256];
145       DWORD bmiMasks[3];
146       RGBQUAD bmiColors[256];
147     } u;
148   } bmi;
149   UINT iUsage;
150   HDC hdc;
151
152   guchar *bits;
153   gint i;
154
155   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
156   g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
157 #if 1
158   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
159 #else
160   /* HB: Not The Right Thing to do, but a nice way to debug
161    * the backing store facility without immediate crashes ...
162    */
163   if (width == 0 || height == 0)
164     {
165       g_warning("gdk_pixmap_new: size requested: %ld %ld", width, height);
166       /* testing: where does it crash next? */
167       if (width == 0) width = 1;
168       if (height == 0) height = 1;
169     }
170 #endif
171
172   if (!window)
173     window = gdk_parent_root;
174
175   if (GDK_WINDOW_DESTROYED (window))
176     return NULL;
177
178   visual = gdk_drawable_get_visual (window);
179
180   if (depth == -1)
181     depth = visual->depth;
182
183   GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n",
184                            width, height, depth));
185
186   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
187   draw_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
188   pix_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
189   draw_impl->wrapper = GDK_DRAWABLE (pixmap);
190   
191   pix_impl->is_foreign = FALSE;
192   pix_impl->width = width;
193   pix_impl->height = height;
194   GDK_PIXMAP_OBJECT (pixmap)->depth = depth;
195
196   if ((hdc = GetDC (GDK_WINDOW_HWND (window))) == NULL)
197     {
198       WIN32_GDI_FAILED ("GetDC");
199       g_object_unref ((GObject *) pixmap);
200       return NULL;
201     }
202
203   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
204   bmi.bmiHeader.biWidth = width;
205   bmi.bmiHeader.biHeight = -height;
206   bmi.bmiHeader.biPlanes = 1;
207   if (depth == 15)
208     bmi.bmiHeader.biBitCount = 16;
209   else
210     bmi.bmiHeader.biBitCount = depth;
211   if (depth == 16)
212     bmi.bmiHeader.biCompression = BI_BITFIELDS;
213   else
214     bmi.bmiHeader.biCompression = BI_RGB;
215   bmi.bmiHeader.biSizeImage = 0;
216   bmi.bmiHeader.biXPelsPerMeter =
217     bmi.bmiHeader.biYPelsPerMeter = 0;
218   bmi.bmiHeader.biClrUsed = 0;
219   bmi.bmiHeader.biClrImportant = 0;
220
221   iUsage = DIB_RGB_COLORS;
222   if (depth == 1)
223     {
224       bmi.u.bmiColors[0].rgbBlue =
225         bmi.u.bmiColors[0].rgbGreen =
226         bmi.u.bmiColors[0].rgbRed = 0x00;
227       bmi.u.bmiColors[0].rgbReserved = 0x00;
228
229       bmi.u.bmiColors[1].rgbBlue =
230         bmi.u.bmiColors[1].rgbGreen =
231         bmi.u.bmiColors[1].rgbRed = 0xFF;
232       bmi.u.bmiColors[1].rgbReserved = 0x00;
233       draw_impl->colormap = NULL;
234     }
235   else
236     {
237       draw_impl->colormap = GDK_DRAWABLE_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl)->colormap;
238       if (draw_impl->colormap == NULL)
239         draw_impl->colormap = gdk_colormap_get_system ();
240
241       if (depth == 8)
242         {
243           iUsage = DIB_PAL_COLORS;
244           for (i = 0; i < 256; i++)
245             bmi.u.bmiIndices[i] = i;
246         }
247       else
248         {
249           if (depth != visual->depth)
250             g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d",
251                        depth, visual->depth);
252           if (depth == 16)
253             {
254               bmi.u.bmiMasks[0] = visual->red_mask;
255               bmi.u.bmiMasks[1] = visual->green_mask;
256               bmi.u.bmiMasks[2] = visual->blue_mask;
257             }
258         }
259     }
260   if ((draw_impl->handle = CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
261                                              iUsage, (PVOID *) &bits,
262                                              NULL, 0)) == NULL)
263     {
264       WIN32_GDI_FAILED ("CreateDIBSection");
265       ReleaseDC (GDK_WINDOW_HWND (window), hdc);
266       g_object_unref ((GObject *) pixmap);
267       return NULL;
268     }
269   ReleaseDC (GDK_WINDOW_HWND (window), hdc);
270
271   GDK_NOTE (MISC, g_print ("... = %#x\n", GDK_PIXMAP_HBITMAP (pixmap)));
272
273   gdk_win32_handle_table_insert (GDK_PIXMAP_HBITMAP (pixmap), pixmap);
274
275   return pixmap;
276 }
277
278 static unsigned char mirror[256] = {
279   0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
280   0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
281   0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
282   0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
283   0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
284   0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
285   0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
286   0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
287   0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
288   0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
289   0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
290   0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
291   0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
292   0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
293   0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
294   0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
295   0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
296   0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
297   0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
298   0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
299   0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
300   0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
301   0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
302   0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
303   0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
304   0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
305   0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
306   0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
307   0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
308   0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
309   0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
310   0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
311 };
312
313 GdkPixmap *
314 gdk_bitmap_create_from_data (GdkWindow   *window,
315                              const gchar *data,
316                              gint         width,
317                              gint         height)
318 {
319   GdkPixmap *pixmap;
320   GdkDrawableImplWin32 *draw_impl;
321   GdkPixmapImplWin32 *pix_impl;
322   gint i, j, bpl, aligned_bpl;
323   guchar *bits;
324
325   g_return_val_if_fail (data != NULL, NULL);
326   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
327   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
328
329   if (!window)
330     window = gdk_parent_root;
331
332   if (GDK_WINDOW_DESTROYED (window))
333     return NULL;
334
335   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
336   draw_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
337   pix_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
338   draw_impl->wrapper = GDK_DRAWABLE (pixmap);
339
340   pix_impl->is_foreign = FALSE;
341   pix_impl->width = width;
342   pix_impl->height = height;
343   GDK_PIXMAP_OBJECT (pixmap)->depth = 1;
344
345   bpl = ((width - 1) / 8 + 1);
346   aligned_bpl = ((bpl - 1) / 2 + 1) * 2;
347   bits = g_malloc (aligned_bpl * height);
348   for (i = 0; i < height; i++)
349     for (j = 0; j < bpl; j++)
350       bits[i*aligned_bpl + j] = mirror[(guchar) data[i*bpl + j]];
351
352   draw_impl->handle = CreateBitmap (width, height, 1, 1, bits);
353
354   GDK_NOTE (MISC, g_print ("gdk_bitmap_create_from_data: %dx%d = %#x\n",
355                            width, height, GDK_PIXMAP_HBITMAP (pixmap)));
356
357   g_free (bits);
358
359   draw_impl->colormap = NULL;
360   gdk_win32_handle_table_insert (GDK_PIXMAP_HBITMAP (pixmap), pixmap);
361
362   return pixmap;
363 }
364
365 GdkPixmap*
366 gdk_pixmap_create_from_data (GdkWindow   *window,
367                              const gchar *data,
368                              gint         width,
369                              gint         height,
370                              gint         depth,
371                              GdkColor    *fg,
372                              GdkColor    *bg)
373 {
374   /* Oh wow. I struggled with dozens of lines of code trying to get
375    * this right using a monochrome Win32 bitmap created from data, and
376    * a colour DIB section as the result, trying setting pens,
377    * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
378    * realized it's much easier to do it using gdk...:
379    */
380
381   GdkPixmap *result = gdk_pixmap_new (window, width, height, depth);
382   GdkPixmap *source = gdk_bitmap_create_from_data (window, data, width, height);
383   GdkGC *gc = gdk_gc_new (result);
384   gdk_gc_set_foreground (gc, fg);
385   gdk_gc_set_background (gc, bg);
386   gdk_draw_drawable (result, gc, source, 0, 0, 0, 0, width, height);
387   gdk_drawable_unref (source);
388   gdk_gc_unref (gc);
389
390   GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n",
391                            width, height, depth,
392                            GDK_PIXMAP_HBITMAP (result)));
393
394   return result;
395 }
396
397 GdkPixmap*
398 gdk_pixmap_foreign_new (GdkNativeWindow anid)
399 {
400   GdkPixmap *pixmap;
401   GdkDrawableImplWin32 *draw_impl;
402   GdkPixmapImplWin32 *pix_impl;
403   HBITMAP hbitmap;
404   SIZE size;
405   unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
406
407   /* check to make sure we were passed a HBITMAP */
408   g_return_val_if_fail(GetObjectType ((HGDIOBJ) anid) == OBJ_BITMAP, NULL);
409
410   /* set the pixmap to the passed in value */
411   hbitmap = (HBITMAP) anid;
412
413   /* get information about the bitmap to fill in the structure for
414      the gdk window */
415   GetBitmapDimensionEx (hbitmap, &size);
416   w_ret = size.cx;
417   h_ret = size.cy;
418
419   /* allocate a new gdk pixmap */
420   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
421   draw_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
422   pix_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
423   draw_impl->wrapper = GDK_DRAWABLE (pixmap);
424   
425   draw_impl->handle = hbitmap;
426   draw_impl->colormap = NULL;
427   pix_impl->width = w_ret;
428   pix_impl->height = h_ret;
429
430   gdk_win32_handle_table_insert (GDK_PIXMAP_HBITMAP (pixmap), pixmap);
431
432   return pixmap;
433 }