///////////////////////////////////////////////////////////////////////////// // Name: bitmap.cpp // Purpose: wxBitmap // Author: Julian Smart // Modified by: // Created: 17/09/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "bitmap.h" #endif #ifdef __VMS #define XtParent XTPARENT #endif #include "wx/setup.h" #include "wx/utils.h" #include "wx/palette.h" #include "wx/bitmap.h" #include "wx/icon.h" #include "wx/log.h" #include "wx/control.h" #include "wx/dcmemory.h" #include "wx/image.h" #include "wx/app.h" #ifdef __VMS__ #pragma message disable nosimpint #endif #include #ifdef __VMS__ #pragma message enable nosimpint #endif #include "wx/motif/private.h" #if wxHAVE_LIB_XPM #include #endif #include IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject) IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject) wxBitmapRefData::wxBitmapRefData() { m_ok = FALSE; m_width = 0; m_height = 0; m_depth = 0; m_quality = 0; m_numColors = 0; m_bitmapMask = NULL; m_pixmap = (WXPixmap) 0; m_display = (WXDisplay*) 0; m_freePixmap = TRUE; //TODO: necessary? m_freeColors = (unsigned long*) 0; m_freeColorsCount = 0; // These 5 variables are for wxControl m_insensPixmap = (WXPixmap) 0; m_labelPixmap = (WXPixmap) 0; m_armPixmap = (WXPixmap) 0; m_image = (WXImage*) 0; m_insensImage = (WXImage*) 0; } wxBitmapRefData::~wxBitmapRefData() { if (m_labelPixmap) XmDestroyPixmap (DefaultScreenOfDisplay ((Display*) m_display), (Pixmap) m_labelPixmap); if (m_armPixmap) XmDestroyPixmap (DefaultScreenOfDisplay ((Display*) m_display), (Pixmap) m_armPixmap); if (m_insensPixmap) XmDestroyPixmap (DefaultScreenOfDisplay ((Display*) m_display), (Pixmap) m_insensPixmap); if (m_image) { XmUninstallImage ((XImage*) m_image); XtFree ((char *) (XImage*) m_image); } if (m_insensImage) { XmUninstallImage ((XImage*) m_insensImage); delete[] ((XImage*) m_insensImage)->data; XtFree ((char *) (XImage*) m_insensImage); } if (m_pixmap && m_freePixmap) XFreePixmap ((Display*) m_display, (Pixmap) m_pixmap); if (m_freeColors) { int screen = DefaultScreen((Display*) m_display); Colormap cmp = DefaultColormap((Display*) m_display,screen); long llp; for(llp = 0;llp < m_freeColorsCount;llp++) XFreeColors((Display*) m_display, cmp, &m_freeColors[llp], 1, 0L); delete m_freeColors; }; if (m_bitmapMask) delete m_bitmapMask; m_bitmapMask = NULL; } wxList wxBitmap::sm_handlers; #define M_BMPDATA ((wxBitmapRefData *)m_refData) wxBitmap::wxBitmap() { m_refData = NULL; } wxBitmap::~wxBitmap() { } wxBitmap::wxBitmap(const char bits[], int width, int height, int depth) { m_refData = new wxBitmapRefData; (void) Create((void*) bits, wxBITMAP_TYPE_XBM_DATA, width, height, depth); } wxBitmap::wxBitmap(int w, int h, int d) { (void)Create(w, h, d); } wxBitmap::wxBitmap(void *data, long type, int width, int height, int depth) { (void) Create(data, type, width, height, depth); } wxBitmap::wxBitmap(const wxString& filename, long type) { LoadFile(filename, (int)type); } // Create from XPM data static wxControl* sg_Control = NULL; wxBitmap::wxBitmap(char **data, wxControl* control) { // Pass the control to the Create function using a global sg_Control = control; (void) Create((void *)data, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0); sg_Control = (wxControl*) NULL; } bool wxBitmap::CreateFromXpm(const char **bits) { wxCHECK_MSG( bits, FALSE, _T("NULL pointer in wxBitmap::CreateFromXpm") ); return Create(bits, wxBITMAP_TYPE_XPM_DATA, 0, 0, 0); } bool wxBitmap::Create(int w, int h, int d) { UnRef(); m_refData = new wxBitmapRefData; if (d < 1) d = wxDisplayDepth(); M_BITMAPDATA->m_width = w; M_BITMAPDATA->m_height = h; M_BITMAPDATA->m_depth = d; M_BITMAPDATA->m_freePixmap = TRUE; Display *dpy = (Display*) wxGetDisplay(); M_BITMAPDATA->m_display = dpy; /* MATTHEW: [4] Remember the display */ M_BITMAPDATA->m_pixmap = (WXPixmap) XCreatePixmap (dpy, RootWindow (dpy, DefaultScreen (dpy)), w, h, d); M_BITMAPDATA->m_ok = (M_BITMAPDATA->m_pixmap != (WXPixmap) 0) ; return M_BITMAPDATA->m_ok; } bool wxBitmap::LoadFile(const wxString& filename, long type) { UnRef(); m_refData = new wxBitmapRefData; wxBitmapHandler *handler = FindHandler(type); if ( handler == NULL ) { wxImage image; if (!image.LoadFile( filename, type )) return FALSE; if (image.Ok()) { *this = image.ConvertToBitmap(); return TRUE; } else return FALSE; } return handler->LoadFile(this, filename, type, -1, -1); } bool wxBitmap::Create(void *data, long type, int width, int height, int depth) { UnRef(); m_refData = new wxBitmapRefData; wxBitmapHandler *handler = FindHandler(type); if ( handler == NULL ) { wxLogWarning("no data bitmap handler for type %d defined.", type); return FALSE; } return handler->Create(this, data, type, width, height, depth); } bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette) { wxBitmapHandler *handler = FindHandler(type); if ( handler == NULL ) { // try wxImage wxImage image( *this ); if (image.Ok()) return image.SaveFile( filename, type ); else return FALSE; } return handler->SaveFile(this, filename, type, palette); } void wxBitmap::SetWidth(int w) { if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; M_BITMAPDATA->m_width = w; } void wxBitmap::SetHeight(int h) { if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; M_BITMAPDATA->m_height = h; } void wxBitmap::SetDepth(int d) { if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; M_BITMAPDATA->m_depth = d; } void wxBitmap::SetQuality(int q) { if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; M_BITMAPDATA->m_quality = q; } void wxBitmap::SetOk(bool isOk) { if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; M_BITMAPDATA->m_ok = isOk; } void wxBitmap::SetPalette(const wxPalette& palette) { if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; M_BITMAPDATA->m_bitmapPalette = palette ; } void wxBitmap::SetMask(wxMask *mask) { if (!M_BITMAPDATA) m_refData = new wxBitmapRefData; M_BITMAPDATA->m_bitmapMask = mask ; } wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const { wxCHECK_MSG( Ok() && (rect.x >= 0) && (rect.y >= 0) && (rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height), wxNullBitmap, wxT("invalid bitmap or bitmap region") ); wxBitmap ret( rect.width, rect.height, 0 ); wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") ); // The remaining still TODO return ret; } void wxBitmap::AddHandler(wxBitmapHandler *handler) { sm_handlers.Append(handler); } void wxBitmap::InsertHandler(wxBitmapHandler *handler) { sm_handlers.Insert(handler); } bool wxBitmap::RemoveHandler(const wxString& name) { wxBitmapHandler *handler = FindHandler(name); if ( handler ) { sm_handlers.DeleteObject(handler); return TRUE; } else return FALSE; } wxBitmapHandler *wxBitmap::FindHandler(const wxString& name) { wxNode *node = sm_handlers.First(); while ( node ) { wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); if ( handler->GetName() == name ) return handler; node = node->Next(); } return NULL; } wxBitmapHandler *wxBitmap::FindHandler(const wxString& extension, long bitmapType) { wxNode *node = sm_handlers.First(); while ( node ) { wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); if ( handler->GetExtension() == extension && (bitmapType == -1 || handler->GetType() == bitmapType) ) return handler; node = node->Next(); } return NULL; } wxBitmapHandler *wxBitmap::FindHandler(long bitmapType) { wxNode *node = sm_handlers.First(); while ( node ) { wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); if (handler->GetType() == bitmapType) return handler; node = node->Next(); } return NULL; } /* * wxMask */ wxMask::wxMask() { m_pixmap = (WXPixmap) 0; } // Construct a mask from a bitmap and a colour indicating // the transparent area wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) { m_pixmap = (WXPixmap) 0; Create(bitmap, colour); } // Construct a mask from a bitmap and a palette index indicating // the transparent area wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) { m_pixmap = (WXPixmap) 0; Create(bitmap, paletteIndex); } // Construct a mask from a mono bitmap (copies the bitmap). wxMask::wxMask(const wxBitmap& bitmap) { m_pixmap = (WXPixmap) 0; Create(bitmap); } wxMask::~wxMask() { // TODO: this may be the wrong display if ( m_pixmap ) XFreePixmap ((Display*) wxGetDisplay(), (Pixmap) m_pixmap); } // Create a mask from a mono bitmap (copies the bitmap). bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap)) { // TODO return FALSE; } // Create a mask from a bitmap and a palette index indicating // the transparent area bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap), int WXUNUSED(paletteIndex)) { // TODO return FALSE; } // Create a mask from a bitmap and a colour indicating // the transparent area bool wxMask::Create(const wxBitmap& WXUNUSED(bitmap), const wxColour& WXUNUSED(colour)) { // TODO return FALSE; } /* * wxBitmapHandler */ IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject) bool wxBitmapHandler::Create(wxBitmap *WXUNUSED(bitmap), void *WXUNUSED(data), long WXUNUSED(type), int WXUNUSED(width), int WXUNUSED(height), int WXUNUSED(depth)) { return FALSE; } bool wxBitmapHandler::LoadFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), long WXUNUSED(type), int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight)) { return FALSE; } bool wxBitmapHandler::SaveFile(wxBitmap *WXUNUSED(bitmap), const wxString& WXUNUSED(name), int WXUNUSED(type), const wxPalette *WXUNUSED(palette)) { return FALSE; } /* * Standard handlers */ class WXDLLEXPORT wxXBMFileHandler: public wxBitmapHandler { DECLARE_DYNAMIC_CLASS(wxXBMFileHandler) public: inline wxXBMFileHandler() { m_name = "XBM file"; m_extension = "xbm"; m_type = wxBITMAP_TYPE_XBM; }; virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags, int desiredWidth, int desiredHeight); }; IMPLEMENT_DYNAMIC_CLASS(wxXBMFileHandler, wxBitmapHandler) bool wxXBMFileHandler::LoadFile(wxBitmap *bitmap, const wxString& name, long WXUNUSED(flags), int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight)) { M_BITMAPHANDLERDATA->m_freePixmap = TRUE; int hotX, hotY; unsigned int w, h; Pixmap pixmap; Display *dpy = (Display*) wxGetDisplay(); M_BITMAPDATA->m_display = (WXDisplay*) dpy; int value = XReadBitmapFile (dpy, RootWindow (dpy, DefaultScreen (dpy)), (char*) (const char*) name, &w, &h, &pixmap, &hotX, &hotY); M_BITMAPHANDLERDATA->m_width = w; M_BITMAPHANDLERDATA->m_height = h; M_BITMAPHANDLERDATA->m_depth = 1; M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) pixmap; if ((value == BitmapFileInvalid) || (value == BitmapOpenFailed) || (value == BitmapNoMemory)) { M_BITMAPHANDLERDATA->m_ok = FALSE; M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) 0; } else M_BITMAPHANDLERDATA->m_ok = TRUE; return M_BITMAPHANDLERDATA->m_ok ; } class WXDLLEXPORT wxXBMDataHandler: public wxBitmapHandler { DECLARE_DYNAMIC_CLASS(wxXBMDataHandler) public: inline wxXBMDataHandler() { m_name = "XBM data"; m_extension = "xbm"; m_type = wxBITMAP_TYPE_XBM_DATA; }; virtual bool Create(wxBitmap *bitmap, void *data, long flags, int width, int height, int depth = 1); }; IMPLEMENT_DYNAMIC_CLASS(wxXBMDataHandler, wxBitmapHandler) bool wxXBMDataHandler::Create( wxBitmap *bitmap, void *data, long WXUNUSED(flags), int width, int height, int WXUNUSED(depth)) { M_BITMAPHANDLERDATA->m_width = width; M_BITMAPHANDLERDATA->m_height = height; M_BITMAPHANDLERDATA->m_depth = 1; M_BITMAPHANDLERDATA->m_freePixmap = TRUE; Display *dpy = (Display*) wxGetDisplay(); M_BITMAPHANDLERDATA->m_display = (WXDisplay*) dpy; M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) XCreateBitmapFromData (dpy, RootWindow (dpy, DefaultScreen (dpy)), (char*) data, width, height); M_BITMAPHANDLERDATA->m_ok = (M_BITMAPHANDLERDATA->m_pixmap != (WXPixmap) 0) ; // code for wxControl. TODO: can we avoid doing this until we need it? // E.g. have CreateButtonPixmaps which is called on demand. XImage* image = (XImage *) XtMalloc (sizeof (XImage)); image->width = width; image->height = height; image->data = (char*) data; image->depth = 1; image->xoffset = 0; image->format = XYBitmap; image->byte_order = LSBFirst; image->bitmap_unit = 8; image->bitmap_bit_order = LSBFirst; image->bitmap_pad = 8; image->bytes_per_line = (width + 7) >> 3; char tmp[128]; sprintf (tmp, "Im%x", (unsigned int) image); XmInstallImage (image, tmp); // Build our manually stipped pixmap. int bpl = (width + 7) / 8; char *data1 = new char[height * bpl]; char* bits = (char*) data; int i; for (i = 0; i < height; i++) { int mask = i % 2 ? 0x55 : 0xaa; int j; for (j = 0; j < bpl; j++) data1[i * bpl + j] = bits[i * bpl + j] & mask; } XImage* insensImage = (XImage *) XtMalloc (sizeof (XImage)); insensImage->width = width; insensImage->height = height; insensImage->data = data1; insensImage->depth = 1; insensImage->xoffset = 0; insensImage->format = XYBitmap; insensImage->byte_order = LSBFirst; insensImage->bitmap_unit = 8; insensImage->bitmap_bit_order = LSBFirst; insensImage->bitmap_pad = 8; insensImage->bytes_per_line = bpl; sprintf (tmp, "Not%x", (unsigned int)insensImage); XmInstallImage (insensImage, tmp); M_BITMAPHANDLERDATA->m_image = (WXImage*) image; M_BITMAPHANDLERDATA->m_insensImage = (WXImage*) insensImage; return TRUE; } #if wxHAVE_LIB_XPM class WXDLLEXPORT wxXPMFileHandler: public wxBitmapHandler { DECLARE_DYNAMIC_CLASS(wxXPMFileHandler) public: inline wxXPMFileHandler() { m_name = "XPM file"; m_extension = "xpm"; m_type = wxBITMAP_TYPE_XPM; }; virtual bool LoadFile(wxBitmap *bitmap, const wxString& name, long flags, int desiredWidth, int desiredHeight); virtual bool SaveFile(wxBitmap *bitmap, const wxString& name, int type, const wxPalette *palette = NULL); }; IMPLEMENT_DYNAMIC_CLASS(wxXPMFileHandler, wxBitmapHandler) bool wxXPMFileHandler::LoadFile( wxBitmap *bitmap, const wxString& name, long WXUNUSED(flags), int WXUNUSED(desiredWidth), int WXUNUSED(desiredHeight) ) { Display *dpy = (Display*) wxGetDisplay(); M_BITMAPHANDLERDATA->m_display = (WXDisplay*) dpy; XpmAttributes xpmAttr; Pixmap pixmap; Pixmap mask = 0; M_BITMAPHANDLERDATA->m_ok = FALSE; xpmAttr.valuemask = XpmReturnInfos | XpmCloseness; xpmAttr.closeness = 40000; int errorStatus = XpmReadFileToPixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)), (char*) (const char*) name, &pixmap, &mask, &xpmAttr); if (errorStatus == XpmSuccess) { M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) pixmap; if ( mask ) { M_BITMAPHANDLERDATA->m_bitmapMask = new wxMask; M_BITMAPHANDLERDATA->m_bitmapMask->SetPixmap((WXPixmap) mask); } unsigned int depthRet; int xRet, yRet; unsigned int widthRet, heightRet, borderWidthRet; Window rootWindowRet; XGetGeometry(dpy, pixmap, &rootWindowRet, &xRet, &yRet, &widthRet, &heightRet, &borderWidthRet, &depthRet); M_BITMAPHANDLERDATA->m_width = xpmAttr.width; M_BITMAPHANDLERDATA->m_height = xpmAttr.height; /* if ( xpmAttr.npixels > 2 ) { M_BITMAPHANDLERDATA->m_depth = 8; // TODO: next time not just a guess :-) ... } else { M_BITMAPHANDLERDATA->m_depth = 1; // mono } */ M_BITMAPHANDLERDATA->m_depth = depthRet; M_BITMAPHANDLERDATA->m_numColors = xpmAttr.npixels; XpmFreeAttributes(&xpmAttr); M_BITMAPHANDLERDATA->m_ok = TRUE; return TRUE; } else { // XpmDebugError(errorStatus, name); M_BITMAPHANDLERDATA->m_ok = FALSE; return FALSE; } } bool wxXPMFileHandler::SaveFile( wxBitmap *bitmap, const wxString& name, int WXUNUSED(type), const wxPalette *WXUNUSED(palette)) { if (M_BITMAPHANDLERDATA->m_ok && M_BITMAPHANDLERDATA->m_pixmap) { Display *dpy = (Display*) M_BITMAPHANDLERDATA->m_display; int errorStatus = XpmWriteFileFromPixmap(dpy, (char*) (const char*) name, (Pixmap) M_BITMAPHANDLERDATA->m_pixmap, (M_BITMAPHANDLERDATA->m_bitmapMask ? (Pixmap) M_BITMAPHANDLERDATA->m_bitmapMask->GetPixmap() : (Pixmap) 0), (XpmAttributes *) NULL); if (errorStatus == XpmSuccess) return TRUE; else return FALSE; } else return FALSE; } class WXDLLEXPORT wxXPMDataHandler: public wxBitmapHandler { DECLARE_DYNAMIC_CLASS(wxXPMDataHandler) public: inline wxXPMDataHandler() { m_name = "XPM data"; m_extension = "xpm"; m_type = wxBITMAP_TYPE_XPM_DATA; }; virtual bool Create(wxBitmap *bitmap, void *data, long flags, int width, int height, int depth = 1); }; IMPLEMENT_DYNAMIC_CLASS(wxXPMDataHandler, wxBitmapHandler) bool wxXPMDataHandler::Create( wxBitmap *bitmap, void *data, long WXUNUSED(flags), int width, int height, int WXUNUSED(depth)) { M_BITMAPHANDLERDATA->m_width = width; M_BITMAPHANDLERDATA->m_height = height; M_BITMAPHANDLERDATA->m_depth = 1; M_BITMAPHANDLERDATA->m_freePixmap = TRUE; Display *dpy = (Display*) wxGetDisplay(); M_BITMAPHANDLERDATA->m_display = (WXDisplay*) dpy; XpmAttributes xpmAttr; xpmAttr.valuemask = XpmReturnInfos; /* nothing yet, but get infos back */ XpmColorSymbol symbolicColors[4]; if (sg_Control && sg_Control->GetMainWidget()) { symbolicColors[0].name = "foreground"; symbolicColors[0].value = NULL; symbolicColors[1].name = "background"; symbolicColors[1].value = NULL; XtVaGetValues((Widget) sg_Control->GetMainWidget(), XmNforeground, &symbolicColors[0].pixel, XmNbackground, &symbolicColors[1].pixel,NULL); xpmAttr.numsymbols = 2; xpmAttr.colorsymbols = symbolicColors; xpmAttr.valuemask |= XpmColorSymbols; // add flag } Pixmap pixmap; Pixmap mask = 0; int ErrorStatus = XpmCreatePixmapFromData(dpy, RootWindow(dpy, DefaultScreen(dpy)), (char**) data, &pixmap, &mask, &xpmAttr); if (ErrorStatus == XpmSuccess) { // Set attributes M_BITMAPHANDLERDATA->m_width = xpmAttr.width; M_BITMAPHANDLERDATA->m_height = xpmAttr.height; unsigned int depthRet; int xRet, yRet; unsigned int widthRet, heightRet, borderWidthRet; Window rootWindowRet; XGetGeometry(dpy, pixmap, &rootWindowRet, &xRet, &yRet, &widthRet, &heightRet, &borderWidthRet, &depthRet); /* if ( xpmAttr.npixels > 2 ) { M_BITMAPHANDLERDATA->m_depth = 8; // next time not just a guess :-) ... } else { M_BITMAPHANDLERDATA->m_depth = 1; // mono } */ M_BITMAPHANDLERDATA->m_depth = depthRet; M_BITMAPHANDLERDATA->m_numColors = xpmAttr.npixels; XpmFreeAttributes(&xpmAttr); M_BITMAPHANDLERDATA->m_ok = TRUE; M_BITMAPHANDLERDATA->m_pixmap = (WXPixmap) pixmap; if ( mask ) { M_BITMAPHANDLERDATA->m_bitmapMask = new wxMask; M_BITMAPHANDLERDATA->m_bitmapMask->SetPixmap((WXPixmap) mask); } } else { // XpmDebugError(ErrorStatus, NULL); M_BITMAPHANDLERDATA->m_ok = FALSE; } return M_BITMAPHANDLERDATA->m_ok ; } #endif // wxHAVE_LIB_XPM void wxBitmap::CleanUpHandlers() { wxNode *node = sm_handlers.First(); while ( node ) { wxBitmapHandler *handler = (wxBitmapHandler *)node->Data(); wxNode *next = node->Next(); delete handler; delete node; node = next; } } void wxBitmap::InitStandardHandlers() { // Initialize all standard bitmap or derived class handlers here. AddHandler(new wxXBMFileHandler); AddHandler(new wxXBMDataHandler); // XPM is considered standard for Motif, although it can be omitted if // libXpm is not installed #if wxHAVE_LIB_XPM AddHandler(new wxXPMFileHandler); AddHandler(new wxXPMDataHandler); #endif // wxHAVE_LIB_XPM } WXPixmap wxBitmap::GetLabelPixmap (WXWidget w) { if (M_BITMAPDATA->m_image == (WXPixmap) 0) return M_BITMAPDATA->m_pixmap; Display *dpy = (Display*) M_BITMAPDATA->m_display; #ifdef FOO /* If we do: if (labelPixmap) return labelPixmap; things can be wrong, because colors can have been changed. If we do: if (labelPixmap) XmDestroyPixmap(DefaultScreenOfDisplay(dpy),labelPixmap) ; we got BadDrawable if the pixmap is referenced by multiples widgets this is a catch22!! So, before doing thing really clean, I just do nothing; if the pixmap is referenced by many widgets, Motif performs caching functions. And if pixmap is referenced with multiples colors, we just have some memory leaks... I hope we can deal with them... */ // Must be destroyed, because colours can have been changed! if (M_BITMAPDATA->m_labelPixmap) XmDestroyPixmap (DefaultScreenOfDisplay (dpy), M_BITMAPDATA->m_labelPixmap); #endif char tmp[128]; sprintf (tmp, "Im%x", (unsigned int) M_BITMAPDATA->m_image); Pixel fg, bg; Widget widget = (Widget) w; while (XmIsGadget ( widget )) widget = XtParent (widget); XtVaGetValues (widget, XmNbackground, &bg, XmNforeground, &fg, NULL); M_BITMAPDATA->m_labelPixmap = (WXPixmap) XmGetPixmap (DefaultScreenOfDisplay (dpy), tmp, fg, bg); return M_BITMAPDATA->m_labelPixmap; } WXPixmap wxBitmap::GetArmPixmap (WXWidget w) { if (M_BITMAPDATA->m_image == (WXPixmap) 0) return M_BITMAPDATA->m_pixmap; Display *dpy = (Display*) M_BITMAPDATA->m_display; #ifdef FOO // See GetLabelPixmap () comment // Must be destroyed, because colours can have been changed! if (M_BITMAPDATA->m_armPixmap) XmDestroyPixmap (DefaultScreenOfDisplay (dpy), M_BITMAPDATA->m_armPixmap); #endif char tmp[128]; sprintf (tmp, "Im%x", (unsigned int) M_BITMAPDATA->m_image); Pixel fg, bg; Widget widget = (Widget) w; XtVaGetValues (widget, XmNarmColor, &bg, NULL); while (XmIsGadget (widget)) widget = XtParent (widget); XtVaGetValues (widget, XmNforeground, &fg, NULL); M_BITMAPDATA->m_armPixmap = (WXPixmap) XmGetPixmap (DefaultScreenOfDisplay (dpy), tmp, fg, bg); return M_BITMAPDATA->m_armPixmap; } WXPixmap wxBitmap::GetInsensPixmap (WXWidget w) { Display *dpy = (Display*) M_BITMAPDATA->m_display; if (M_BITMAPDATA->m_insensPixmap) return M_BITMAPDATA->m_insensPixmap; if (!w) { M_BITMAPDATA->m_insensPixmap = (WXPixmap) XCreateInsensitivePixmap(dpy, (Pixmap) M_BITMAPDATA->m_pixmap); if (M_BITMAPDATA->m_insensPixmap) return M_BITMAPDATA->m_insensPixmap; else return M_BITMAPDATA->m_pixmap; } if (M_BITMAPDATA->m_insensImage == (WXPixmap) 0) return M_BITMAPDATA->m_pixmap; #ifdef FOO See GetLabelPixmap () comment // Must be destroyed, because colours can have been changed! if (M_BITMAPDATA->m_insensPixmap) XmDestroyPixmap (DefaultScreenOfDisplay (dpy), (Pixmap) M_BITMAPDATA->m_insensPixmap); #endif char tmp[128]; sprintf (tmp, "Not%x", (unsigned int) M_BITMAPDATA->m_insensImage); Pixel fg, bg; Widget widget = (Widget) w; while (XmIsGadget (widget)) widget = XtParent (widget); XtVaGetValues (widget, XmNbackground, &bg, XmNforeground, &fg, NULL); M_BITMAPDATA->m_insensPixmap = (WXPixmap) XmGetPixmap (DefaultScreenOfDisplay (dpy), tmp, fg, bg); return M_BITMAPDATA->m_insensPixmap; } // We may need this sometime... /**************************************************************************** NAME XCreateInsensitivePixmap - create a grayed-out copy of a pixmap SYNOPSIS Pixmap XCreateInsensitivePixmap( Display *display, Pixmap pixmap ) DESCRIPTION This function creates a grayed-out copy of the argument pixmap, suitable for use as a XmLabel's XmNlabelInsensitivePixmap resource. RETURN VALUES The return value is the new Pixmap id or zero on error. Errors include a NULL display argument or an invalid Pixmap argument. ERRORS If one of the XLib functions fail, it will produce a X error. The default X error handler prints a diagnostic and calls exit(). SEE ALSO XCopyArea(3), XCreateBitmapFromData(3), XCreateGC(3), XCreatePixmap(3), XFillRectangle(3), exit(2) AUTHOR John R Veregge - john@puente.jpl.nasa.gov Advanced Engineering and Prototyping Group (AEG) Information Systems Technology Section (395) Jet Propulsion Lab - Calif Institute of Technology *****************************************************************************/ Pixmap XCreateInsensitivePixmap( Display *display, Pixmap pixmap ) { static char stipple_data[] = { 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA }; GC gc; Pixmap ipixmap, stipple; unsigned width, height, depth; Window window; /* These return values */ unsigned border; /* from XGetGeometry() */ int x, y; /* are not needed. */ ipixmap = 0; if ( NULL == display || 0 == pixmap ) return ipixmap; if ( 0 == XGetGeometry( display, pixmap, &window, &x, &y, &width, &height, &border, &depth ) ) return ipixmap; /* BadDrawable: probably an invalid pixmap */ /* Get the stipple pixmap to be used to 'gray-out' the argument pixmap. */ stipple = XCreateBitmapFromData( display, pixmap, stipple_data, 16, 16 ); if ( 0 != stipple ) { gc = XCreateGC( display, pixmap, (XtGCMask)0, (XGCValues*)NULL ); if ( NULL != gc ) { /* Create an identical copy of the argument pixmap. */ ipixmap = XCreatePixmap( display, pixmap, width, height, depth ); if ( 0 != ipixmap ) { /* Copy the argument pixmap into the new pixmap. */ XCopyArea( display, pixmap, ipixmap, gc, 0, 0, width, height, 0, 0 ); /* Refill the new pixmap using the stipple algorithm/pixmap. */ XSetStipple( display, gc, stipple ); XSetFillStyle( display, gc, FillStippled ); XFillRectangle( display, ipixmap, gc, 0, 0, width, height ); } XFreeGC( display, gc ); } XFreePixmap( display, stipple ); } return ipixmap; } // Creates a bitmap with transparent areas drawn in // the given colour. wxBitmap wxCreateMaskedBitmap(const wxBitmap& bitmap, wxColour& colour) { wxBitmap newBitmap(bitmap.GetWidth(), bitmap.GetHeight(), bitmap.GetDepth()); wxMemoryDC destDC; wxMemoryDC srcDC; srcDC.SelectObject(bitmap); destDC.SelectObject(newBitmap); wxBrush brush(colour, wxSOLID); destDC.SetOptimization(FALSE); destDC.SetBackground(brush); destDC.Clear(); destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE); return newBitmap; } //----------------------------------------------------------------------------- // wxImage conversion routines //----------------------------------------------------------------------------- /* Date: Wed, 05 Jan 2000 11:45:40 +0100 From: Frits Boel To: julian.smart@ukonline.co.uk Subject: Patch for Motif ConvertToBitmap Hi Julian, I've been working on a wxWin application for image processing. From the beginning, I was surprised by the (lack of) speed of ConvertToBitmap, till I looked in the source code of image.cpp. I saw that converting a wxImage to a bitmap with 8-bit pixels is done with comparing every pixel to the 256 colors of the palet. A very time-consuming piece of code! Because I wanted a faster application, I've made a 'patch' for this. In short: every pixel of the image is compared to a sorted list with colors. If the color is found in the list, the palette entry is returned; if the color is not found, the color palette is searched and then the palette entry is returned and the color added to the sorted list. Maybe there is another method for this, namely changing the palette itself (if the colors are known, as is the case with tiffs with a colormap). I did not look at this, maybe someone else did? The code of the patch is attached, have a look on it, and maybe you will ship it with the next release of wxMotif? Regards, Frits Boel Software engineer at Hubrecht Laboratory, The Netherlands. */ class wxSearchColor { public: wxSearchColor( void ); wxSearchColor( int size, XColor *colors ); ~wxSearchColor( void ); int SearchColor( int r, int g, int b ); private: int AddColor( unsigned int value, int pos ); int size; XColor *colors; unsigned int *color; int *entry; int bottom; int top; }; wxSearchColor::wxSearchColor( void ) { size = 0; colors = (XColor*) NULL; color = (unsigned int *) NULL; entry = (int*) NULL; bottom = 0; top = 0; } wxSearchColor::wxSearchColor( int size_, XColor *colors_ ) { int i; size = size_; colors = colors_; color = new unsigned int[size]; entry = new int [size]; for (i = 0; i < size; i++ ) { entry[i] = -1; } bottom = top = ( size >> 1 ); } wxSearchColor::~wxSearchColor( void ) { if ( color ) delete color; if ( entry ) delete entry; } int wxSearchColor::SearchColor( int r, int g, int b ) { unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b; int begin = bottom; int end = top; int middle = 0; while ( begin <= end ) { middle = ( begin + end ) >> 1; if ( value == color[middle] ) { return( entry[middle] ); } else if ( value < color[middle] ) { end = middle - 1; } else { begin = middle + 1; } } return AddColor( value, middle ); } int wxSearchColor::AddColor( unsigned int value, int pos ) { int i; int pixel = -1; int max = 3 * (65536); for ( i = 0; i < 256; i++ ) { int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red; int gdiff = ((value ) & 0xFF00 ) - colors[i].green; int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue; int sum = abs (rdiff) + abs (gdiff) + abs (bdiff); if (sum < max) { pixel = i; max = sum; } } if ( entry[pos] < 0 ) { color[pos] = value; entry[pos] = pixel; } else if ( value < color[pos] ) { if ( bottom > 0 ) { for ( i = bottom; i < pos; i++ ) { color[i-1] = color[i]; entry[i-1] = entry[i]; } bottom--; color[pos-1] = value; entry[pos-1] = pixel; } else if ( top < size-1 ) { for ( i = top; i >= pos; i-- ) { color[i+1] = color[i]; entry[i+1] = entry[i]; } top++; color[pos] = value; entry[pos] = pixel; } } else { if ( top < size-1 ) { for ( i = top; i > pos; i-- ) { color[i+1] = color[i]; entry[i+1] = entry[i]; } top++; color[pos+1] = value; entry[pos+1] = pixel; } else if ( bottom > 0 ) { for ( i = bottom; i < pos; i++ ) { color[i-1] = color[i]; entry[i-1] = entry[i]; } bottom--; color[pos] = value; entry[pos] = pixel; } } return( pixel ); } bool wxBitmap::CreateFromImage( const wxImage& image, int depth ) { wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") ) wxCHECK_MSG( depth == -1, FALSE, wxT("invalid bitmap depth") ) m_refData = new wxBitmapRefData(); int width = image.GetWidth(); int height = image.GetHeight(); SetHeight( height ); SetWidth( width ); Display *dpy = (Display*) wxGetDisplay(); Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) ); int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) ); // Create image XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 ); data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height ); Create( width, height, bpp ); // Create mask XImage *mask_image = (XImage*) NULL; if (image.HasMask()) { mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 ); mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height ); } // Retrieve depth info XVisualInfo vinfo_template; XVisualInfo *vi; vinfo_template.visual = vis; vinfo_template.visualid = XVisualIDFromVisual( vis ); vinfo_template.depth = bpp; int nitem = 0; vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem ); wxCHECK_MSG( vi, FALSE, wxT("no visual") ); XFree( vi ); if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15; if (bpp < 8) bpp = 8; // Render enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR }; byte_order b_o = RGB; if (bpp >= 24) { if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB; else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB; else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG; else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR; else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB; else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR; } int r_mask = image.GetMaskRed(); int g_mask = image.GetMaskGreen(); int b_mask = image.GetMaskBlue(); XColor colors[256]; if (bpp == 8) { Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy ); for (int i = 0; i < 256; i++) colors[i].pixel = i; XQueryColors( dpy, cmap, colors, 256 ); } wxSearchColor scolor( 256, colors ); unsigned char* data = image.GetData(); bool hasMask = image.HasMask(); int index = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int r = data[index]; index++; int g = data[index]; index++; int b = data[index]; index++; if (hasMask) { if ((r == r_mask) && (b == b_mask) && (g == g_mask)) XPutPixel( mask_image, x, y, 0 ); else XPutPixel( mask_image, x, y, 1 ); } switch (bpp) { case 8: { #if 0 // Old, slower code int pixel = -1; /* if (wxTheApp->m_colorCube) { pixel = wxTheApp->m_colorCube [ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ]; } else { */ int max = 3 * (65536); for (int i = 0; i < 256; i++) { int rdiff = (r << 8) - colors[i].red; int gdiff = (g << 8) - colors[i].green; int bdiff = (b << 8) - colors[i].blue; int sum = abs (rdiff) + abs (gdiff) + abs (bdiff); if (sum < max) { pixel = i; max = sum; } } /* } */ #endif // And this is all to get the 'right' color... int pixel = scolor.SearchColor( r, g, b ); XPutPixel( data_image, x, y, pixel ); break; } case 15: { int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); XPutPixel( data_image, x, y, pixel ); break; } case 16: { int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); XPutPixel( data_image, x, y, pixel ); break; } case 32: case 24: { int pixel = 0; switch (b_o) { case RGB: pixel = (r << 16) | (g << 8) | b; break; case RBG: pixel = (r << 16) | (b << 8) | g; break; case BRG: pixel = (b << 16) | (r << 8) | g; break; case BGR: pixel = (b << 16) | (g << 8) | r; break; case GRB: pixel = (g << 16) | (r << 8) | b; break; case GBR: pixel = (g << 16) | (b << 8) | r; break; } XPutPixel( data_image, x, y, pixel ); } default: break; } } // for } // for // Blit picture XGCValues gcvalues; gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) ); GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues ); XPutImage( dpy, (Drawable)GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height ); XDestroyImage( data_image ); XFreeGC( dpy, gc ); // Blit mask if (image.HasMask()) { wxBitmap maskBitmap(width, height, 1); GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), (XtGCMask) 0, (XGCValues*)NULL ); XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height ); XDestroyImage( mask_image ); XFreeGC( dpy, gcMask ); wxMask* mask = new wxMask; mask->SetPixmap(maskBitmap.GetPixmap()); SetMask(mask); maskBitmap.SetPixmapNull(); } return TRUE; } wxImage wxBitmap::ConvertToImage() const { wxImage image; wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") ); Display *dpy = (Display*) wxGetDisplay(); Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) ); int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) ); XImage *ximage = XGetImage( dpy, (Drawable)GetPixmap(), 0, 0, GetWidth(), GetHeight(), AllPlanes, ZPixmap ); wxCHECK_MSG( ximage, wxNullImage, wxT("couldn't create image") ); image.Create( GetWidth(), GetHeight() ); char unsigned *data = image.GetData(); if (!data) { XDestroyImage( ximage ); wxFAIL_MSG( wxT("couldn't create image") ); return wxNullImage; } /* GdkImage *gdk_image_mask = (GdkImage*) NULL; if (GetMask()) { gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(), 0, 0, GetWidth(), GetHeight() ); image.SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable } */ // Retrieve depth info XVisualInfo vinfo_template; XVisualInfo *vi; vinfo_template.visual = vis; vinfo_template.visualid = XVisualIDFromVisual( vis ); vinfo_template.depth = bpp; int nitem = 0; vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem ); wxCHECK_MSG( vi, wxNullImage, wxT("no visual") ); if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15; XFree( vi ); XColor colors[256]; if (bpp == 8) { Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy ); for (int i = 0; i < 256; i++) colors[i].pixel = i; XQueryColors( dpy, cmap, colors, 256 ); } long pos = 0; for (int j = 0; j < GetHeight(); j++) { for (int i = 0; i < GetWidth(); i++) { int pixel = XGetPixel( ximage, i, j ); if (bpp <= 8) { data[pos] = colors[pixel].red >> 8; data[pos+1] = colors[pixel].green >> 8; data[pos+2] = colors[pixel].blue >> 8; } else if (bpp == 15) { data[pos] = (pixel >> 7) & 0xf8; data[pos+1] = (pixel >> 2) & 0xf8; data[pos+2] = (pixel << 3) & 0xf8; } else if (bpp == 16) { data[pos] = (pixel >> 8) & 0xf8; data[pos+1] = (pixel >> 3) & 0xfc; data[pos+2] = (pixel << 3) & 0xf8; } else { data[pos] = (pixel >> 16) & 0xff; data[pos+1] = (pixel >> 8) & 0xff; data[pos+2] = pixel & 0xff; } /* if (gdk_image_mask) { int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j ); if (mask_pixel == 0) { data[pos] = 16; data[pos+1] = 16; data[pos+2] = 16; } } */ pos += 3; } } XDestroyImage( ximage ); /* if (gdk_image_mask) gdk_image_destroy( gdk_image_mask ); */ return image; }