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