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