]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/bitmap.cpp
Corrected Normalize invocation by casting
[wxWidgets.git] / src / gtk1 / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        bitmap.cpp
3 // Purpose:
4 // Author:      Robert Roebling
5 // RCS-ID:      $Id$
6 // Copyright:   (c) 1998 Robert Roebling
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "bitmap.h"
12 #endif
13
14 #include "wx/defs.h"
15
16 #include "wx/palette.h"
17 #include "wx/bitmap.h"
18 #include "wx/icon.h"
19 #include "wx/filefn.h"
20 #include "wx/image.h"
21 #include "wx/dcmemory.h"
22 #include "wx/app.h"
23
24 #include <gdk/gdk.h>
25 #include <gtk/gtk.h>
26 #include <gdk/gdkx.h>
27
28 #if (GTK_MINOR_VERSION > 0)
29 #include <gdk/gdkrgb.h>
30 #endif
31
32 extern void gdk_wx_draw_bitmap     (GdkDrawable  *drawable,
33                           GdkGC               *gc,
34                           GdkDrawable  *src,
35                           gint                xsrc,
36                           gint                ysrc,
37                           gint                xdest,
38                           gint                ydest,
39                           gint                width,
40                           gint                height);
41
42 //-----------------------------------------------------------------------------
43 // data
44 //-----------------------------------------------------------------------------
45
46 extern GtkWidget *wxGetRootWindow();
47
48 //-----------------------------------------------------------------------------
49 // wxMask
50 //-----------------------------------------------------------------------------
51
52 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
53
54 wxMask::wxMask()
55 {
56     m_bitmap = (GdkBitmap *) NULL;
57 }
58
59 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
60 {
61     m_bitmap = (GdkBitmap *) NULL;
62     Create( bitmap, colour );
63 }
64
65 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
66 {
67     m_bitmap = (GdkBitmap *) NULL;
68     Create( bitmap, paletteIndex );
69 }
70
71 wxMask::wxMask( const wxBitmap& bitmap )
72 {
73     m_bitmap = (GdkBitmap *) NULL;
74     Create( bitmap );
75 }
76
77 wxMask::~wxMask()
78 {
79     if (m_bitmap)
80         gdk_bitmap_unref( m_bitmap );
81 }
82
83 bool wxMask::Create( const wxBitmap& bitmap,
84                      const wxColour& colour )
85 {
86     if (m_bitmap)
87     {
88         gdk_bitmap_unref( m_bitmap );
89         m_bitmap = (GdkBitmap*) NULL;
90     }
91
92     wxImage image( bitmap );
93     if (!image.Ok()) return FALSE;
94
95     m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, image.GetWidth(), image.GetHeight(), 1 );
96     GdkGC *gc = gdk_gc_new( m_bitmap );
97
98     GdkColor color;
99     color.red = 65000;
100     color.green = 65000;
101     color.blue = 65000;
102     color.pixel = 1;
103     gdk_gc_set_foreground( gc, &color );
104     gdk_gc_set_fill( gc, GDK_SOLID );
105     gdk_draw_rectangle( m_bitmap, gc, TRUE, 0, 0, image.GetWidth(), image.GetHeight() );
106
107     unsigned char *data = image.GetData();
108     int index = 0;
109
110     unsigned char red = colour.Red();
111     unsigned char green = colour.Green();
112     unsigned char blue = colour.Blue();
113
114     GdkVisual *visual = wxTheApp->GetGdkVisual();
115
116     int bpp = visual->depth;
117     if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
118     if (bpp == 15)
119     {
120         red = red & 0xf8;
121         green = green & 0xf8;
122         blue = blue & 0xf8;
123     } else
124     if (bpp == 16)
125     {
126         red = red & 0xf8;
127         green = green & 0xfc;
128         blue = blue & 0xf8;
129     } else
130     if (bpp == 12)
131     {
132         red = red & 0xf0;
133         green = green & 0xf0;
134         blue = blue & 0xf0;
135     }
136
137     color.red = 0;
138     color.green = 0;
139     color.blue = 0;
140     color.pixel = 0;
141     gdk_gc_set_foreground( gc, &color );
142
143     for (int j = 0; j < image.GetHeight(); j++)
144     {
145         int start_x = -1;
146         int i;
147         for (i = 0; i < image.GetWidth(); i++)
148         {
149             if ((data[index] == red) &&
150                 (data[index+1] == green) &&
151                 (data[index+2] == blue))
152             {
153                 if (start_x == -1)
154                 start_x = i;
155             }
156             else
157             {
158                 if (start_x != -1)
159                 {
160                     gdk_draw_line( m_bitmap, gc, start_x, j, i-1, j );
161                     start_x = -1;
162                 }
163             }
164             index += 3;
165         }
166         if (start_x != -1)
167             gdk_draw_line( m_bitmap, gc, start_x, j, i, j );
168     }
169
170     gdk_gc_unref( gc );
171
172     return TRUE;
173 }
174
175 bool wxMask::Create( const wxBitmap& bitmap, int paletteIndex )
176 {
177     unsigned char r,g,b;
178     wxPalette *pal = bitmap.GetPalette();
179
180     wxCHECK_MSG( pal, FALSE, wxT("Cannot create mask from bitmap without palette") );
181
182     pal->GetRGB(paletteIndex, &r, &g, &b);
183
184     return Create(bitmap, wxColour(r, g, b));
185 }
186
187 bool wxMask::Create( const wxBitmap& bitmap )
188 {
189     if (m_bitmap)
190     {
191         gdk_bitmap_unref( m_bitmap );
192         m_bitmap = (GdkBitmap*) NULL;
193     }
194
195     if (!bitmap.Ok()) return FALSE;
196
197     wxCHECK_MSG( bitmap.GetBitmap(), FALSE, wxT("Cannot create mask from colour bitmap") );
198
199     m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
200
201     if (!m_bitmap) return FALSE;
202
203     GdkGC *gc = gdk_gc_new( m_bitmap );
204
205     gdk_wx_draw_bitmap( m_bitmap, gc, bitmap.GetBitmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight() );
206
207     gdk_gc_unref( gc );
208
209     return TRUE;
210 }
211
212 GdkBitmap *wxMask::GetBitmap() const
213 {
214     return m_bitmap;
215 }
216
217 //-----------------------------------------------------------------------------
218 // wxBitmap
219 //-----------------------------------------------------------------------------
220
221 class wxBitmapRefData: public wxObjectRefData
222 {
223 public:
224     wxBitmapRefData();
225     ~wxBitmapRefData();
226
227     GdkPixmap      *m_pixmap;
228     GdkBitmap      *m_bitmap;
229     wxMask         *m_mask;
230     int             m_width;
231     int             m_height;
232     int             m_bpp;
233     wxPalette      *m_palette;
234 };
235
236 wxBitmapRefData::wxBitmapRefData()
237 {
238     m_pixmap = (GdkPixmap *) NULL;
239     m_bitmap = (GdkBitmap *) NULL;
240     m_mask = (wxMask *) NULL;
241     m_width = 0;
242     m_height = 0;
243     m_bpp = 0;
244     m_palette = (wxPalette *) NULL;
245 }
246
247 wxBitmapRefData::~wxBitmapRefData()
248 {
249     if (m_pixmap) gdk_pixmap_unref( m_pixmap );
250     if (m_bitmap) gdk_bitmap_unref( m_bitmap );
251     if (m_mask) delete m_mask;
252     if (m_palette) delete m_palette;
253 }
254
255 //-----------------------------------------------------------------------------
256
257 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
258
259 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
260
261 wxBitmap::wxBitmap()
262 {
263 }
264
265 wxBitmap::wxBitmap( int width, int height, int depth )
266 {
267     Create( width, height, depth );
268 }
269
270 bool wxBitmap::Create( int width, int height, int depth )
271 {
272     UnRef();
273
274     wxCHECK_MSG( (width > 0) && (height > 0), FALSE, wxT("invalid bitmap size") )
275
276     GdkVisual *visual = wxTheApp->GetGdkVisual();
277
278     if (depth == -1) depth = visual->depth;
279
280     wxCHECK_MSG( (depth == visual->depth) ||
281                  (depth == 1), FALSE, wxT("invalid bitmap depth") )
282
283     m_refData = new wxBitmapRefData();
284     M_BMPDATA->m_mask = (wxMask *) NULL;
285     M_BMPDATA->m_width = width;
286     M_BMPDATA->m_height = height;
287     if (depth == 1)
288     {
289         M_BMPDATA->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
290         M_BMPDATA->m_bpp = 1;
291     }
292     else
293     {
294         M_BMPDATA->m_pixmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, depth );
295         M_BMPDATA->m_bpp = visual->depth;
296     }
297
298     return Ok();
299 }
300
301 bool wxBitmap::CreateFromXpm( const char **bits )
302 {
303     wxCHECK_MSG( bits != NULL, FALSE, wxT("invalid bitmap data") )
304
305     GdkVisual *visual = wxTheApp->GetGdkVisual();
306
307     m_refData = new wxBitmapRefData();
308
309     GdkBitmap *mask = (GdkBitmap*) NULL;
310
311     M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm_d( wxGetRootWindow()->window, &mask, NULL, (gchar **) bits );
312
313     wxCHECK_MSG( M_BMPDATA->m_pixmap, FALSE, wxT("couldn't create pixmap") );
314
315     if (mask)
316     {
317         M_BMPDATA->m_mask = new wxMask();
318         M_BMPDATA->m_mask->m_bitmap = mask;
319     }
320
321     gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
322
323     M_BMPDATA->m_bpp = visual->depth;  // ?
324
325     return TRUE;
326 }
327
328 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
329 {
330     wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
331     wxCHECK_MSG( depth == -1 || depth == 1, FALSE, wxT("invalid bitmap depth") )
332
333     m_refData = new wxBitmapRefData();
334
335     // ------
336     // convertion to mono bitmap:
337     // ------
338     if (depth == 1)
339     {
340         int width = image.GetWidth();
341         int height = image.GetHeight();
342
343         SetHeight( height );
344         SetWidth( width );
345
346         SetBitmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 ) );
347
348         SetDepth( 1 );
349
350         GdkVisual *visual = wxTheApp->GetGdkVisual();
351
352         // Create picture image
353
354         unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
355
356         GdkImage *data_image =
357             gdk_image_new_bitmap( visual, data_data, width, height );
358
359         // Create mask image
360
361         GdkImage *mask_image = (GdkImage*) NULL;
362
363         if (image.HasMask())
364         {
365             unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
366
367             mask_image =  gdk_image_new_bitmap( visual, mask_data, width, height );
368
369             wxMask *mask = new wxMask();
370             mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
371
372             SetMask( mask );
373         }
374
375         int r_mask = image.GetMaskRed();
376         int g_mask = image.GetMaskGreen();
377         int b_mask = image.GetMaskBlue();
378
379         unsigned char* data = image.GetData();
380
381         int index = 0;
382         for (int y = 0; y < height; y++)
383         {
384             for (int x = 0; x < width; x++)
385             {
386                 int r = data[index];
387                 index++;
388                 int g = data[index];
389                 index++;
390                 int b = data[index];
391                 index++;
392
393                 if (image.HasMask())
394                 {
395                     if ((r == r_mask) && (b == b_mask) && (g == g_mask))
396                         gdk_image_put_pixel( mask_image, x, y, 1 );
397                     else
398                         gdk_image_put_pixel( mask_image, x, y, 0 );
399                 }
400
401                 if ((r == 255) && (b == 255) && (g == 255))
402                     gdk_image_put_pixel( data_image, x, y, 1 );
403                 else
404                     gdk_image_put_pixel( data_image, x, y, 0 );
405
406             } // for
407         }  // for
408
409         // Blit picture
410
411         GdkGC *data_gc = gdk_gc_new( GetBitmap() );
412
413         gdk_draw_image( GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
414
415         gdk_image_destroy( data_image );
416         gdk_gc_unref( data_gc );
417
418         // Blit mask
419
420         if (image.HasMask())
421         {
422             GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
423
424             gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
425
426             gdk_image_destroy( mask_image );
427             gdk_gc_unref( mask_gc );
428         }
429     }
430
431     // ------
432     // convertion to colour bitmap:
433     // ------
434     else
435     {
436         int width = image.GetWidth();
437         int height = image.GetHeight();
438
439         SetHeight( height );
440         SetWidth( width );
441
442         SetPixmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, -1 ) );
443
444         GdkVisual *visual = wxTheApp->GetGdkVisual();
445
446         int bpp = visual->depth;
447
448         SetDepth( bpp );
449
450         if ((bpp == 16) && (visual->red_mask != 0xf800)) bpp = 15;
451         if (bpp < 8) bpp = 8;
452
453         // We handle 8-bit bitmaps ourselves using the colour cube, 12-bit 
454         // visuals are not supported by GDK so we do these ourselves, too.
455         // 15-bit and 16-bit should actually work and 24-bit certainly does.
456 #ifdef __sgi
457         if (!image.HasMask() && (bpp > 16))
458 #else
459         if (!image.HasMask() && (bpp > 12))
460 #endif
461         {
462             static bool s_hasInitialized = FALSE;
463
464             if (!s_hasInitialized)
465             {
466                 gdk_rgb_init();
467                 s_hasInitialized = TRUE;
468             }
469
470             GdkGC *gc = gdk_gc_new( GetPixmap() );
471
472             gdk_draw_rgb_image( GetPixmap(),
473                                 gc,
474                                 0, 0,
475                                 width, height,
476                                 GDK_RGB_DITHER_NONE,
477                                 image.GetData(),
478                                 width*3 );
479
480             gdk_gc_unref( gc );
481             return TRUE;
482         }
483
484         // Create picture image
485
486         GdkImage *data_image =
487             gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
488
489         // Create mask image
490
491         GdkImage *mask_image = (GdkImage*) NULL;
492
493         if (image.HasMask())
494         {
495             unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
496
497             mask_image =  gdk_image_new_bitmap( visual, mask_data, width, height );
498
499             wxMask *mask = new wxMask();
500             mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
501
502             SetMask( mask );
503         }
504
505         // Render
506
507         enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
508         byte_order b_o = RGB;
509
510         if (bpp > 8)
511         {
512             if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask))      b_o = RGB;
513             else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask))  b_o = RGB;
514             else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask))   b_o = BRG;
515             else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
516             else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask))   b_o = GRB;
517             else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask))  b_o = GBR;
518         }
519
520         int r_mask = image.GetMaskRed();
521         int g_mask = image.GetMaskGreen();
522         int b_mask = image.GetMaskBlue();
523
524         unsigned char* data = image.GetData();
525
526         int index = 0;
527         for (int y = 0; y < height; y++)
528         {
529             for (int x = 0; x < width; x++)
530             {
531                 int r = data[index];
532                 index++;
533                 int g = data[index];
534                 index++;
535                 int b = data[index];
536                 index++;
537
538                 if (image.HasMask())
539                 {
540                     if ((r == r_mask) && (b == b_mask) && (g == g_mask))
541                         gdk_image_put_pixel( mask_image, x, y, 1 );
542                     else
543                         gdk_image_put_pixel( mask_image, x, y, 0 );
544                 }
545
546                 switch (bpp)
547                 {
548                     case 8:
549                     {
550                         int pixel = -1;
551                         if (wxTheApp->m_colorCube)
552                         {
553                             pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
554                         }
555                         else
556                         {
557                             GdkColormap *cmap = gtk_widget_get_default_colormap();
558                             GdkColor *colors = cmap->colors;
559                             int max = 3 * (65536);
560     
561                             for (int i = 0; i < cmap->size; i++)
562                             {
563                                 int rdiff = (r << 8) - colors[i].red;
564                                 int gdiff = (g << 8) - colors[i].green;
565                                 int bdiff = (b << 8) - colors[i].blue;
566                                 int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
567                                 if (sum < max) { pixel = i; max = sum; }
568                             }
569                         }
570     
571                         gdk_image_put_pixel( data_image, x, y, pixel );
572     
573                         break;
574                     }
575                     case 12:  // SGI only
576                     {
577                         guint32 pixel = 0;
578                         switch (b_o)
579                         {
580                             case RGB: pixel = ((r & 0xf0) << 4) | (g & 0xf0) | ((b & 0xf0) >> 4); break;
581                             case RBG: pixel = ((r & 0xf0) << 4) | (b & 0xf0) | ((g & 0xf0) >> 4); break;
582                             case GRB: pixel = ((g & 0xf0) << 4) | (r & 0xf0) | ((b & 0xf0) >> 4); break;
583                             case GBR: pixel = ((g & 0xf0) << 4) | (b & 0xf0) | ((r & 0xf0) >> 4); break;
584                             case BRG: pixel = ((b & 0xf0) << 4) | (r & 0xf0) | ((g & 0xf0) >> 4); break;
585                             case BGR: pixel = ((b & 0xf0) << 4) | (g & 0xf0) | ((r & 0xf0) >> 4); break;
586                         }
587                         gdk_image_put_pixel( data_image, x, y, pixel );
588                         break;
589                     }
590                     case 15:
591                     {
592                         guint32 pixel = 0;
593                         switch (b_o)
594                         {
595                             case RGB: pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
596                             case RBG: pixel = ((r & 0xf8) << 7) | ((b & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
597                             case GRB: pixel = ((g & 0xf8) << 7) | ((r & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
598                             case GBR: pixel = ((g & 0xf8) << 7) | ((b & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
599                             case BRG: pixel = ((b & 0xf8) << 7) | ((r & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
600                             case BGR: pixel = ((b & 0xf8) << 7) | ((g & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
601                         }
602                         gdk_image_put_pixel( data_image, x, y, pixel );
603                         break;
604                     }
605                     case 16:
606                     {
607                         // I actually don't know if for 16-bit displays, it is alway the green
608                         // component or the second component which has 6 bits.
609                         guint32 pixel = 0;
610                         switch (b_o)
611                         {
612                             case RGB: pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
613                             case RBG: pixel = ((r & 0xf8) << 8) | ((b & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
614                             case GRB: pixel = ((g & 0xf8) << 8) | ((r & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
615                             case GBR: pixel = ((g & 0xf8) << 8) | ((b & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
616                             case BRG: pixel = ((b & 0xf8) << 8) | ((r & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
617                             case BGR: pixel = ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
618                         }
619                         gdk_image_put_pixel( data_image, x, y, pixel );
620                         break;
621                     }
622                     case 32:
623                     case 24:
624                     {
625                         guint32 pixel = 0;
626                         switch (b_o)
627                         {
628                             case RGB: pixel = (r << 16) | (g << 8) | b; break;
629                             case RBG: pixel = (r << 16) | (b << 8) | g; break;
630                             case BRG: pixel = (b << 16) | (r << 8) | g; break;
631                             case BGR: pixel = (b << 16) | (g << 8) | r; break;
632                             case GRB: pixel = (g << 16) | (r << 8) | b; break;
633                             case GBR: pixel = (g << 16) | (b << 8) | r; break;
634                         }
635                         gdk_image_put_pixel( data_image, x, y, pixel );
636                     }
637                     default: break;
638                 }
639             } // for
640         }  // for
641
642         // Blit picture
643
644         GdkGC *data_gc = gdk_gc_new( GetPixmap() );
645
646         gdk_draw_image( GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
647
648         gdk_image_destroy( data_image );
649         gdk_gc_unref( data_gc );
650
651         // Blit mask
652
653         if (image.HasMask())
654         {
655             GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
656
657             gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
658
659             gdk_image_destroy( mask_image );
660             gdk_gc_unref( mask_gc );
661         }
662     }
663
664     return TRUE;
665 }
666
667 wxImage wxBitmap::ConvertToImage() const
668 {
669     wxImage image;
670
671     wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
672
673     GdkImage *gdk_image = (GdkImage*) NULL;
674     if (GetPixmap())
675     {
676         gdk_image = gdk_image_get( GetPixmap(),
677             0, 0,
678             GetWidth(), GetHeight() );
679     } else
680     if (GetBitmap())
681     {
682         gdk_image = gdk_image_get( GetBitmap(),
683             0, 0,
684             GetWidth(), GetHeight() );
685     } else
686     {
687         wxFAIL_MSG( wxT("Ill-formed bitmap") );
688     }
689
690     wxCHECK_MSG( gdk_image, wxNullImage, wxT("couldn't create image") );
691
692     image.Create( GetWidth(), GetHeight() );
693     char unsigned *data = image.GetData();
694
695     if (!data)
696     {
697         gdk_image_destroy( gdk_image );
698         wxFAIL_MSG( wxT("couldn't create image") );
699         return wxNullImage;
700     }
701
702     GdkImage *gdk_image_mask = (GdkImage*) NULL;
703     if (GetMask())
704     {
705         gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
706             0, 0,
707             GetWidth(), GetHeight() );
708
709         image.SetMaskColour( 16, 16, 16 );  // anything unlikely and dividable
710     }
711
712     int bpp = -1;
713     int red_shift_right = 0;
714     int green_shift_right = 0;
715     int blue_shift_right = 0;
716     int red_shift_left = 0;
717     int green_shift_left = 0;
718     int blue_shift_left = 0;
719     bool use_shift = FALSE;
720
721     if (GetPixmap())
722     {
723         GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
724         if (visual == NULL)
725             visual = wxTheApp->GetGdkVisual();
726         
727         bpp = visual->depth;
728         if (bpp == 16) bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
729         red_shift_right = visual->red_shift;
730         red_shift_left = 8-visual->red_prec;
731         green_shift_right = visual->green_shift;
732         green_shift_left = 8-visual->green_prec;
733         blue_shift_right = visual->blue_shift;
734         blue_shift_left = 8-visual->blue_prec;
735
736         use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
737     }
738     if (GetBitmap())
739     {
740         bpp = 1;
741     }
742
743
744     GdkColormap *cmap = gtk_widget_get_default_colormap();
745
746     long pos = 0;
747     for (int j = 0; j < GetHeight(); j++)
748     {
749         for (int i = 0; i < GetWidth(); i++)
750         {
751             wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
752             if (bpp == 1)
753             {
754                 if (pixel == 0)
755                 {
756                     data[pos]   = 0;
757                     data[pos+1] = 0;
758                     data[pos+2] = 0;
759                 }
760                 else
761                 {
762                     data[pos]   = 255;
763                     data[pos+1] = 255;
764                     data[pos+2] = 255;
765                 }
766             }
767             else if (use_shift)
768             {
769                 data[pos] =   (pixel >> red_shift_right)   << red_shift_left;
770                 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
771                 data[pos+2] = (pixel >> blue_shift_right)  << blue_shift_left;
772             }
773             else if (cmap->colors)
774             {
775                 data[pos] =   cmap->colors[pixel].red   >> 8;
776                 data[pos+1] = cmap->colors[pixel].green >> 8;
777                 data[pos+2] = cmap->colors[pixel].blue  >> 8;
778             }
779             else
780             {
781                 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
782             }
783
784             if (gdk_image_mask)
785             {
786                 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
787                 if (mask_pixel == 0)
788                 {
789                     data[pos] = 16;
790                     data[pos+1] = 16;
791                     data[pos+2] = 16;
792                 }
793             }
794
795             pos += 3;
796         }
797     }
798
799     gdk_image_destroy( gdk_image );
800     if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
801
802     return image;
803 }
804
805 wxBitmap::wxBitmap( const wxBitmap& bmp )
806 {
807     Ref( bmp );
808 }
809
810 wxBitmap::wxBitmap( const wxString &filename, int type )
811 {
812     LoadFile( filename, type );
813 }
814
815 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
816 {
817     m_refData = new wxBitmapRefData();
818
819     M_BMPDATA->m_mask = (wxMask *) NULL;
820     M_BMPDATA->m_bitmap =
821       gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) bits, width, height );
822     M_BMPDATA->m_width = width;
823     M_BMPDATA->m_height = height;
824     M_BMPDATA->m_bpp = 1;
825
826     wxCHECK_RET( M_BMPDATA->m_bitmap, wxT("couldn't create bitmap") );
827 }
828
829 wxBitmap::~wxBitmap()
830 {
831 }
832
833 wxBitmap& wxBitmap::operator = ( const wxBitmap& bmp )
834 {
835     if ( m_refData != bmp.m_refData )
836         Ref( bmp );
837
838     return *this;
839 }
840
841 bool wxBitmap::operator == ( const wxBitmap& bmp ) const
842 {
843     return m_refData == bmp.m_refData;
844 }
845
846 bool wxBitmap::operator != ( const wxBitmap& bmp ) const
847 {
848     return m_refData != bmp.m_refData;
849 }
850
851 bool wxBitmap::Ok() const
852 {
853     return (m_refData != NULL);
854 }
855
856 int wxBitmap::GetHeight() const
857 {
858     wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
859
860     return M_BMPDATA->m_height;
861 }
862
863 int wxBitmap::GetWidth() const
864 {
865     wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
866
867     return M_BMPDATA->m_width;
868 }
869
870 int wxBitmap::GetDepth() const
871 {
872     wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
873
874     return M_BMPDATA->m_bpp;
875 }
876
877 wxMask *wxBitmap::GetMask() const
878 {
879     wxCHECK_MSG( Ok(), (wxMask *) NULL, wxT("invalid bitmap") );
880
881     return M_BMPDATA->m_mask;
882 }
883
884 void wxBitmap::SetMask( wxMask *mask )
885 {
886     wxCHECK_RET( Ok(), wxT("invalid bitmap") );
887
888     if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
889
890     M_BMPDATA->m_mask = mask;
891 }
892
893 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
894 {
895     *this = icon;
896     return TRUE;
897 }
898
899 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
900 {
901     wxCHECK_MSG( Ok() &&
902                  (rect.x >= 0) && (rect.y >= 0) &&
903                  (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
904                  wxNullBitmap, wxT("invalid bitmap or bitmap region") );
905
906     wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
907     wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
908
909     if (ret.GetPixmap())
910     {
911         GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
912         gdk_draw_pixmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
913         gdk_gc_destroy( gc );
914     }
915     else
916     {
917         GdkGC *gc = gdk_gc_new( ret.GetBitmap() );
918         gdk_wx_draw_bitmap( ret.GetBitmap(), gc, GetBitmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
919         gdk_gc_destroy( gc );
920     }
921
922     if (GetMask())
923     {
924         wxMask *mask = new wxMask;
925         mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
926
927         GdkGC *gc = gdk_gc_new( mask->m_bitmap );
928         gdk_wx_draw_bitmap( mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, 0, 0, rect.x, rect.y, rect.width, rect.height );
929         gdk_gc_destroy( gc );
930
931         ret.SetMask( mask );
932     }
933
934     return ret;
935 }
936
937 bool wxBitmap::SaveFile( const wxString &name, int type, wxPalette *WXUNUSED(palette) )
938 {
939     wxCHECK_MSG( Ok(), FALSE, wxT("invalid bitmap") );
940
941     // Try to save the bitmap via wxImage handlers:
942     {
943         wxImage image( *this );
944         if (image.Ok()) return image.SaveFile( name, type );
945     }
946
947     return FALSE;
948 }
949
950 bool wxBitmap::LoadFile( const wxString &name, int type )
951 {
952     UnRef();
953
954     if (!wxFileExists(name)) return FALSE;
955
956     GdkVisual *visual = wxTheApp->GetGdkVisual();
957
958     if (type == wxBITMAP_TYPE_XPM)
959     {
960         m_refData = new wxBitmapRefData();
961
962         GdkBitmap *mask = (GdkBitmap*) NULL;
963
964         M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm( wxGetRootWindow()->window, &mask, NULL, name.fn_str() );
965
966         if (mask)
967         {
968            M_BMPDATA->m_mask = new wxMask();
969            M_BMPDATA->m_mask->m_bitmap = mask;
970         }
971
972         gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
973
974         M_BMPDATA->m_bpp = visual->depth;
975     }
976     else // try if wxImage can load it
977     {
978         wxImage image;
979         if (!image.LoadFile( name, type )) return FALSE;
980         if (image.Ok()) *this = image.ConvertToBitmap();
981         else return FALSE;
982     }
983
984     return TRUE;
985 }
986
987 wxPalette *wxBitmap::GetPalette() const
988 {
989     if (!Ok()) return (wxPalette *) NULL;
990
991     return M_BMPDATA->m_palette;
992 }
993
994 void wxBitmap::SetHeight( int height )
995 {
996     if (!m_refData) m_refData = new wxBitmapRefData();
997
998     M_BMPDATA->m_height = height;
999 }
1000
1001 void wxBitmap::SetWidth( int width )
1002 {
1003     if (!m_refData) m_refData = new wxBitmapRefData();
1004
1005     M_BMPDATA->m_width = width;
1006 }
1007
1008 void wxBitmap::SetDepth( int depth )
1009 {
1010     if (!m_refData) m_refData = new wxBitmapRefData();
1011
1012     M_BMPDATA->m_bpp = depth;
1013 }
1014
1015 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
1016 {
1017     if (!m_refData) m_refData = new wxBitmapRefData();
1018
1019     M_BMPDATA->m_pixmap = pixmap;
1020 }
1021
1022 void wxBitmap::SetBitmap( GdkPixmap *bitmap )
1023 {
1024     if (!m_refData) m_refData = new wxBitmapRefData();
1025
1026     M_BMPDATA->m_bitmap = bitmap;
1027 }
1028
1029 GdkPixmap *wxBitmap::GetPixmap() const
1030 {
1031     wxCHECK_MSG( Ok(), (GdkPixmap *) NULL, wxT("invalid bitmap") );
1032
1033     return M_BMPDATA->m_pixmap;
1034 }
1035
1036 GdkBitmap *wxBitmap::GetBitmap() const
1037 {
1038     wxCHECK_MSG( Ok(), (GdkBitmap *) NULL, wxT("invalid bitmap") );
1039
1040     return M_BMPDATA->m_bitmap;
1041 }