Stripped out miscellaneous Motif/Xt-specific code
[wxWidgets.git] / src / x11 / bitmap.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: bitmap.cpp
3 // Purpose: wxBitmap
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "bitmap.h"
14 #endif
15
16 #include "wx/setup.h"
17 #include "wx/utils.h"
18 #include "wx/palette.h"
19 #include "wx/bitmap.h"
20 #include "wx/icon.h"
21 #include "wx/log.h"
22 #include "wx/control.h"
23 #include "wx/dcmemory.h"
24 #include "wx/image.h"
25 #include "wx/app.h"
26
27 #ifdef __VMS__
28 #pragma message disable nosimpint
29 #endif
30 #ifdef __VMS__
31 #pragma message enable nosimpint
32 #endif
33
34 #include "wx/x11/private.h"
35
36 #if wxHAVE_LIB_XPM
37 #include <X11/xpm.h>
38 #endif
39 #include <math.h>
40
41
42 IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
43 IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
44
45 wxBitmapRefData::wxBitmapRefData()
46 {
47 m_ok = FALSE;
48 m_width = 0;
49 m_height = 0;
50 m_depth = 0;
51 m_quality = 0;
52 m_numColors = 0;
53 m_bitmapMask = NULL;
54
55 m_pixmap = (WXPixmap) 0;
56 m_display = (WXDisplay*) 0;
57
58 m_freePixmap = TRUE; //TODO: necessary?
59 m_freeColors = (unsigned long*) 0;
60 m_freeColorsCount = 0;
61 }
62
63 wxBitmapRefData::~wxBitmapRefData()
64 {
65 if (m_pixmap && m_freePixmap)
66 XFreePixmap ((Display*) m_display, (Pixmap) m_pixmap);
67
68 if (m_freeColors)
69 {
70 int screen = DefaultScreen((Display*) m_display);
71 Colormap cmp = DefaultColormap((Display*) m_display,screen);
72 long llp;
73 for(llp = 0;llp < m_freeColorsCount;llp++)
74 XFreeColors((Display*) m_display, cmp, &m_freeColors[llp], 1, 0L);
75 delete m_freeColors;
76 };
77
78 if (m_bitmapMask)
79 delete m_bitmapMask;
80 m_bitmapMask = NULL;
81 }
82
83 wxList wxBitmap::sm_handlers;
84
85 #define M_BMPDATA ((wxBitmapRefData *)m_refData)
86
87 wxBitmap::wxBitmap()
88 {
89 m_refData = NULL;
90 }
91
92 wxBitmap::~wxBitmap()
93 {
94 }
95
96 wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
97 {
98 m_refData = new wxBitmapRefData;
99
100 (void) Create((void*) bits, wxBITMAP_TYPE_XBM_DATA, width, height, depth);
101 }
102
103 wxBitmap::wxBitmap(int w, int h, int d)
104 {
105 (void)Create(w, h, d);
106 }
107
108 wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth)
109 {
110 (void) Create(data, type, width, height, depth);
111 }
112
113 wxBitmap::wxBitmap(const wxString& filename, long type)
114 {
115 LoadFile(filename, (int)type);
116 }
117
118 wxBitmap::wxBitmap(char **data)
119 {
120 (void) Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0);
121 }
122
123 bool wxBitmap::Create(int w, int h, int d)
124 {
125 UnRef();
126
127 m_refData = new wxBitmapRefData;
128
129 if (d < 1)
130 d = wxDisplayDepth();
131
132 M_BITMAPDATA->m_width = w;
133 M_BITMAPDATA->m_height = h;
134 M_BITMAPDATA->m_depth = d;
135 M_BITMAPDATA->m_freePixmap = TRUE;
136
137 Display *dpy = (Display*) wxGetDisplay();
138
139 M_BITMAPDATA->m_display = dpy; /* MATTHEW: [4] Remember the display */
140
141 M_BITMAPDATA->m_pixmap = (WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
142 w, h, d);
143
144 M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_pixmap != (WXPixmap) 0) ;
145 return M_BITMAPDATA->m_ok;
146 }
147
148 bool wxBitmap::LoadFile(const wxString& filename, long type)
149 {
150 UnRef();
151
152 m_refData = new wxBitmapRefData;
153
154 wxBitmapHandler *handler = FindHandler(type);
155
156 if ( handler == NULL ) {
157 wxImage image;
158 if (!image.LoadFile( filename, type )) return FALSE;
159 if (image.Ok())
160 {
161 *this = image.ConvertToBitmap();
162 return TRUE;
163 }
164 else return FALSE;
165 }
166
167 return handler->LoadFile(this, filename, type, -1, -1);
168 }
169
170 bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
171 {
172 UnRef();
173
174 m_refData = new wxBitmapRefData;
175
176 wxBitmapHandler *handler = FindHandler(type);
177
178 if ( handler == NULL ) {
179 wxLogWarning("no data bitmap handler for type %d defined.", type);
180
181 return FALSE;
182 }
183
184 return handler->Create(this, data, type, width, height, depth);
185 }
186
187 bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette)
188 {
189 wxBitmapHandler *handler = FindHandler(type);
190
191 if ( handler == NULL ) { // try wxImage
192 wxImage image( *this );
193 if (image.Ok()) return image.SaveFile( filename, type );
194 else return FALSE;
195 }
196
197 return handler->SaveFile(this, filename, type, palette);
198 }
199
200 void wxBitmap::SetWidth(int w)
201 {
202 if (!M_BITMAPDATA)
203 m_refData = new wxBitmapRefData;
204
205 M_BITMAPDATA->m_width = w;
206 }
207
208 void wxBitmap::SetHeight(int h)
209 {
210 if (!M_BITMAPDATA)
211 m_refData = new wxBitmapRefData;
212
213 M_BITMAPDATA->m_height = h;
214 }
215
216 void wxBitmap::SetDepth(int d)
217 {
218 if (!M_BITMAPDATA)
219 m_refData = new wxBitmapRefData;
220
221 M_BITMAPDATA->m_depth = d;
222 }
223
224 void wxBitmap::SetQuality(int q)
225 {
226 if (!M_BITMAPDATA)
227 m_refData = new wxBitmapRefData;
228
229 M_BITMAPDATA->m_quality = q;
230 }
231
232 void wxBitmap::SetOk(bool isOk)
233 {
234 if (!M_BITMAPDATA)
235 m_refData = new wxBitmapRefData;
236
237 M_BITMAPDATA->m_ok = isOk;
238 }
239
240 void wxBitmap::SetPalette(const wxPalette& palette)
241 {
242 if (!M_BITMAPDATA)
243 m_refData = new wxBitmapRefData;
244
245 M_BITMAPDATA->m_bitmapPalette = palette ;
246 }
247
248 void wxBitmap::SetMask(wxMask *mask)
249 {
250 if (!M_BITMAPDATA)
251 m_refData = new wxBitmapRefData;
252
253 M_BITMAPDATA->m_bitmapMask = mask ;
254 }
255
256 wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
257 {
258 wxCHECK_MSG( Ok() &&
259 (rect.x >= 0) && (rect.y >= 0) &&
260 (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
261 wxNullBitmap, wxT("invalid bitmap or bitmap region") );
262
263 wxBitmap ret( rect.width, rect.height, 0 );
264 wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );
265
266 // The remaining still TODO
267 return ret;
268 }
269
270 void wxBitmap::AddHandler(wxBitmapHandler *handler)
271 {
272 sm_handlers.Append(handler);
273 }
274
275 void wxBitmap::InsertHandler(wxBitmapHandler *handler)
276 {
277 sm_handlers.Insert(handler);
278 }
279
280 bool wxBitmap::RemoveHandler(const wxString& name)
281 {
282 wxBitmapHandler *handler = FindHandler(name);
283 if ( handler )
284 {
285 sm_handlers.DeleteObject(handler);
286 return TRUE;
287 }
288 else
289 return FALSE;
290 }
291
292 wxBitmapHandler *wxBitmap::FindHandler(const wxString& name)
293 {
294 wxNode *node = sm_handlers.First();
295 while ( node )
296 {
297 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
298 if ( handler->GetName() == name )
299 return handler;
300 node = node->Next();
301 }
302 return NULL;
303 }
304
305 wxBitmapHandler *wxBitmap::FindHandler(const wxString& extension, long bitmapType)
306 {
307 wxNode *node = sm_handlers.First();
308 while ( node )
309 {
310 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
311 if ( handler->GetExtension() == extension &&
312 (bitmapType == -1 || handler->GetType() == bitmapType) )
313 return handler;
314 node = node->Next();
315 }
316 return NULL;
317 }
318
319 wxBitmapHandler *wxBitmap::FindHandler(long bitmapType)
320 {
321 wxNode *node = sm_handlers.First();
322 while ( node )
323 {
324 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
325 if (handler->GetType() == bitmapType)
326 return handler;
327 node = node->Next();
328 }
329 return NULL;
330 }
331
332 /*
333 * wxMask
334 */
335
336 wxMask::wxMask()
337 {
338 m_pixmap = (WXPixmap) 0;
339 }
340
341 // Construct a mask from a bitmap and a colour indicating
342 // the transparent area
343 wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour)
344 {
345 m_pixmap = (WXPixmap) 0;
346
347 Create(bitmap, colour);
348 }
349
350 // Construct a mask from a bitmap and a palette index indicating
351 // the transparent area
352 wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex)
353 {
354 m_pixmap = (WXPixmap) 0;
355
356 Create(bitmap, paletteIndex);
357 }
358
359 // Construct a mask from a mono bitmap (copies the bitmap).
360 wxMask::wxMask(const wxBitmap& bitmap)
361 {
362 m_pixmap = (WXPixmap) 0;
363
364 Create(bitmap);
365 }
366
367 wxMask::~wxMask()
368 {
369 // TODO: this may be the wrong display
370 if ( m_pixmap )
371 XFreePixmap ((Display*) wxGetDisplay(), (Pixmap) m_pixmap);
372 }
373
374 // Create a mask from a mono bitmap (copies the bitmap).
375 bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap))
376 {
377 // TODO
378 return FALSE;
379 }
380
381 // Create a mask from a bitmap and a palette index indicating
382 // the transparent area
383 bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap), int WXUNUSED(paletteIndex))
384 {
385 // TODO
386 return FALSE;
387 }
388
389 // Create a mask from a bitmap and a colour indicating
390 // the transparent area
391 bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap), const wxColour& WXUNUSED(colour))
392 {
393 // TODO
394 return FALSE;
395 }
396
397 /*
398 * wxBitmapHandler
399 */
400
401 IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)
402
403 bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap), void *WXUNUSED(data), long WXUNUSED(type),
404 int WXUNUSED(width), int WXUNUSED(height), int WXUNUSED(depth))
405 {
406 return FALSE;
407 }
408
409 bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), long WXUNUSED(type),
410 int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight))
411 {
412 return FALSE;
413 }
414
415 bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), int WXUNUSED(type),
416 const wxPalette *WXUNUSED(palette))
417 {
418 return FALSE;
419 }
420
421 /*
422 * Standard handlers
423 */
424
425 class WXDLLEXPORT wxXBMFileHandler: public wxBitmapHandler
426 {
427 DECLARE_DYNAMIC_CLASS(wxXBMFileHandler)
428 public:
429 inline wxXBMFileHandler()
430 {
431 m_name = "XBM file";
432 m_extension = "xbm";
433 m_type = wxBITMAP_TYPE_XBM;
434 };
435
436 virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
437 int desiredWidth, int desiredHeight);
438 };
439 IMPLEMENT_DYNAMIC_CLASS(wxXBMFileHandler, wxBitmapHandler)
440
441 bool wxXBMFileHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long WXUNUSED(flags),
442 int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight))
443 {
444 M_BITMAPHANDLERDATA->m_freePixmap = TRUE;
445
446 int hotX, hotY;
447 unsigned int w, h;
448 Pixmap pixmap;
449
450 Display *dpy = (Display*) wxGetDisplay();
451 M_BITMAPDATA->m_display = (WXDisplay*) dpy;
452
453 int value = XReadBitmapFile (dpy, RootWindow (dpy, DefaultScreen (dpy)),
454 (char*) (const char*) name, &w, &h, &pixmap, &hotX, &hotY);
455 M_BITMAPHANDLERDATA->m_width = w;
456 M_BITMAPHANDLERDATA->m_height = h;
457 M_BITMAPHANDLERDATA->m_depth = 1;
458 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) pixmap;
459
460 if ((value == BitmapFileInvalid) ||
461 (value == BitmapOpenFailed) ||
462 (value == BitmapNoMemory))
463 {
464 M_BITMAPHANDLERDATA->m_ok = FALSE;
465 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) 0;
466 }
467 else
468 M_BITMAPHANDLERDATA->m_ok = TRUE;
469
470 return M_BITMAPHANDLERDATA->m_ok ;
471 }
472
473 class WXDLLEXPORT wxXBMDataHandler: public wxBitmapHandler
474 {
475 DECLARE_DYNAMIC_CLASS(wxXBMDataHandler)
476 public:
477 inline wxXBMDataHandler()
478 {
479 m_name = "XBM data";
480 m_extension = "xbm";
481 m_type = wxBITMAP_TYPE_XBM_DATA;
482 };
483
484 virtual bool Create(wxBitmap *bitmap, void *data, long flags, int width, int height, int depth = 1);
485 };
486 IMPLEMENT_DYNAMIC_CLASS(wxXBMDataHandler, wxBitmapHandler)
487
488 bool wxXBMDataHandler::Create( wxBitmap *bitmap, void *data, long WXUNUSED(flags),
489 int width, int height, int WXUNUSED(depth))
490 {
491 M_BITMAPHANDLERDATA->m_width = width;
492 M_BITMAPHANDLERDATA->m_height = height;
493 M_BITMAPHANDLERDATA->m_depth = 1;
494 M_BITMAPHANDLERDATA->m_freePixmap = TRUE;
495
496 Display *dpy = (Display*) wxGetDisplay();
497 M_BITMAPHANDLERDATA->m_display = (WXDisplay*) dpy;
498
499 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) XCreateBitmapFromData (dpy, RootWindow (dpy, DefaultScreen (dpy)), (char*) data, width, height);
500 M_BITMAPHANDLERDATA->m_ok = (M_BITMAPHANDLERDATA->m_pixmap != (WXPixmap) 0) ;
501
502 return TRUE;
503 }
504
505 #if wxHAVE_LIB_XPM
506 class WXDLLEXPORT wxXPMFileHandler: public wxBitmapHandler
507 {
508 DECLARE_DYNAMIC_CLASS(wxXPMFileHandler)
509 public:
510 inline wxXPMFileHandler()
511 {
512 m_name = "XPM file";
513 m_extension = "xpm";
514 m_type = wxBITMAP_TYPE_XPM;
515 };
516
517 virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags,
518 int desiredWidth, int desiredHeight);
519 virtual bool SaveFile(wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette = NULL);
520 };
521
522 IMPLEMENT_DYNAMIC_CLASS(wxXPMFileHandler, wxBitmapHandler)
523
524 bool wxXPMFileHandler::LoadFile( wxBitmap *bitmap, const wxString& name, long WXUNUSED(flags),
525 int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight) )
526 {
527 Display *dpy = (Display*) wxGetDisplay();
528 M_BITMAPHANDLERDATA->m_display = (WXDisplay*) dpy;
529
530 XpmAttributes xpmAttr;
531 Pixmap pixmap;
532 Pixmap mask = 0;
533
534 M_BITMAPHANDLERDATA->m_ok = FALSE;
535 xpmAttr.valuemask = XpmReturnInfos | XpmCloseness;
536 xpmAttr.closeness = 40000;
537 int errorStatus = XpmReadFileToPixmap(dpy,
538 RootWindow(dpy, DefaultScreen(dpy)), (char*) (const char*) name,
539 &pixmap, &mask, &xpmAttr);
540
541 if (errorStatus == XpmSuccess)
542 {
543 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) pixmap;
544 if ( mask )
545 {
546 M_BITMAPHANDLERDATA->m_bitmapMask = new wxMask;
547 M_BITMAPHANDLERDATA->m_bitmapMask->SetPixmap((WXPixmap) mask);
548 }
549
550 unsigned int depthRet;
551 int xRet, yRet;
552 unsigned int widthRet, heightRet, borderWidthRet;
553 Window rootWindowRet;
554 XGetGeometry(dpy, pixmap, &rootWindowRet, &xRet, &yRet,
555 &widthRet, &heightRet, &borderWidthRet, &depthRet);
556
557 M_BITMAPHANDLERDATA->m_width = xpmAttr.width;
558 M_BITMAPHANDLERDATA->m_height = xpmAttr.height;
559
560 /*
561 if ( xpmAttr.npixels > 2 )
562 {
563 M_BITMAPHANDLERDATA->m_depth = 8; // TODO: next time not just a guess :-) ...
564 } else
565 {
566 M_BITMAPHANDLERDATA->m_depth = 1; // mono
567 }
568 */
569
570 M_BITMAPHANDLERDATA->m_depth = depthRet;
571
572 M_BITMAPHANDLERDATA->m_numColors = xpmAttr.npixels;
573
574 XpmFreeAttributes(&xpmAttr);
575
576 M_BITMAPHANDLERDATA->m_ok = TRUE;
577 return TRUE;
578 } else
579 {
580 // XpmDebugError(errorStatus, name);
581 M_BITMAPHANDLERDATA->m_ok = FALSE;
582 return FALSE;
583 }
584 }
585
586 bool wxXPMFileHandler::SaveFile( wxBitmap *bitmap, const wxString& name, int WXUNUSED(type),
587 const wxPalette *WXUNUSED(palette))
588 {
589 if (M_BITMAPHANDLERDATA->m_ok && M_BITMAPHANDLERDATA->m_pixmap)
590 {
591 Display *dpy = (Display*) M_BITMAPHANDLERDATA->m_display;
592 int errorStatus = XpmWriteFileFromPixmap(dpy, (char*) (const char*) name,
593 (Pixmap) M_BITMAPHANDLERDATA->m_pixmap,
594 (M_BITMAPHANDLERDATA->m_bitmapMask ? (Pixmap) M_BITMAPHANDLERDATA->m_bitmapMask->GetPixmap() : (Pixmap) 0),
595 (XpmAttributes *) NULL);
596 if (errorStatus == XpmSuccess)
597 return TRUE;
598 else
599 return FALSE;
600 }
601 else
602 return FALSE;
603 }
604
605 class WXDLLEXPORT wxXPMDataHandler: public wxBitmapHandler
606 {
607 DECLARE_DYNAMIC_CLASS(wxXPMDataHandler)
608 public:
609 inline wxXPMDataHandler()
610 {
611 m_name = "XPM data";
612 m_extension = "xpm";
613 m_type = wxBITMAP_TYPE_XPM_DATA;
614 };
615
616 virtual bool Create(wxBitmap *bitmap, void *data, long flags, int width, int height, int depth = 1);
617 };
618 IMPLEMENT_DYNAMIC_CLASS(wxXPMDataHandler, wxBitmapHandler)
619
620 bool wxXPMDataHandler::Create( wxBitmap *bitmap, void *data, long WXUNUSED(flags),
621 int width, int height, int WXUNUSED(depth))
622 {
623 M_BITMAPHANDLERDATA->m_width = width;
624 M_BITMAPHANDLERDATA->m_height = height;
625 M_BITMAPHANDLERDATA->m_depth = 1;
626 M_BITMAPHANDLERDATA->m_freePixmap = TRUE;
627
628 Display *dpy = (Display*) wxGetDisplay();
629 M_BITMAPHANDLERDATA->m_display = (WXDisplay*) dpy;
630
631 XpmAttributes xpmAttr;
632
633 xpmAttr.valuemask = XpmReturnInfos; /* nothing yet, but get infos back */
634
635 XpmColorSymbol symbolicColors[4];
636 if (sg_Control && sg_Control->GetMainWidget())
637 {
638 symbolicColors[0].name = "foreground";
639 symbolicColors[0].value = NULL;
640 symbolicColors[1].name = "background";
641 symbolicColors[1].value = NULL;
642 XtVaGetValues((Widget) sg_Control->GetMainWidget(),
643 XmNforeground, &symbolicColors[0].pixel,
644 XmNbackground, &symbolicColors[1].pixel,NULL);
645 xpmAttr.numsymbols = 2;
646 xpmAttr.colorsymbols = symbolicColors;
647 xpmAttr.valuemask |= XpmColorSymbols; // add flag
648 }
649
650 Pixmap pixmap;
651 Pixmap mask = 0;
652 int ErrorStatus = XpmCreatePixmapFromData(dpy, RootWindow(dpy, DefaultScreen(dpy)),
653 (char**) data, &pixmap, &mask, &xpmAttr);
654 if (ErrorStatus == XpmSuccess)
655 {
656 // Set attributes
657 M_BITMAPHANDLERDATA->m_width = xpmAttr.width;
658 M_BITMAPHANDLERDATA->m_height = xpmAttr.height;
659
660 unsigned int depthRet;
661 int xRet, yRet;
662 unsigned int widthRet, heightRet, borderWidthRet;
663 Window rootWindowRet;
664 XGetGeometry(dpy, pixmap, &rootWindowRet, &xRet, &yRet,
665 &widthRet, &heightRet, &borderWidthRet, &depthRet);
666
667 /*
668 if ( xpmAttr.npixels > 2 )
669 {
670 M_BITMAPHANDLERDATA->m_depth = 8; // next time not just a guess :-) ...
671 } else
672 {
673 M_BITMAPHANDLERDATA->m_depth = 1; // mono
674 }
675 */
676
677 M_BITMAPHANDLERDATA->m_depth = depthRet;
678
679 M_BITMAPHANDLERDATA->m_numColors = xpmAttr.npixels;
680 XpmFreeAttributes(&xpmAttr);
681 M_BITMAPHANDLERDATA->m_ok = TRUE;
682 M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) pixmap;
683 if ( mask )
684 {
685 M_BITMAPHANDLERDATA->m_bitmapMask = new wxMask;
686 M_BITMAPHANDLERDATA->m_bitmapMask->SetPixmap((WXPixmap) mask);
687 }
688 }
689 else
690 {
691 // XpmDebugError(ErrorStatus, NULL);
692 M_BITMAPHANDLERDATA->m_ok = FALSE;
693 }
694 return M_BITMAPHANDLERDATA->m_ok ;
695 }
696
697 #endif // wxHAVE_LIB_XPM
698
699 void wxBitmap::CleanUpHandlers()
700 {
701 wxNode *node = sm_handlers.First();
702 while ( node )
703 {
704 wxBitmapHandler *handler = (wxBitmapHandler *)node->Data();
705 wxNode *next = node->Next();
706 delete handler;
707 delete node;
708 node = next;
709 }
710 }
711
712 void wxBitmap::InitStandardHandlers()
713 {
714 // Initialize all standard bitmap or derived class handlers here.
715 AddHandler(new wxXBMFileHandler);
716 AddHandler(new wxXBMDataHandler);
717
718 // XPM is considered standard for Motif, although it can be omitted if
719 // libXpm is not installed
720 #if wxHAVE_LIB_XPM
721 AddHandler(new wxXPMFileHandler);
722 AddHandler(new wxXPMDataHandler);
723 #endif // wxHAVE_LIB_XPM
724 }
725
726 // We may need this sometime...
727
728 /****************************************************************************
729
730 NAME
731 XCreateInsensitivePixmap - create a grayed-out copy of a pixmap
732
733 SYNOPSIS
734 Pixmap XCreateInsensitivePixmap( Display *display, Pixmap pixmap )
735
736 DESCRIPTION
737 This function creates a grayed-out copy of the argument pixmap, suitable
738 for use as a XmLabel's XmNlabelInsensitivePixmap resource.
739
740 RETURN VALUES
741 The return value is the new Pixmap id or zero on error. Errors include
742 a NULL display argument or an invalid Pixmap argument.
743
744 ERRORS
745 If one of the XLib functions fail, it will produce a X error. The
746 default X error handler prints a diagnostic and calls exit().
747
748 SEE ALSO
749 XCopyArea(3), XCreateBitmapFromData(3), XCreateGC(3), XCreatePixmap(3),
750 XFillRectangle(3), exit(2)
751
752 AUTHOR
753 John R Veregge - john@puente.jpl.nasa.gov
754 Advanced Engineering and Prototyping Group (AEG)
755 Information Systems Technology Section (395)
756 Jet Propulsion Lab - Calif Institute of Technology
757
758 *****************************************************************************/
759
760 Pixmap
761 XCreateInsensitivePixmap( Display *display, Pixmap pixmap )
762
763 {
764 static char stipple_data[] =
765 {
766 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
767 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
768 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA,
769 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA
770 };
771 GC gc;
772 Pixmap ipixmap, stipple;
773 unsigned width, height, depth;
774
775 Window window; /* These return values */
776 unsigned border; /* from XGetGeometry() */
777 int x, y; /* are not needed. */
778
779 ipixmap = 0;
780
781 if ( NULL == display || 0 == pixmap )
782 return ipixmap;
783
784 if ( 0 == XGetGeometry( display, pixmap, &window, &x, &y,
785 &width, &height, &border, &depth )
786 )
787 return ipixmap; /* BadDrawable: probably an invalid pixmap */
788
789 /* Get the stipple pixmap to be used to 'gray-out' the argument pixmap.
790 */
791 stipple = XCreateBitmapFromData( display, pixmap, stipple_data, 16, 16 );
792 if ( 0 != stipple )
793 {
794 gc = XCreateGC( display, pixmap, (XtGCMask)0, (XGCValues*)NULL );
795 if ( NULL != gc )
796 {
797 /* Create an identical copy of the argument pixmap.
798 */
799 ipixmap = XCreatePixmap( display, pixmap, width, height, depth );
800 if ( 0 != ipixmap )
801 {
802 /* Copy the argument pixmap into the new pixmap.
803 */
804 XCopyArea( display, pixmap, ipixmap,
805 gc, 0, 0, width, height, 0, 0 );
806
807 /* Refill the new pixmap using the stipple algorithm/pixmap.
808 */
809 XSetStipple( display, gc, stipple );
810 XSetFillStyle( display, gc, FillStippled );
811 XFillRectangle( display, ipixmap, gc, 0, 0, width, height );
812 }
813 XFreeGC( display, gc );
814 }
815 XFreePixmap( display, stipple );
816 }
817 return ipixmap;
818 }
819
820 // Creates a bitmap with transparent areas drawn in
821 // the given colour.
822 wxBitmap wxCreateMaskedBitmap(const wxBitmap& bitmap, wxColour& colour)
823 {
824 wxBitmap newBitmap(bitmap.GetWidth(),
825 bitmap.GetHeight(),
826 bitmap.GetDepth());
827 wxMemoryDC destDC;
828 wxMemoryDC srcDC;
829 srcDC.SelectObject(bitmap);
830 destDC.SelectObject(newBitmap);
831
832 wxBrush brush(colour, wxSOLID);
833 destDC.SetOptimization(FALSE);
834 destDC.SetBackground(brush);
835 destDC.Clear();
836 destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE);
837
838 return newBitmap;
839 }
840
841
842
843
844 //-----------------------------------------------------------------------------
845 // wxImage conversion routines
846 //-----------------------------------------------------------------------------
847
848 /*
849
850 Date: Wed, 05 Jan 2000 11:45:40 +0100
851 From: Frits Boel <boel@niob.knaw.nl>
852 To: julian.smart@ukonline.co.uk
853 Subject: Patch for Motif ConvertToBitmap
854
855 Hi Julian,
856
857 I've been working on a wxWin application for image processing. From the
858 beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
859 till I looked in the source code of image.cpp. I saw that converting a
860 wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
861 to the 256 colors of the palet. A very time-consuming piece of code!
862
863 Because I wanted a faster application, I've made a 'patch' for this. In
864 short: every pixel of the image is compared to a sorted list with
865 colors. If the color is found in the list, the palette entry is
866 returned; if the color is not found, the color palette is searched and
867 then the palette entry is returned and the color added to the sorted
868 list.
869
870 Maybe there is another method for this, namely changing the palette
871 itself (if the colors are known, as is the case with tiffs with a
872 colormap). I did not look at this, maybe someone else did?
873
874 The code of the patch is attached, have a look on it, and maybe you will
875 ship it with the next release of wxMotif?
876
877 Regards,
878
879 Frits Boel
880 Software engineer at Hubrecht Laboratory, The Netherlands.
881
882 */
883
884 class wxSearchColor
885 {
886 public:
887 wxSearchColor( void );
888 wxSearchColor( int size, XColor *colors );
889 ~wxSearchColor( void );
890
891 int SearchColor( int r, int g, int b );
892 private:
893 int AddColor( unsigned int value, int pos );
894
895 int size;
896 XColor *colors;
897 unsigned int *color;
898 int *entry;
899
900 int bottom;
901 int top;
902 };
903
904 wxSearchColor::wxSearchColor( void )
905 {
906 size = 0;
907 colors = (XColor*) NULL;
908 color = (unsigned int *) NULL;
909 entry = (int*) NULL;
910
911 bottom = 0;
912 top = 0;
913 }
914
915 wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
916 {
917 int i;
918 size = size_;
919 colors = colors_;
920 color = new unsigned int[size];
921 entry = new int [size];
922
923 for (i = 0; i < size; i++ ) {
924 entry[i] = -1;
925 }
926
927 bottom = top = ( size >> 1 );
928 }
929
930 wxSearchColor::~wxSearchColor( void )
931 {
932 if ( color ) delete color;
933 if ( entry ) delete entry;
934 }
935
936 int wxSearchColor::SearchColor( int r, int g, int b )
937 {
938 unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
939 int begin = bottom;
940 int end = top;
941 int middle = 0;
942
943 while ( begin <= end ) {
944
945 middle = ( begin + end ) >> 1;
946
947 if ( value == color[middle] ) {
948 return( entry[middle] );
949 } else if ( value < color[middle] ) {
950 end = middle - 1;
951 } else {
952 begin = middle + 1;
953 }
954
955 }
956
957 return AddColor( value, middle );
958 }
959
960 int wxSearchColor::AddColor( unsigned int value, int pos )
961 {
962 int i;
963 int pixel = -1;
964 int max = 3 * (65536);
965 for ( i = 0; i < 256; i++ ) {
966 int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
967 int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
968 int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
969 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
970 if (sum < max) { pixel = i; max = sum; }
971 }
972
973 if ( entry[pos] < 0 ) {
974 color[pos] = value;
975 entry[pos] = pixel;
976 } else if ( value < color[pos] ) {
977
978 if ( bottom > 0 ) {
979 for ( i = bottom; i < pos; i++ ) {
980 color[i-1] = color[i];
981 entry[i-1] = entry[i];
982 }
983 bottom--;
984 color[pos-1] = value;
985 entry[pos-1] = pixel;
986 } else if ( top < size-1 ) {
987 for ( i = top; i >= pos; i-- ) {
988 color[i+1] = color[i];
989 entry[i+1] = entry[i];
990 }
991 top++;
992 color[pos] = value;
993 entry[pos] = pixel;
994 }
995
996 } else {
997
998 if ( top < size-1 ) {
999 for ( i = top; i > pos; i-- ) {
1000 color[i+1] = color[i];
1001 entry[i+1] = entry[i];
1002 }
1003 top++;
1004 color[pos+1] = value;
1005 entry[pos+1] = pixel;
1006 } else if ( bottom > 0 ) {
1007 for ( i = bottom; i < pos; i++ ) {
1008 color[i-1] = color[i];
1009 entry[i-1] = entry[i];
1010 }
1011 bottom--;
1012 color[pos] = value;
1013 entry[pos] = pixel;
1014 }
1015
1016 }
1017
1018 return( pixel );
1019 }
1020
1021
1022 bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
1023 {
1024 wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
1025 wxCHECK_MSG( depth == -1, FALSE, wxT("invalid bitmap depth") )
1026
1027 m_refData = new wxBitmapRefData();
1028
1029 int width = image.GetWidth();
1030 int height = image.GetHeight();
1031
1032 SetHeight( height );
1033 SetWidth( width );
1034
1035 Display *dpy = (Display*) wxGetDisplay();
1036 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1037 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1038
1039 // Create image
1040
1041 XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
1042 data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
1043
1044 Create( width, height, bpp );
1045
1046 // Create mask
1047
1048 XImage *mask_image = (XImage*) NULL;
1049 if (image.HasMask())
1050 {
1051 mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 );
1052 mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height );
1053 }
1054
1055 // Retrieve depth info
1056
1057 XVisualInfo vinfo_template;
1058 XVisualInfo *vi;
1059
1060 vinfo_template.visual = vis;
1061 vinfo_template.visualid = XVisualIDFromVisual( vis );
1062 vinfo_template.depth = bpp;
1063 int nitem = 0;
1064
1065 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1066
1067 wxCHECK_MSG( vi, FALSE, wxT("no visual") );
1068
1069 XFree( vi );
1070
1071 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1072 if (bpp < 8) bpp = 8;
1073
1074 // Render
1075
1076 enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
1077 byte_order b_o = RGB;
1078
1079 if (bpp >= 24)
1080 {
1081 if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
1082 else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
1083 else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
1084 else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
1085 else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
1086 else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
1087 }
1088
1089 int r_mask = image.GetMaskRed();
1090 int g_mask = image.GetMaskGreen();
1091 int b_mask = image.GetMaskBlue();
1092
1093 XColor colors[256];
1094 if (bpp == 8)
1095 {
1096 Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
1097
1098 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1099 XQueryColors( dpy, cmap, colors, 256 );
1100 }
1101
1102 wxSearchColor scolor( 256, colors );
1103 unsigned char* data = image.GetData();
1104
1105 bool hasMask = image.HasMask();
1106
1107 int index = 0;
1108 for (int y = 0; y < height; y++)
1109 {
1110 for (int x = 0; x < width; x++)
1111 {
1112 int r = data[index];
1113 index++;
1114 int g = data[index];
1115 index++;
1116 int b = data[index];
1117 index++;
1118
1119 if (hasMask)
1120 {
1121 if ((r == r_mask) && (b == b_mask) && (g == g_mask))
1122 XPutPixel( mask_image, x, y, 0 );
1123 else
1124 XPutPixel( mask_image, x, y, 1 );
1125 }
1126
1127 switch (bpp)
1128 {
1129 case 8:
1130 {
1131 #if 0 // Old, slower code
1132 int pixel = -1;
1133 /*
1134 if (wxTheApp->m_colorCube)
1135 {
1136 pixel = wxTheApp->m_colorCube
1137 [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
1138 }
1139 else
1140 {
1141 */
1142 int max = 3 * (65536);
1143 for (int i = 0; i < 256; i++)
1144 {
1145 int rdiff = (r << 8) - colors[i].red;
1146 int gdiff = (g << 8) - colors[i].green;
1147 int bdiff = (b << 8) - colors[i].blue;
1148 int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
1149 if (sum < max) { pixel = i; max = sum; }
1150 }
1151 /*
1152 }
1153 */
1154 #endif
1155
1156 // And this is all to get the 'right' color...
1157 int pixel = scolor.SearchColor( r, g, b );
1158 XPutPixel( data_image, x, y, pixel );
1159 break;
1160 }
1161 case 15:
1162 {
1163 int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
1164 XPutPixel( data_image, x, y, pixel );
1165 break;
1166 }
1167 case 16:
1168 {
1169 int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
1170 XPutPixel( data_image, x, y, pixel );
1171 break;
1172 }
1173 case 32:
1174 case 24:
1175 {
1176 int pixel = 0;
1177 switch (b_o)
1178 {
1179 case RGB: pixel = (r << 16) | (g << 8) | b; break;
1180 case RBG: pixel = (r << 16) | (b << 8) | g; break;
1181 case BRG: pixel = (b << 16) | (r << 8) | g; break;
1182 case BGR: pixel = (b << 16) | (g << 8) | r; break;
1183 case GRB: pixel = (g << 16) | (r << 8) | b; break;
1184 case GBR: pixel = (g << 16) | (b << 8) | r; break;
1185 }
1186 XPutPixel( data_image, x, y, pixel );
1187 }
1188 default: break;
1189 }
1190 } // for
1191 } // for
1192
1193 // Blit picture
1194
1195 XGCValues gcvalues;
1196 gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
1197 GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
1198 XPutImage( dpy, (Drawable)GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
1199
1200 XDestroyImage( data_image );
1201 XFreeGC( dpy, gc );
1202
1203 // Blit mask
1204 if (image.HasMask())
1205 {
1206 wxBitmap maskBitmap(width, height, 1);
1207
1208 GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), (XtGCMask) 0, (XGCValues*)NULL );
1209 XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height );
1210
1211 XDestroyImage( mask_image );
1212 XFreeGC( dpy, gcMask );
1213
1214 wxMask* mask = new wxMask;
1215 mask->SetPixmap(maskBitmap.GetPixmap());
1216
1217 SetMask(mask);
1218
1219 maskBitmap.SetPixmapNull();
1220 }
1221
1222
1223 return TRUE;
1224 }
1225
1226 wxImage wxBitmap::ConvertToImage() const
1227 {
1228 wxImage image;
1229
1230 wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
1231
1232 Display *dpy = (Display*) wxGetDisplay();
1233 Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
1234 int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
1235
1236 XImage *ximage = XGetImage( dpy,
1237 (Drawable)GetPixmap(),
1238 0, 0,
1239 GetWidth(), GetHeight(),
1240 AllPlanes, ZPixmap );
1241
1242 wxCHECK_MSG( ximage, wxNullImage, wxT("couldn't create image") );
1243
1244 image.Create( GetWidth(), GetHeight() );
1245 char unsigned *data = image.GetData();
1246
1247 if (!data)
1248 {
1249 XDestroyImage( ximage );
1250 wxFAIL_MSG( wxT("couldn't create image") );
1251 return wxNullImage;
1252 }
1253
1254 /*
1255 GdkImage *gdk_image_mask = (GdkImage*) NULL;
1256 if (GetMask())
1257 {
1258 gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
1259 0, 0,
1260 GetWidth(), GetHeight() );
1261
1262 image.SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
1263 }
1264 */
1265
1266 // Retrieve depth info
1267
1268 XVisualInfo vinfo_template;
1269 XVisualInfo *vi;
1270
1271 vinfo_template.visual = vis;
1272 vinfo_template.visualid = XVisualIDFromVisual( vis );
1273 vinfo_template.depth = bpp;
1274 int nitem = 0;
1275
1276 vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
1277
1278 wxCHECK_MSG( vi, wxNullImage, wxT("no visual") );
1279
1280 if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
1281
1282 XFree( vi );
1283
1284 XColor colors[256];
1285 if (bpp == 8)
1286 {
1287 Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
1288
1289 for (int i = 0; i < 256; i++) colors[i].pixel = i;
1290 XQueryColors( dpy, cmap, colors, 256 );
1291 }
1292
1293 long pos = 0;
1294 for (int j = 0; j < GetHeight(); j++)
1295 {
1296 for (int i = 0; i < GetWidth(); i++)
1297 {
1298 int pixel = XGetPixel( ximage, i, j );
1299 if (bpp <= 8)
1300 {
1301 data[pos] = colors[pixel].red >> 8;
1302 data[pos+1] = colors[pixel].green >> 8;
1303 data[pos+2] = colors[pixel].blue >> 8;
1304 } else if (bpp == 15)
1305 {
1306 data[pos] = (pixel >> 7) & 0xf8;
1307 data[pos+1] = (pixel >> 2) & 0xf8;
1308 data[pos+2] = (pixel << 3) & 0xf8;
1309 } else if (bpp == 16)
1310 {
1311 data[pos] = (pixel >> 8) & 0xf8;
1312 data[pos+1] = (pixel >> 3) & 0xfc;
1313 data[pos+2] = (pixel << 3) & 0xf8;
1314 } else
1315 {
1316 data[pos] = (pixel >> 16) & 0xff;
1317 data[pos+1] = (pixel >> 8) & 0xff;
1318 data[pos+2] = pixel & 0xff;
1319 }
1320
1321 /*
1322 if (gdk_image_mask)
1323 {
1324 int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
1325 if (mask_pixel == 0)
1326 {
1327 data[pos] = 16;
1328 data[pos+1] = 16;
1329 data[pos+2] = 16;
1330 }
1331 }
1332 */
1333
1334 pos += 3;
1335 }
1336 }
1337
1338 XDestroyImage( ximage );
1339 /*
1340 if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
1341 */
1342
1343 return image;
1344 }