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