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