]> git.saurik.com Git - wxWidgets.git/blob - src/gtk1/bitmap.cpp
Second try to get wxDataViewChoiceByIndex and its name right, hopefully fixes #11970...
[wxWidgets.git] / src / gtk1 / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk1/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 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #include "wx/bitmap.h"
14
15 #ifndef WX_PRECOMP
16     #include "wx/app.h"
17     #include "wx/dcmemory.h"
18     #include "wx/palette.h"
19     #include "wx/icon.h"
20     #include "wx/math.h"
21     #include "wx/image.h"
22 #endif // WX_PRECOMP
23
24 #include "wx/filefn.h"
25
26 #include <gdk/gdk.h>
27 #include <gtk/gtk.h>
28 #include <gdk/gdkx.h>
29
30 #include <gdk/gdkrgb.h>
31
32 extern
33 void gdk_wx_draw_bitmap (GdkDrawable  *drawable,
34                          GdkGC        *gc,
35                          GdkDrawable  *src,
36                          gint          xsrc,
37                          gint          ysrc,
38                          gint          xdest,
39                          gint          ydest,
40                          gint          width,
41                          gint          height);
42
43 //-----------------------------------------------------------------------------
44 // data
45 //-----------------------------------------------------------------------------
46
47 extern GtkWidget *wxGetRootWindow();
48
49 //-----------------------------------------------------------------------------
50 // wxMask
51 //-----------------------------------------------------------------------------
52
53 IMPLEMENT_DYNAMIC_CLASS(wxMask,wxObject)
54
55 wxMask::wxMask()
56 {
57     m_bitmap = NULL;
58 }
59
60 wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
61 {
62     m_bitmap = NULL;
63     Create( bitmap, colour );
64 }
65
66 #if wxUSE_PALETTE
67 wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
68 {
69     m_bitmap = NULL;
70     Create( bitmap, paletteIndex );
71 }
72 #endif // wxUSE_PALETTE
73
74 wxMask::wxMask( const wxBitmap& bitmap )
75 {
76     m_bitmap = NULL;
77     Create( bitmap );
78 }
79
80 wxMask::~wxMask()
81 {
82     if (m_bitmap)
83         gdk_bitmap_unref( m_bitmap );
84 }
85
86 bool wxMask::Create( const wxBitmap& bitmap,
87                      const wxColour& colour )
88 {
89     if (m_bitmap)
90     {
91         gdk_bitmap_unref( m_bitmap );
92         m_bitmap = NULL;
93     }
94
95     wxImage image = bitmap.ConvertToImage();
96     if (!image.Ok()) return false;
97
98     m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, image.GetWidth(), image.GetHeight(), 1 );
99     GdkGC *gc = gdk_gc_new( m_bitmap );
100
101     GdkColor color;
102     color.red = 65000;
103     color.green = 65000;
104     color.blue = 65000;
105     color.pixel = 1;
106     gdk_gc_set_foreground( gc, &color );
107     gdk_gc_set_fill( gc, GDK_SOLID );
108     gdk_draw_rectangle( m_bitmap, gc, TRUE, 0, 0, image.GetWidth(), image.GetHeight() );
109
110     unsigned char *data = image.GetData();
111     int index = 0;
112
113     unsigned char red = colour.Red();
114     unsigned char green = colour.Green();
115     unsigned char blue = colour.Blue();
116
117     GdkVisual *visual = wxTheApp->GetGdkVisual();
118
119     int bpp = visual->depth;
120     if ((bpp == 16) && (visual->red_mask != 0xf800))
121         bpp = 15;
122     if (bpp == 15)
123     {
124         red = red & 0xf8;
125         green = green & 0xf8;
126         blue = blue & 0xf8;
127     }
128     else if (bpp == 16)
129     {
130         red = red & 0xf8;
131         green = green & 0xfc;
132         blue = blue & 0xf8;
133     }
134     else if (bpp == 12)
135     {
136         red = red & 0xf0;
137         green = green & 0xf0;
138         blue = blue & 0xf0;
139     }
140
141     color.red = 0;
142     color.green = 0;
143     color.blue = 0;
144     color.pixel = 0;
145     gdk_gc_set_foreground( gc, &color );
146
147     for (int j = 0; j < image.GetHeight(); j++)
148     {
149         int start_x = -1;
150         int i;
151         for (i = 0; i < image.GetWidth(); i++)
152         {
153             if ((data[index] == red) &&
154                 (data[index+1] == green) &&
155                 (data[index+2] == blue))
156             {
157                 if (start_x == -1)
158                 start_x = i;
159             }
160             else
161             {
162                 if (start_x != -1)
163                 {
164                     gdk_draw_line( m_bitmap, gc, start_x, j, i-1, j );
165                     start_x = -1;
166                 }
167             }
168             index += 3;
169         }
170         if (start_x != -1)
171             gdk_draw_line( m_bitmap, gc, start_x, j, i, j );
172     }
173
174     gdk_gc_unref( gc );
175
176     return true;
177 }
178
179 #if wxUSE_PALETTE
180 bool wxMask::Create( const wxBitmap& bitmap, int paletteIndex )
181 {
182     unsigned char r,g,b;
183     wxPalette *pal = bitmap.GetPalette();
184
185     wxCHECK_MSG( pal, false, wxT("Cannot create mask from bitmap without palette") );
186
187     pal->GetRGB(paletteIndex, &r, &g, &b);
188
189     return Create(bitmap, wxColour(r, g, b));
190 }
191 #endif // wxUSE_PALETTE
192
193 bool wxMask::Create( const wxBitmap& bitmap )
194 {
195     if (m_bitmap)
196     {
197         gdk_bitmap_unref( m_bitmap );
198         m_bitmap = NULL;
199     }
200
201     if (!bitmap.Ok()) return false;
202
203     wxCHECK_MSG( bitmap.GetBitmap(), false, wxT("Cannot create mask from colour bitmap") );
204
205     m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
206
207     if (!m_bitmap) return false;
208
209     GdkGC *gc = gdk_gc_new( m_bitmap );
210
211     gdk_wx_draw_bitmap( m_bitmap, gc, bitmap.GetBitmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight() );
212
213     gdk_gc_unref( gc );
214
215     return true;
216 }
217
218 GdkBitmap *wxMask::GetBitmap() const
219 {
220     return m_bitmap;
221 }
222
223
224 //-----------------------------------------------------------------------------
225 // wxBitmapRefData
226 //-----------------------------------------------------------------------------
227
228 class wxBitmapRefData : public wxGDIRefData
229 {
230 public:
231     wxBitmapRefData();
232     wxBitmapRefData(const wxBitmapRefData& data);
233     bool Create(int width, int height, int bpp);
234     virtual ~wxBitmapRefData();
235
236     virtual bool IsOk() const { return m_pixmap || m_bitmap; }
237
238     GdkPixmap      *m_pixmap;
239     GdkBitmap      *m_bitmap;
240     wxMask         *m_mask;
241     int             m_width;
242     int             m_height;
243     int             m_bpp;
244 #if wxUSE_PALETTE
245     wxPalette      *m_palette;
246 #endif // wxUSE_PALETTE
247 };
248
249 wxBitmapRefData::wxBitmapRefData()
250 {
251     m_pixmap = NULL;
252     m_bitmap = NULL;
253     m_mask = NULL;
254     m_width = 0;
255     m_height = 0;
256     m_bpp = 0;
257 #if wxUSE_PALETTE
258     m_palette = NULL;
259 #endif // wxUSE_PALETTE
260 }
261
262 wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data)
263 {
264     Create(data.m_width, data.m_height, data.m_bpp);
265
266     m_mask = data.m_mask ? new wxMask(*data.m_mask) : NULL;
267
268 #if wxUSE_PALETTE
269     wxASSERT_MSG( !data.m_palette,
270                   wxT("copying bitmaps palette not implemented") );
271 #endif // wxUSE_PALETTE
272
273
274     // copy the bitmap data by simply drawing the source bitmap on this one
275     GdkPixmap **dst;
276     if ( data.m_pixmap )
277     {
278         dst = &m_pixmap;
279     }
280     else if ( data.m_bitmap )
281     {
282         dst = &m_bitmap;
283     }
284     else // invalid bitmap?
285     {
286         return;
287     }
288
289     GdkGC *gc = gdk_gc_new(*dst);
290     if ( m_bpp == 1 )
291     {
292         gdk_wx_draw_bitmap(m_bitmap, gc, data.m_bitmap, 0, 0, 0, 0, -1, -1);
293     }
294     else // colour pixmap
295     {
296         gdk_draw_pixmap(m_pixmap, gc, data.m_pixmap, 0, 0, 0, 0, -1, -1);
297     }
298
299     gdk_gc_unref(gc);
300 }
301
302 bool wxBitmapRefData::Create(int width, int height, int bpp)
303 {
304     m_width = width;
305     m_height = height;
306     m_bpp = bpp;
307
308     m_mask = NULL;
309 #if wxUSE_PALETTE
310     m_palette = NULL;
311 #endif
312
313     // to understand how this compiles you should know that GdkPixmap and
314     // GdkBitmap are one and the same type in GTK+ 1
315     GdkPixmap **ppix;
316     if ( m_bpp != 1 )
317     {
318         const GdkVisual * const visual = wxTheApp->GetGdkVisual();
319
320         wxCHECK_MSG( (bpp == -1) || (bpp == visual->depth) || (bpp == 32), false,
321                         wxT("invalid bitmap depth") );
322
323         m_bpp = visual->depth;
324
325         ppix = &m_pixmap;
326         m_bitmap = NULL;
327     }
328     else // mono bitmap
329     {
330         ppix = &m_bitmap;
331         m_pixmap = NULL;
332     }
333
334     *ppix = gdk_pixmap_new( wxGetRootWindow()->window, width, height, m_bpp );
335
336     return *ppix != NULL;
337 }
338
339 wxBitmapRefData::~wxBitmapRefData()
340 {
341     if (m_pixmap)
342         gdk_pixmap_unref( m_pixmap );
343     if (m_bitmap)
344         gdk_bitmap_unref( m_bitmap );
345     delete m_mask;
346 #if wxUSE_PALETTE
347     delete m_palette;
348 #endif // wxUSE_PALETTE
349 }
350
351
352 //-----------------------------------------------------------------------------
353 // wxBitmap
354 //-----------------------------------------------------------------------------
355
356 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
357
358 IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
359
360 wxGDIRefData *wxBitmap::CreateGDIRefData() const
361 {
362     return new wxBitmapRefData;
363 }
364
365 wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const
366 {
367     return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
368 }
369
370 bool wxBitmap::Create( int width, int height, int depth )
371 {
372     UnRef();
373
374     if ( width <= 0 || height <= 0 )
375     {
376         return false;
377     }
378
379     m_refData = new wxBitmapRefData();
380     return M_BMPDATA->Create(width, height, depth);
381 }
382
383 wxBitmap::wxBitmap(const char* const* bits)
384 {
385     wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data"));
386
387     GdkVisual *visual = wxTheApp->GetGdkVisual();
388
389     m_refData = new wxBitmapRefData();
390
391     GdkBitmap *mask = NULL;
392
393     M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm_d( wxGetRootWindow()->window, &mask, NULL, (gchar **) bits );
394
395     wxCHECK2_MSG(M_BMPDATA->m_pixmap, return, wxT("couldn't create pixmap"));
396
397     if (mask)
398     {
399         M_BMPDATA->m_mask = new wxMask();
400         M_BMPDATA->m_mask->m_bitmap = mask;
401     }
402
403     gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
404
405     M_BMPDATA->m_bpp = visual->depth;  // Can we get a different depth from create_from_xpm_d() ?
406 }
407
408 wxBitmap wxBitmap::Rescale( int clipx, int clipy, int clipwidth, int clipheight, int newx, int newy )
409 {
410     wxCHECK_MSG( Ok(), wxNullBitmap, wxT("invalid bitmap") );
411
412     if (newy==M_BMPDATA->m_width && newy==M_BMPDATA->m_height)
413         return *this;
414
415     int width = wxMax(newx, 1);
416     int height = wxMax(newy, 1);
417     width = wxMin(width, clipwidth);
418     height = wxMin(height, clipheight);
419
420     wxBitmap bmp;
421
422     GdkImage *img = NULL;
423     if (GetPixmap())
424         img = gdk_image_get( GetPixmap(), 0, 0, GetWidth(), GetHeight() );
425     else if (GetBitmap())
426         img = gdk_image_get( GetBitmap(), 0, 0, GetWidth(), GetHeight() );
427     else
428         wxFAIL_MSG( wxT("Ill-formed bitmap") );
429
430     wxCHECK_MSG( img, wxNullBitmap, wxT("couldn't create image") );
431
432     int bpp = -1;
433
434
435     GdkGC *gc = NULL;
436     GdkPixmap *dstpix = NULL;
437     if (GetPixmap())
438     {
439         GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
440         if (visual == NULL)
441             visual = wxTheApp->GetGdkVisual();
442
443         bpp = visual->depth;
444         bmp = wxBitmap(width,height,bpp);
445         dstpix = bmp.GetPixmap();
446         gc = gdk_gc_new( dstpix );
447     }
448
449     char *dst = NULL;
450     long dstbyteperline = 0;
451
452     if (GetBitmap())
453     {
454         bpp = 1;
455         dstbyteperline = width/8*M_BMPDATA->m_bpp;
456         if (width*M_BMPDATA->m_bpp % 8 != 0)
457             dstbyteperline++;
458         dst = (char*) malloc(dstbyteperline*height);
459     }
460
461     // be careful to use the right scaling factor
462     float scx = (float)M_BMPDATA->m_width/(float)newx;
463     float scy = (float)M_BMPDATA->m_height/(float)newy;
464     // prepare accel-tables
465     int *tablex = (int *)calloc(width,sizeof(int));
466     int *tabley = (int *)calloc(height,sizeof(int));
467
468     // accel table filled with clipped values
469     for (int x = 0; x < width; x++)
470         tablex[x] = (int) (scx * (x+clipx));
471     for (int y = 0; y < height; y++)
472         tabley[y] = (int) (scy * (y+clipy));
473
474     // Main rescaling routine starts here
475     for (int h = 0; h < height; h++)
476     {
477         char outbyte = 0;
478         int old_x = -1;
479         guint32 old_pixval = 0;
480
481         for (int w = 0; w < width; w++)
482         {
483             guint32 pixval;
484             int x = tablex[w];
485             if (x == old_x)
486                 pixval = old_pixval;
487             else
488             {
489                 pixval = gdk_image_get_pixel( img, x, tabley[h] );
490                 old_pixval = pixval;
491                 old_x = x;
492             }
493
494             if (bpp == 1)
495             {
496                 if (!pixval)
497                 {
498                     char bit=1;
499                     char shift = bit << (w % 8);
500                     outbyte |= shift;
501                 }
502
503                 if ((w+1)%8==0)
504                 {
505                     dst[h*dstbyteperline+w/8] = outbyte;
506                     outbyte = 0;
507                 }
508             }
509             else
510             {
511                 GdkColor col;
512                 col.pixel = pixval;
513                 gdk_gc_set_foreground( gc, &col );
514                 gdk_draw_point( dstpix, gc, w, h);
515             }
516         }
517
518         // do not forget the last byte
519         if ((bpp == 1) && (width % 8 != 0))
520             dst[h*dstbyteperline+width/8] = outbyte;
521     }
522
523     gdk_image_destroy( img );
524     if (gc) gdk_gc_unref( gc );
525
526     if (bpp == 1)
527     {
528         bmp = wxBitmap( (const char *)dst, width, height, 1 );
529         free( dst );
530     }
531
532     if (GetMask())
533     {
534         dstbyteperline = width/8;
535         if (width % 8 != 0)
536             dstbyteperline++;
537         dst = (char*) malloc(dstbyteperline*height);
538         img = gdk_image_get( GetMask()->GetBitmap(), 0, 0, GetWidth(), GetHeight() );
539
540         for (int h = 0; h < height; h++)
541         {
542             char outbyte = 0;
543             int old_x = -1;
544             guint32 old_pixval = 0;
545
546             for (int w = 0; w < width; w++)
547             {
548                 guint32 pixval;
549                 int x = tablex[w];
550                 if (x == old_x)
551                     pixval = old_pixval;
552                 else
553                 {
554                     pixval = gdk_image_get_pixel( img, x, tabley[h] );
555                     old_pixval = pixval;
556                     old_x = x;
557                 }
558
559                 if (pixval)
560                 {
561                     char bit=1;
562                     char shift = bit << (w % 8);
563                     outbyte |= shift;
564                 }
565
566                 if ((w+1)%8 == 0)
567                 {
568                     dst[h*dstbyteperline+w/8] = outbyte;
569                     outbyte = 0;
570                 }
571             }
572
573             // do not forget the last byte
574             if (width % 8 != 0)
575                 dst[h*dstbyteperline+width/8] = outbyte;
576         }
577         wxMask* mask = new wxMask;
578         mask->m_bitmap = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) dst, width, height );
579         bmp.SetMask(mask);
580
581         free( dst );
582         gdk_image_destroy( img );
583     }
584
585     free( tablex );
586     free( tabley );
587
588     return bmp;
589 }
590
591 bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
592 {
593     UnRef();
594
595     wxCHECK_MSG( image.Ok(), false, wxT("invalid image") );
596     wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") );
597
598     if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
599         return false;
600
601     m_refData = new wxBitmapRefData();
602
603     if (depth == 1)
604     {
605         return CreateFromImageAsBitmap(image);
606     }
607     else
608     {
609         return CreateFromImageAsPixmap(image);
610     }
611 }
612
613 // conversion to mono bitmap:
614 bool wxBitmap::CreateFromImageAsBitmap(const wxImage& img)
615 {
616     // convert alpha channel to mask, if it is present:
617     wxImage image(img);
618     image.ConvertAlphaToMask();
619
620     int width = image.GetWidth();
621     int height = image.GetHeight();
622
623     SetHeight( height );
624     SetWidth( width );
625
626     SetBitmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 ) );
627
628     SetDepth( 1 );
629
630     GdkVisual *visual = wxTheApp->GetGdkVisual();
631
632     // Create picture image
633
634     unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
635
636     GdkImage *data_image =
637         gdk_image_new_bitmap( visual, data_data, width, height );
638
639     // Create mask image
640
641     GdkImage *mask_image = NULL;
642
643     if (image.HasMask())
644     {
645         unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
646
647         mask_image =  gdk_image_new_bitmap( visual, mask_data, width, height );
648
649         wxMask *mask = new wxMask();
650         mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
651
652         SetMask( mask );
653     }
654
655     int r_mask = image.GetMaskRed();
656     int g_mask = image.GetMaskGreen();
657     int b_mask = image.GetMaskBlue();
658
659     unsigned char* data = image.GetData();
660
661     int index = 0;
662     for (int y = 0; y < height; y++)
663     {
664         for (int x = 0; x < width; x++)
665         {
666             int r = data[index];
667             index++;
668             int g = data[index];
669             index++;
670             int b = data[index];
671             index++;
672
673             if (image.HasMask())
674             {
675                 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
676                     gdk_image_put_pixel( mask_image, x, y, 1 );
677                 else
678                     gdk_image_put_pixel( mask_image, x, y, 0 );
679             }
680
681             if ((r == 255) && (b == 255) && (g == 255))
682                 gdk_image_put_pixel( data_image, x, y, 1 );
683             else
684                 gdk_image_put_pixel( data_image, x, y, 0 );
685
686         } // for
687     }  // for
688
689     // Blit picture
690
691     GdkGC *data_gc = gdk_gc_new( GetBitmap() );
692
693     gdk_draw_image( GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
694
695     gdk_image_destroy( data_image );
696     gdk_gc_unref( data_gc );
697
698     // Blit mask
699
700     if (image.HasMask())
701     {
702         GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
703
704         gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
705
706         gdk_image_destroy( mask_image );
707         gdk_gc_unref( mask_gc );
708     }
709
710     return true;
711 }
712
713 // conversion to colour bitmap:
714 bool wxBitmap::CreateFromImageAsPixmap(const wxImage& img)
715 {
716     // convert alpha channel to mask, if it is present:
717     wxImage image(img);
718     image.ConvertAlphaToMask();
719
720     int width = image.GetWidth();
721     int height = image.GetHeight();
722
723     SetHeight( height );
724     SetWidth( width );
725
726     SetPixmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, -1 ) );
727
728     GdkVisual *visual = wxTheApp->GetGdkVisual();
729
730     int bpp = visual->depth;
731
732     SetDepth( bpp );
733
734     if ((bpp == 16) && (visual->red_mask != 0xf800))
735         bpp = 15;
736     else if (bpp < 8)
737         bpp = 8;
738
739     // We handle 8-bit bitmaps ourselves using the colour cube, 12-bit
740     // visuals are not supported by GDK so we do these ourselves, too.
741     // 15-bit and 16-bit should actually work and 24-bit certainly does.
742 #ifdef __sgi
743     if (!image.HasMask() && (bpp > 16))
744 #else
745     if (!image.HasMask() && (bpp > 12))
746 #endif
747     {
748         static bool s_hasInitialized = false;
749
750         if (!s_hasInitialized)
751         {
752             gdk_rgb_init();
753             s_hasInitialized = true;
754         }
755
756         GdkGC *gc = gdk_gc_new( GetPixmap() );
757
758         gdk_draw_rgb_image( GetPixmap(),
759                             gc,
760                             0, 0,
761                             width, height,
762                             GDK_RGB_DITHER_NONE,
763                             image.GetData(),
764                             width*3 );
765
766         gdk_gc_unref( gc );
767         return true;
768     }
769
770     // Create picture image
771
772     GdkImage *data_image =
773         gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
774
775     // Create mask image
776
777     GdkImage *mask_image = NULL;
778
779     if (image.HasMask())
780     {
781         unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
782
783         mask_image =  gdk_image_new_bitmap( visual, mask_data, width, height );
784
785         wxMask *mask = new wxMask();
786         mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
787
788         SetMask( mask );
789     }
790
791     // Render
792
793     enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
794     byte_order b_o = RGB;
795
796     if (bpp > 8)
797     {
798         if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask))      b_o = RGB;
799         else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask))  b_o = RBG;
800         else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask))   b_o = BRG;
801         else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
802         else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask))   b_o = GRB;
803         else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask))  b_o = GBR;
804     }
805
806     int r_mask = image.GetMaskRed();
807     int g_mask = image.GetMaskGreen();
808     int b_mask = image.GetMaskBlue();
809
810     unsigned char* data = image.GetData();
811
812     int index = 0;
813     for (int y = 0; y < height; y++)
814     {
815         for (int x = 0; x < width; x++)
816         {
817             int r = data[index];
818             index++;
819             int g = data[index];
820             index++;
821             int b = data[index];
822             index++;
823
824             if (image.HasMask())
825             {
826                 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
827                     gdk_image_put_pixel( mask_image, x, y, 1 );
828                 else
829                     gdk_image_put_pixel( mask_image, x, y, 0 );
830             }
831
832             switch (bpp)
833             {
834                 case 8:
835                 {
836                     int pixel = -1;
837                     if (wxTheApp->m_colorCube)
838                     {
839                         pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
840                     }
841                     else
842                     {
843                         GdkColormap *cmap = gtk_widget_get_default_colormap();
844                         GdkColor *colors = cmap->colors;
845                         int max = 3 * (65536);
846
847                         for (int i = 0; i < cmap->size; i++)
848                         {
849                             int rdiff = (r << 8) - colors[i].red;
850                             int gdiff = (g << 8) - colors[i].green;
851                             int bdiff = (b << 8) - colors[i].blue;
852                             int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
853                             if (sum < max) { pixel = i; max = sum; }
854                         }
855                     }
856
857                     gdk_image_put_pixel( data_image, x, y, pixel );
858
859                     break;
860                 }
861                 case 12:  // SGI only
862                 {
863                     guint32 pixel = 0;
864                     switch (b_o)
865                     {
866                         case RGB: pixel = ((r & 0xf0) << 4) | (g & 0xf0) | ((b & 0xf0) >> 4); break;
867                         case RBG: pixel = ((r & 0xf0) << 4) | (b & 0xf0) | ((g & 0xf0) >> 4); break;
868                         case GRB: pixel = ((g & 0xf0) << 4) | (r & 0xf0) | ((b & 0xf0) >> 4); break;
869                         case GBR: pixel = ((g & 0xf0) << 4) | (b & 0xf0) | ((r & 0xf0) >> 4); break;
870                         case BRG: pixel = ((b & 0xf0) << 4) | (r & 0xf0) | ((g & 0xf0) >> 4); break;
871                         case BGR: pixel = ((b & 0xf0) << 4) | (g & 0xf0) | ((r & 0xf0) >> 4); break;
872                     }
873                     gdk_image_put_pixel( data_image, x, y, pixel );
874                     break;
875                 }
876                 case 15:
877                 {
878                     guint32 pixel = 0;
879                     switch (b_o)
880                     {
881                         case RGB: pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
882                         case RBG: pixel = ((r & 0xf8) << 7) | ((b & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
883                         case GRB: pixel = ((g & 0xf8) << 7) | ((r & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
884                         case GBR: pixel = ((g & 0xf8) << 7) | ((b & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
885                         case BRG: pixel = ((b & 0xf8) << 7) | ((r & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
886                         case BGR: pixel = ((b & 0xf8) << 7) | ((g & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
887                     }
888                     gdk_image_put_pixel( data_image, x, y, pixel );
889                     break;
890                 }
891                 case 16:
892                 {
893                     // I actually don't know if for 16-bit displays, it is alway the green
894                     // component or the second component which has 6 bits.
895                     guint32 pixel = 0;
896                     switch (b_o)
897                     {
898                         case RGB: pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
899                         case RBG: pixel = ((r & 0xf8) << 8) | ((b & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
900                         case GRB: pixel = ((g & 0xf8) << 8) | ((r & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
901                         case GBR: pixel = ((g & 0xf8) << 8) | ((b & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
902                         case BRG: pixel = ((b & 0xf8) << 8) | ((r & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
903                         case BGR: pixel = ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
904                     }
905                     gdk_image_put_pixel( data_image, x, y, pixel );
906                     break;
907                 }
908                 case 32:
909                 case 24:
910                 {
911                     guint32 pixel = 0;
912                     switch (b_o)
913                     {
914                         case RGB: pixel = (r << 16) | (g << 8) | b; break;
915                         case RBG: pixel = (r << 16) | (b << 8) | g; break;
916                         case BRG: pixel = (b << 16) | (r << 8) | g; break;
917                         case BGR: pixel = (b << 16) | (g << 8) | r; break;
918                         case GRB: pixel = (g << 16) | (r << 8) | b; break;
919                         case GBR: pixel = (g << 16) | (b << 8) | r; break;
920                     }
921                     gdk_image_put_pixel( data_image, x, y, pixel );
922                     break;
923                 }
924                 default: break;
925             }
926         } // for
927     }  // for
928
929     // Blit picture
930
931     GdkGC *data_gc = gdk_gc_new( GetPixmap() );
932
933     gdk_draw_image( GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
934
935     gdk_image_destroy( data_image );
936     gdk_gc_unref( data_gc );
937
938     // Blit mask
939
940     if (image.HasMask())
941     {
942         GdkGC *mask_gc = gdk_gc_new( GetMask()->GetBitmap() );
943
944         gdk_draw_image( GetMask()->GetBitmap(), mask_gc, mask_image, 0, 0, 0, 0, width, height );
945
946         gdk_image_destroy( mask_image );
947         gdk_gc_unref( mask_gc );
948     }
949
950     return true;
951 }
952
953 wxImage wxBitmap::ConvertToImage() const
954 {
955     wxImage image;
956
957     wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
958
959     image.Create(GetWidth(), GetHeight());
960     unsigned char *data = image.GetData();
961
962     if (!data)
963     {
964         wxFAIL_MSG( wxT("couldn't create image") );
965         return wxNullImage;
966     }
967
968     // the colour used as transparent one in wxImage and the one it is
969     // replaced with when it really occurs in the bitmap
970     static const int MASK_RED = 1;
971     static const int MASK_GREEN = 2;
972     static const int MASK_BLUE = 3;
973     static const int MASK_BLUE_REPLACEMENT = 2;
974
975     GdkImage *gdk_image = NULL;
976
977     if (HasPixmap())
978     {
979         gdk_image = gdk_image_get( GetPixmap(),
980                                     0, 0,
981                                     GetWidth(), GetHeight() );
982     }
983     else if (GetBitmap())
984     {
985         gdk_image = gdk_image_get( GetBitmap(),
986                                     0, 0,
987                                     GetWidth(), GetHeight() );
988     }
989     else
990     {
991         wxFAIL_MSG( wxT("Ill-formed bitmap") );
992     }
993
994     wxCHECK_MSG( gdk_image, wxNullImage, wxT("couldn't create image") );
995
996     GdkImage *gdk_image_mask = NULL;
997     if (GetMask())
998     {
999         gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
1000                                         0, 0,
1001                                         GetWidth(), GetHeight() );
1002
1003         image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
1004     }
1005
1006     int bpp = -1;
1007     int red_shift_right = 0;
1008     int green_shift_right = 0;
1009     int blue_shift_right = 0;
1010     int red_shift_left = 0;
1011     int green_shift_left = 0;
1012     int blue_shift_left = 0;
1013     bool use_shift = false;
1014
1015     if (GetPixmap())
1016     {
1017         GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
1018         if (visual == NULL)
1019             visual = wxTheApp->GetGdkVisual();
1020
1021         bpp = visual->depth;
1022         if (bpp == 16)
1023             bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
1024         red_shift_right = visual->red_shift;
1025         red_shift_left = 8-visual->red_prec;
1026         green_shift_right = visual->green_shift;
1027         green_shift_left = 8-visual->green_prec;
1028         blue_shift_right = visual->blue_shift;
1029         blue_shift_left = 8-visual->blue_prec;
1030
1031         use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
1032     }
1033     if (GetBitmap())
1034     {
1035         bpp = 1;
1036     }
1037
1038
1039     GdkColormap *cmap = gtk_widget_get_default_colormap();
1040
1041     long pos = 0;
1042     for (int j = 0; j < GetHeight(); j++)
1043     {
1044         for (int i = 0; i < GetWidth(); i++)
1045         {
1046             wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
1047             if (bpp == 1)
1048             {
1049                 if (pixel == 0)
1050                 {
1051                     data[pos]   = 0;
1052                     data[pos+1] = 0;
1053                     data[pos+2] = 0;
1054                 }
1055                 else
1056                 {
1057                     data[pos]   = 255;
1058                     data[pos+1] = 255;
1059                     data[pos+2] = 255;
1060                 }
1061             }
1062             else if (use_shift)
1063             {
1064                 data[pos] =   (pixel >> red_shift_right)   << red_shift_left;
1065                 data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
1066                 data[pos+2] = (pixel >> blue_shift_right)  << blue_shift_left;
1067             }
1068             else if (cmap->colors)
1069             {
1070                 data[pos] =   cmap->colors[pixel].red   >> 8;
1071                 data[pos+1] = cmap->colors[pixel].green >> 8;
1072                 data[pos+2] = cmap->colors[pixel].blue  >> 8;
1073             }
1074             else
1075             {
1076                 wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
1077             }
1078
1079             if (gdk_image_mask)
1080             {
1081                 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1082                 if (mask_pixel == 0)
1083                 {
1084                     data[pos] = MASK_RED;
1085                     data[pos+1] = MASK_GREEN;
1086                     data[pos+2] = MASK_BLUE;
1087                 }
1088                 else if ( data[pos] == MASK_RED &&
1089                             data[pos+1] == MASK_GREEN &&
1090                                 data[pos+2] == MASK_BLUE )
1091                 {
1092                     data[pos+2] = MASK_BLUE_REPLACEMENT;
1093                 }
1094             }
1095
1096             pos += 3;
1097         }
1098     }
1099
1100     gdk_image_destroy( gdk_image );
1101     if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1102
1103     return image;
1104 }
1105
1106 wxBitmap::wxBitmap( const wxString &filename, wxBitmapType type )
1107 {
1108     LoadFile( filename, type );
1109 }
1110
1111 wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
1112 {
1113     if ( width > 0 && height > 0 )
1114     {
1115         m_refData = new wxBitmapRefData();
1116
1117         M_BMPDATA->m_mask = NULL;
1118         M_BMPDATA->m_bitmap = gdk_bitmap_create_from_data
1119                               (
1120                                 wxGetRootWindow()->window,
1121                                 (gchar *) bits,
1122                                 width,
1123                                 height
1124                               );
1125         M_BMPDATA->m_width = width;
1126         M_BMPDATA->m_height = height;
1127         M_BMPDATA->m_bpp = 1;
1128
1129         wxASSERT_MSG( M_BMPDATA->m_bitmap, wxT("couldn't create bitmap") );
1130     }
1131 }
1132
1133 wxBitmap::~wxBitmap()
1134 {
1135 }
1136
1137 int wxBitmap::GetHeight() const
1138 {
1139     wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1140
1141     return M_BMPDATA->m_height;
1142 }
1143
1144 int wxBitmap::GetWidth() const
1145 {
1146     wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1147
1148     return M_BMPDATA->m_width;
1149 }
1150
1151 int wxBitmap::GetDepth() const
1152 {
1153     wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
1154
1155     return M_BMPDATA->m_bpp;
1156 }
1157
1158 wxMask *wxBitmap::GetMask() const
1159 {
1160     wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
1161
1162     return M_BMPDATA->m_mask;
1163 }
1164
1165 void wxBitmap::SetMask( wxMask *mask )
1166 {
1167     wxCHECK_RET( Ok(), wxT("invalid bitmap") );
1168
1169     AllocExclusive();
1170     if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
1171
1172     M_BMPDATA->m_mask = mask;
1173 }
1174
1175 bool wxBitmap::CopyFromIcon(const wxIcon& icon)
1176 {
1177     *this = icon;
1178     return true;
1179 }
1180
1181 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
1182 {
1183     wxCHECK_MSG( Ok() &&
1184                  (rect.x >= 0) && (rect.y >= 0) &&
1185                  (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
1186                  wxNullBitmap, wxT("invalid bitmap or bitmap region") );
1187
1188     wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
1189     wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
1190
1191     if (ret.GetPixmap())
1192     {
1193         GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
1194         gdk_draw_pixmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1195         gdk_gc_destroy( gc );
1196     }
1197     else
1198     {
1199         GdkGC *gc = gdk_gc_new( ret.GetBitmap() );
1200         GdkColor col;
1201         col.pixel = 0xFFFFFF;
1202         gdk_gc_set_foreground( gc, &col );
1203         col.pixel = 0;
1204         gdk_gc_set_background( gc, &col );
1205         gdk_wx_draw_bitmap( ret.GetBitmap(), gc, GetBitmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
1206         gdk_gc_destroy( gc );
1207     }
1208
1209     if (GetMask())
1210     {
1211         wxMask *mask = new wxMask;
1212         mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
1213
1214         GdkGC *gc = gdk_gc_new( mask->m_bitmap );
1215         GdkColor col;
1216         col.pixel = 0xFFFFFF;
1217         gdk_gc_set_foreground( gc, &col );
1218         col.pixel = 0;
1219         gdk_gc_set_background( gc, &col );
1220         gdk_wx_draw_bitmap( mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, rect.x, rect.y, 0, 0, rect.width, rect.height );
1221         gdk_gc_destroy( gc );
1222
1223         ret.SetMask( mask );
1224     }
1225
1226     return ret;
1227 }
1228
1229 bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
1230 {
1231     wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1232
1233     // Try to save the bitmap via wxImage handlers:
1234     {
1235         wxImage image = ConvertToImage();
1236         if (image.Ok()) return image.SaveFile( name, type );
1237     }
1238
1239     return false;
1240 }
1241
1242 bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
1243 {
1244     UnRef();
1245
1246     if (!wxFileExists(name))
1247         return false;
1248
1249     GdkVisual *visual = wxTheApp->GetGdkVisual();
1250
1251     if (type == wxBITMAP_TYPE_XPM)
1252     {
1253         m_refData = new wxBitmapRefData();
1254
1255         GdkBitmap *mask = NULL;
1256
1257         M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm
1258                               (
1259                                 wxGetRootWindow()->window,
1260                                 &mask,
1261                                 NULL,
1262                                 name.fn_str()
1263                               );
1264
1265         if (mask)
1266         {
1267            M_BMPDATA->m_mask = new wxMask();
1268            M_BMPDATA->m_mask->m_bitmap = mask;
1269         }
1270
1271         gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
1272
1273         M_BMPDATA->m_bpp = visual->depth;
1274     }
1275     else // try if wxImage can load it
1276     {
1277         wxImage image;
1278         if ( !image.LoadFile( name, type ) || !image.Ok() )
1279             return false;
1280
1281         *this = wxBitmap(image);
1282     }
1283
1284     return true;
1285 }
1286
1287 #if wxUSE_PALETTE
1288 wxPalette *wxBitmap::GetPalette() const
1289 {
1290     if (!Ok())
1291         return NULL;
1292
1293     return M_BMPDATA->m_palette;
1294 }
1295
1296 void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
1297 {
1298     // TODO
1299 }
1300 #endif // wxUSE_PALETTE
1301
1302 void wxBitmap::SetHeight( int height )
1303 {
1304     AllocExclusive();
1305     M_BMPDATA->m_height = height;
1306 }
1307
1308 void wxBitmap::SetWidth( int width )
1309 {
1310     AllocExclusive();
1311     M_BMPDATA->m_width = width;
1312 }
1313
1314 void wxBitmap::SetDepth( int depth )
1315 {
1316     AllocExclusive();
1317     M_BMPDATA->m_bpp = depth;
1318 }
1319
1320 void wxBitmap::SetPixmap( GdkPixmap *pixmap )
1321 {
1322     if (!m_refData)
1323         m_refData = new wxBitmapRefData();
1324
1325     M_BMPDATA->m_pixmap = pixmap;
1326 }
1327
1328 void wxBitmap::SetBitmap( GdkPixmap *bitmap )
1329 {
1330     if (!m_refData)
1331         m_refData = new wxBitmapRefData();
1332
1333     M_BMPDATA->m_bitmap = bitmap;
1334 }
1335
1336 GdkPixmap *wxBitmap::GetPixmap() const
1337 {
1338     wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
1339
1340     return M_BMPDATA->m_pixmap;
1341 }
1342
1343 bool wxBitmap::HasPixmap() const
1344 {
1345     wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
1346
1347     return M_BMPDATA->m_pixmap != NULL;
1348 }
1349
1350 GdkBitmap *wxBitmap::GetBitmap() const
1351 {
1352     wxCHECK_MSG( Ok(), NULL, wxT("invalid bitmap") );
1353
1354     return M_BMPDATA->m_bitmap;
1355 }
1356
1357 void *wxBitmap::GetRawData(wxPixelDataBase& WXUNUSED(data), int WXUNUSED(bpp))
1358 {
1359     return NULL;
1360 }
1361
1362 void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
1363 {
1364 }
1365
1366 bool wxBitmap::HasAlpha() const
1367 {
1368     return false;
1369 }
1370
1371 /* static */ void wxBitmap::InitStandardHandlers()
1372 {
1373     // TODO: Insert handler based on GdkPixbufs handler later
1374 }