]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkpixmap-win32.c
f23d42b5bbaf5c69250432562f1df5e2ff3db0a5
[~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 <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #include "gdkpixmap.h"
33 #include "gdkprivate-win32.h"
34
35 static void gdk_pixmap_impl_win32_get_size   (GdkDrawable        *drawable,
36                                               gint               *width,
37                                               gint               *height);
38
39 static void gdk_pixmap_impl_win32_init       (GdkPixmapImplWin32      *pixmap);
40 static void gdk_pixmap_impl_win32_class_init (GdkPixmapImplWin32Class *klass);
41 static void gdk_pixmap_impl_win32_finalize   (GObject                 *object);
42
43 static gpointer parent_class = NULL;
44
45 GType
46 _gdk_pixmap_impl_win32_get_type (void)
47 {
48   static GType object_type = 0;
49
50   if (!object_type)
51     {
52       static const GTypeInfo object_info =
53       {
54         sizeof (GdkPixmapImplWin32Class),
55         (GBaseInitFunc) NULL,
56         (GBaseFinalizeFunc) NULL,
57         (GClassInitFunc) gdk_pixmap_impl_win32_class_init,
58         NULL,           /* class_finalize */
59         NULL,           /* class_data */
60         sizeof (GdkPixmapImplWin32),
61         0,              /* n_preallocs */
62         (GInstanceInitFunc) gdk_pixmap_impl_win32_init,
63       };
64       
65       object_type = g_type_register_static (GDK_TYPE_DRAWABLE_IMPL_WIN32,
66                                             "GdkPixmapImplWin32",
67                                             &object_info, 0);
68     }
69   
70   return object_type;
71 }
72
73 GType
74 _gdk_pixmap_impl_get_type (void)
75 {
76   return _gdk_pixmap_impl_win32_get_type ();
77 }
78
79 static void
80 gdk_pixmap_impl_win32_init (GdkPixmapImplWin32 *impl)
81 {
82   impl->width = 1;
83   impl->height = 1;
84 }
85
86 static void
87 gdk_pixmap_impl_win32_class_init (GdkPixmapImplWin32Class *klass)
88 {
89   GObjectClass *object_class = G_OBJECT_CLASS (klass);
90   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
91   
92   parent_class = g_type_class_peek_parent (klass);
93
94   object_class->finalize = gdk_pixmap_impl_win32_finalize;
95
96   drawable_class->get_size = gdk_pixmap_impl_win32_get_size;
97 }
98
99 static void
100 gdk_pixmap_impl_win32_finalize (GObject *object)
101 {
102   GdkPixmapImplWin32 *impl = GDK_PIXMAP_IMPL_WIN32 (object);
103   GdkPixmap *wrapper = GDK_PIXMAP (GDK_DRAWABLE_IMPL_WIN32 (impl)->wrapper);
104
105   GDK_NOTE (MISC, g_print ("gdk_pixmap_impl_win32_finalize: %#x\n",
106                            (guint) GDK_PIXMAP_HBITMAP (wrapper)));
107
108   if (!DeleteObject (GDK_PIXMAP_HBITMAP (wrapper)))
109     WIN32_GDI_FAILED ("DeleteObject");
110
111   gdk_win32_handle_table_remove (GDK_PIXMAP_HBITMAP (wrapper));
112
113   G_OBJECT_CLASS (parent_class)->finalize (object);
114 }
115
116 static void
117 gdk_pixmap_impl_win32_get_size (GdkDrawable *drawable,
118                                 gint        *width,
119                                 gint        *height)
120 {
121   if (width)
122     *width = GDK_PIXMAP_IMPL_WIN32 (drawable)->width;
123   if (height)
124     *height = GDK_PIXMAP_IMPL_WIN32 (drawable)->height;
125 }
126
127 GdkPixmap*
128 gdk_pixmap_new (GdkWindow *window,
129                 gint       width,
130                 gint       height,
131                 gint       depth)
132 {
133   GdkPixmap *pixmap;
134   GdkDrawableImplWin32 *draw_impl;
135   GdkPixmapImplWin32 *pix_impl;
136   GdkVisual *visual;
137
138   struct {
139     BITMAPINFOHEADER bmiHeader;
140     union {
141       WORD bmiIndices[256];
142       DWORD bmiMasks[3];
143       RGBQUAD bmiColors[256];
144     } u;
145   } bmi;
146   UINT iUsage;
147   HDC hdc;
148
149   guchar *bits;
150   gint i;
151
152   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
153   g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
154 #if 1
155   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
156 #else
157   /* HB: Not The Right Thing to do, but a nice way to debug
158    * the backing store facility without immediate crashes ...
159    */
160   if (width == 0 || height == 0)
161     {
162       g_warning("gdk_pixmap_new: size requested: %ld %ld", width, height);
163       /* testing: where does it crash next? */
164       if (width == 0) width = 1;
165       if (height == 0) height = 1;
166     }
167 #endif
168
169   if (!window)
170     window = _gdk_parent_root;
171
172   if (GDK_WINDOW_DESTROYED (window))
173     return NULL;
174
175   visual = gdk_drawable_get_visual (window);
176
177   if (depth == -1)
178     depth = gdk_drawable_get_depth (GDK_DRAWABLE (window));
179
180   GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n",
181                            width, height, depth));
182
183   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
184   draw_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
185   pix_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
186   draw_impl->wrapper = GDK_DRAWABLE (pixmap);
187   
188   pix_impl->is_foreign = FALSE;
189   pix_impl->width = width;
190   pix_impl->height = height;
191   GDK_PIXMAP_OBJECT (pixmap)->depth = depth;
192
193   if ((hdc = GetDC (GDK_WINDOW_HWND (window))) == NULL)
194     {
195       WIN32_GDI_FAILED ("GetDC");
196       g_object_unref ((GObject *) pixmap);
197       return NULL;
198     }
199
200   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
201   bmi.bmiHeader.biWidth = width;
202   bmi.bmiHeader.biHeight = -height;
203   bmi.bmiHeader.biPlanes = 1;
204   if (depth == 15)
205     bmi.bmiHeader.biBitCount = 16;
206   else
207     bmi.bmiHeader.biBitCount = depth;
208   if (depth == 16)
209     bmi.bmiHeader.biCompression = BI_BITFIELDS;
210   else
211     bmi.bmiHeader.biCompression = BI_RGB;
212   bmi.bmiHeader.biSizeImage = 0;
213   bmi.bmiHeader.biXPelsPerMeter =
214     bmi.bmiHeader.biYPelsPerMeter = 0;
215   bmi.bmiHeader.biClrUsed = 0;
216   bmi.bmiHeader.biClrImportant = 0;
217
218   iUsage = DIB_RGB_COLORS;
219   if (depth == 1)
220     {
221       bmi.u.bmiColors[0].rgbBlue =
222         bmi.u.bmiColors[0].rgbGreen =
223         bmi.u.bmiColors[0].rgbRed = 0x00;
224       bmi.u.bmiColors[0].rgbReserved = 0x00;
225
226       bmi.u.bmiColors[1].rgbBlue =
227         bmi.u.bmiColors[1].rgbGreen =
228         bmi.u.bmiColors[1].rgbRed = 0xFF;
229       bmi.u.bmiColors[1].rgbReserved = 0x00;
230       draw_impl->colormap = NULL;
231       GDK_NOTE (MISC, g_print ("... colormap NULL\n"));
232     }
233   else
234     {
235       draw_impl->colormap = GDK_DRAWABLE_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl)->colormap;
236       if (draw_impl->colormap == NULL)
237         draw_impl->colormap = gdk_colormap_get_system ();
238       GDK_NOTE (MISC, g_print ("... colormap %p\n", draw_impl->colormap));
239
240       if (depth == 8)
241         {
242           iUsage = DIB_PAL_COLORS;
243           for (i = 0; i < 256; i++)
244             bmi.u.bmiIndices[i] = i;
245         }
246       else
247         {
248           if (depth != visual->depth)
249             g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d",
250                        depth, visual->depth);
251           if (depth == 16)
252             {
253               bmi.u.bmiMasks[0] = visual->red_mask;
254               bmi.u.bmiMasks[1] = visual->green_mask;
255               bmi.u.bmiMasks[2] = visual->blue_mask;
256             }
257         }
258     }
259   if ((draw_impl->handle = CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
260                                              iUsage, (PVOID *) &bits,
261                                              NULL, 0)) == NULL)
262     {
263       WIN32_GDI_FAILED ("CreateDIBSection");
264       ReleaseDC (GDK_WINDOW_HWND (window), hdc);
265       g_object_unref ((GObject *) pixmap);
266       return NULL;
267     }
268   ReleaseDC (GDK_WINDOW_HWND (window), hdc);
269
270   GDK_NOTE (MISC, g_print ("... = %#x\n",
271                            (guint) 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,
356                            (guint) GDK_PIXMAP_HBITMAP (pixmap)));
357
358   g_free (bits);
359
360   draw_impl->colormap = NULL;
361   gdk_win32_handle_table_insert (&GDK_PIXMAP_HBITMAP (pixmap), pixmap);
362
363   return pixmap;
364 }
365
366 GdkPixmap*
367 gdk_pixmap_create_from_data (GdkWindow   *window,
368                              const gchar *data,
369                              gint         width,
370                              gint         height,
371                              gint         depth,
372                              GdkColor    *fg,
373                              GdkColor    *bg)
374 {
375   /* Oh wow. I struggled with dozens of lines of code trying to get
376    * this right using a monochrome Win32 bitmap created from data, and
377    * a colour DIB section as the result, trying setting pens,
378    * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
379    * realized it's much easier to do it using gdk...:
380    */
381
382   GdkPixmap *result;
383   GdkPixmap *source;
384   GdkGC *gc;
385
386   if (GDK_WINDOW_DESTROYED (window))
387     return NULL;
388
389   result = gdk_pixmap_new (window, width, height, depth);
390   source = gdk_bitmap_create_from_data (window, data, width, height);
391   gc = gdk_gc_new (result);
392
393   gdk_gc_set_foreground (gc, fg);
394   gdk_gc_set_background (gc, bg);
395   gdk_draw_drawable (result, gc, source, 0, 0, 0, 0, width, height);
396   gdk_drawable_unref (source);
397   gdk_gc_unref (gc);
398
399   GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n",
400                            width, height, depth,
401                            (guint) GDK_PIXMAP_HBITMAP (result)));
402
403   return result;
404 }
405
406 GdkPixmap*
407 gdk_pixmap_foreign_new (GdkNativeWindow anid)
408 {
409   GdkPixmap *pixmap;
410   GdkDrawableImplWin32 *draw_impl;
411   GdkPixmapImplWin32 *pix_impl;
412   HBITMAP hbitmap;
413   SIZE size;
414   unsigned int w_ret, h_ret;
415
416   /* check to make sure we were passed a HBITMAP */
417   g_return_val_if_fail(GetObjectType ((HGDIOBJ) anid) == OBJ_BITMAP, NULL);
418
419   /* set the pixmap to the passed in value */
420   hbitmap = (HBITMAP) anid;
421
422   /* get information about the bitmap to fill in the structure for
423      the gdk window */
424   GetBitmapDimensionEx (hbitmap, &size);
425   w_ret = size.cx;
426   h_ret = size.cy;
427
428   /* allocate a new gdk pixmap */
429   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
430   draw_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
431   pix_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
432   draw_impl->wrapper = GDK_DRAWABLE (pixmap);
433   
434   draw_impl->handle = hbitmap;
435   draw_impl->colormap = NULL;
436   pix_impl->width = w_ret;
437   pix_impl->height = h_ret;
438
439   gdk_win32_handle_table_insert (&GDK_PIXMAP_HBITMAP (pixmap), pixmap);
440
441   return pixmap;
442 }