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