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