]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkpixmap-win32.c
Use cairo_set_device_offset().
[~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   _gdk_win32_drawable_finish (GDK_DRAWABLE (object));  
112
113   GDI_CALL (DeleteObject, (GDK_PIXMAP_HBITMAP (wrapper)));
114
115   gdk_win32_handle_table_remove (GDK_PIXMAP_HBITMAP (wrapper));
116
117   G_OBJECT_CLASS (parent_class)->finalize (object);
118 }
119
120 static void
121 gdk_pixmap_impl_win32_get_size (GdkDrawable *drawable,
122                                 gint        *width,
123                                 gint        *height)
124 {
125   if (width)
126     *width = GDK_PIXMAP_IMPL_WIN32 (drawable)->width;
127   if (height)
128     *height = GDK_PIXMAP_IMPL_WIN32 (drawable)->height;
129 }
130
131 GdkPixmap*
132 gdk_pixmap_new (GdkDrawable *drawable,
133                 gint         width,
134                 gint         height,
135                 gint         depth)
136 {
137   struct {
138     BITMAPINFOHEADER bmiHeader;
139     union {
140       WORD bmiIndices[256];
141       DWORD bmiMasks[3];
142       RGBQUAD bmiColors[256];
143     } u;
144   } bmi;
145   UINT iUsage;
146   HDC hdc;
147   HWND hwnd;
148   HPALETTE holdpal = NULL;
149   HBITMAP hbitmap;
150   GdkPixmap *pixmap;
151   GdkDrawableImplWin32 *drawable_impl;
152   GdkPixmapImplWin32 *pixmap_impl;
153   GdkColormap *cmap;
154   guchar *bits;
155   gint i;
156   gint window_depth;
157
158   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
159   g_return_val_if_fail ((drawable != NULL) || (depth != -1), NULL);
160   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
161
162   if (!drawable)
163     drawable = _gdk_root;
164
165   if (GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
166     return NULL;
167
168   window_depth = gdk_drawable_get_depth (GDK_DRAWABLE (drawable));
169   if (depth == -1)
170     depth = window_depth;
171
172   GDK_NOTE (PIXMAP, g_print ("gdk_pixmap_new: %dx%dx%d drawable=%p\n",
173                              width, height, depth, drawable));
174
175   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
176   drawable_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
177   pixmap_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
178   drawable_impl->wrapper = GDK_DRAWABLE (pixmap);
179   
180   pixmap_impl->is_foreign = FALSE;
181   pixmap_impl->width = width;
182   pixmap_impl->height = height;
183   GDK_PIXMAP_OBJECT (pixmap)->depth = depth;
184
185   if (depth == window_depth)
186     {
187       cmap = gdk_drawable_get_colormap (drawable);
188       if (cmap)
189         gdk_drawable_set_colormap (pixmap, cmap);
190     }
191   
192   if (GDK_IS_WINDOW (drawable))
193     hwnd = GDK_WINDOW_HWND (drawable);
194   else
195     hwnd = GetDesktopWindow ();
196   if ((hdc = GetDC (hwnd)) == 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   switch (depth)
208     {
209     case 1:
210     case 24:
211     case 32:
212       bmi.bmiHeader.biBitCount = depth;
213       break;
214
215     case 4:
216       bmi.bmiHeader.biBitCount = 4;
217       break;
218       
219     case 5:
220     case 6:
221     case 7:
222     case 8:
223       bmi.bmiHeader.biBitCount = 8;
224       break;
225       
226     case 15:
227     case 16:
228       bmi.bmiHeader.biBitCount = 16;
229       break;
230
231     default:
232       g_warning ("gdk_win32_pixmap_new: depth = %d", depth);
233       g_assert_not_reached ();
234     }
235
236   if (bmi.bmiHeader.biBitCount == 16)
237     bmi.bmiHeader.biCompression = BI_BITFIELDS;
238   else
239     bmi.bmiHeader.biCompression = BI_RGB;
240
241   bmi.bmiHeader.biSizeImage = 0;
242   bmi.bmiHeader.biXPelsPerMeter =
243     bmi.bmiHeader.biYPelsPerMeter = 0;
244   bmi.bmiHeader.biClrUsed = 0;
245   bmi.bmiHeader.biClrImportant = 0;
246
247   iUsage = DIB_RGB_COLORS;
248   if (depth == 1)
249     {
250       bmi.u.bmiColors[0].rgbBlue =
251         bmi.u.bmiColors[0].rgbGreen =
252         bmi.u.bmiColors[0].rgbRed = 0x00;
253       bmi.u.bmiColors[0].rgbReserved = 0x00;
254
255       bmi.u.bmiColors[1].rgbBlue =
256         bmi.u.bmiColors[1].rgbGreen =
257         bmi.u.bmiColors[1].rgbRed = 0xFF;
258       bmi.u.bmiColors[1].rgbReserved = 0x00;
259     }
260   else
261     {
262       if (depth <= 8 && drawable_impl->colormap != NULL)
263         {
264           GdkColormapPrivateWin32 *cmapp =
265             GDK_WIN32_COLORMAP_DATA (drawable_impl->colormap);
266           gint k;
267
268           if ((holdpal = SelectPalette (hdc, cmapp->hpal, FALSE)) == NULL)
269             WIN32_GDI_FAILED ("SelectPalette");
270           else if ((k = RealizePalette (hdc)) == GDI_ERROR)
271             WIN32_GDI_FAILED ("RealizePalette");
272           else if (k > 0)
273             GDK_NOTE (PIXMAP_OR_COLORMAP, g_print ("_gdk_win32_pixmap_new: realized %p: %d colors\n",
274                                                    cmapp->hpal, k));
275
276           iUsage = DIB_PAL_COLORS;
277           for (i = 0; i < 256; i++)
278             bmi.u.bmiIndices[i] = i;
279         }
280       else if (bmi.bmiHeader.biBitCount == 16)
281         {
282           GdkVisual *visual = gdk_visual_get_system ();
283
284           bmi.u.bmiMasks[0] = visual->red_mask;
285           bmi.u.bmiMasks[1] = visual->green_mask;
286           bmi.u.bmiMasks[2] = visual->blue_mask;
287         }
288     }
289
290   hbitmap = CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
291                               iUsage, (PVOID *) &bits, NULL, 0);
292   if (holdpal != NULL)
293     SelectPalette (hdc, holdpal, FALSE);
294
295   GDI_CALL (ReleaseDC, (hwnd, hdc));
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   pixmap_impl->bits = bits;
308
309   gdk_win32_handle_table_insert (&GDK_PIXMAP_HBITMAP (pixmap), pixmap);
310
311   return pixmap;
312 }
313
314 static const unsigned char mirror[256] = {
315   0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
316   0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
317   0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
318   0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
319   0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
320   0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
321   0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
322   0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
323   0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
324   0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
325   0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
326   0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
327   0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
328   0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
329   0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
330   0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
331   0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
332   0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
333   0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
334   0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
335   0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
336   0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
337   0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
338   0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
339   0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
340   0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
341   0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
342   0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
343   0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
344   0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
345   0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
346   0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
347 };
348
349 GdkPixmap *
350 gdk_bitmap_create_from_data (GdkDrawable *drawable,
351                              const gchar *data,
352                              gint         width,
353                              gint         height)
354 {
355   GdkPixmap *pixmap;
356   GdkPixmapImplWin32 *pixmap_impl;
357   gint i, j, data_bpl, pixmap_bpl;
358   guchar *bits;
359
360   g_return_val_if_fail (data != NULL, NULL);
361   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
362   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
363
364   if (!drawable)
365     drawable = _gdk_root;
366   else if (GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
367     return NULL;
368
369   pixmap = gdk_pixmap_new (drawable, width, height, 1);
370
371   if (pixmap == NULL)
372     return NULL;
373
374   pixmap_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
375   bits = pixmap_impl->bits;
376   data_bpl = ((width - 1) / 8 + 1);
377   pixmap_bpl = ((width - 1)/32 + 1)*4;
378
379   for (i = 0; i < height; i++)
380     for (j = 0; j < data_bpl; j++)
381       bits[i*pixmap_bpl + j] = mirror[(guchar) data[i*data_bpl + j]];
382
383   GDK_NOTE (PIXMAP, g_print ("gdk_bitmap_create_from_data: %dx%d=%p\n",
384                              width, height, GDK_PIXMAP_HBITMAP (pixmap)));
385
386   return pixmap;
387 }
388
389 GdkPixmap*
390 gdk_pixmap_create_from_data (GdkDrawable    *drawable,
391                              const gchar    *data,
392                              gint            width,
393                              gint            height,
394                              gint            depth,
395                              const GdkColor *fg,
396                              const GdkColor *bg)
397 {
398   /* Oh wow. I struggled with dozens of lines of code trying to get
399    * this right using a monochrome Win32 bitmap created from data, and
400    * a colour DIB section as the result, trying setting pens,
401    * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
402    * realized it's much easier to do it using gdk...:
403    */
404
405   GdkPixmap *result;
406   GdkPixmap *source;
407   GdkGC *gc;
408
409   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
410   g_return_val_if_fail (data != NULL, NULL);
411   g_return_val_if_fail (fg != NULL, NULL);
412   g_return_val_if_fail (bg != NULL, NULL);
413   g_return_val_if_fail ((drawable != NULL) || (depth != -1), NULL);
414   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
415
416   if (GDK_IS_WINDOW (drawable) && GDK_WINDOW_DESTROYED (drawable))
417     return NULL;
418
419   result = gdk_pixmap_new (drawable, width, height, depth);
420   source = gdk_bitmap_create_from_data (drawable, data, width, height);
421   gc = gdk_gc_new (result);
422
423   gdk_gc_set_foreground (gc, fg);
424   gdk_gc_set_background (gc, bg);
425   _gdk_win32_blit
426     (TRUE,
427      GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (result)->impl),
428      gc, source, 0, 0, 0, 0, width, height);
429   g_object_unref (source);
430   gdk_gc_unref (gc);
431
432   GDK_NOTE (PIXMAP, g_print ("gdk_pixmap_create_from_data: %dx%dx%d=%p\n",
433                              width, height, depth,
434                              GDK_PIXMAP_HBITMAP (result)));
435
436   return result;
437 }
438
439 GdkPixmap *
440 gdk_pixmap_foreign_new_for_display (GdkDisplay      *display,
441                                     GdkNativeWindow  anid)
442 {
443   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
444   g_return_val_if_fail (display == _gdk_display, NULL);
445
446   return gdk_pixmap_foreign_new (anid);
447 }
448
449 GdkPixmap*
450 gdk_pixmap_foreign_new (GdkNativeWindow anid)
451 {
452   GdkPixmap *pixmap;
453   GdkDrawableImplWin32 *draw_impl;
454   GdkPixmapImplWin32 *pix_impl;
455   HBITMAP hbitmap;
456   SIZE size;
457
458   /* Check to make sure we were passed a HBITMAP */
459   g_return_val_if_fail (GetObjectType ((HGDIOBJ) anid) == OBJ_BITMAP, NULL);
460
461   hbitmap = (HBITMAP) anid;
462
463   /* Get information about the bitmap to fill in the structure for the
464    * GDK window.
465    */
466   GetBitmapDimensionEx (hbitmap, &size);
467
468   /* Allocate a new GDK pixmap */
469   pixmap = g_object_new (gdk_pixmap_get_type (), NULL);
470   draw_impl = GDK_DRAWABLE_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
471   pix_impl = GDK_PIXMAP_IMPL_WIN32 (GDK_PIXMAP_OBJECT (pixmap)->impl);
472   draw_impl->wrapper = GDK_DRAWABLE (pixmap);
473   
474   draw_impl->handle = hbitmap;
475   draw_impl->colormap = NULL;
476   pix_impl->width = size.cx;
477   pix_impl->height = size.cy;
478   pix_impl->bits = NULL;
479
480   gdk_win32_handle_table_insert (&GDK_PIXMAP_HBITMAP (pixmap), pixmap);
481
482   return pixmap;
483 }
484
485 GdkPixmap*
486 gdk_pixmap_lookup (GdkNativeWindow anid)
487 {
488   return (GdkPixmap*) gdk_win32_handle_table_lookup (anid);
489 }
490
491 GdkPixmap*
492 gdk_pixmap_lookup_for_display (GdkDisplay *display, GdkNativeWindow anid)
493 {
494   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
495   g_return_val_if_fail (display == _gdk_display, NULL);
496
497   return gdk_pixmap_lookup (anid);
498 }