X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7266b6723573ce6317577226cb1e5d32826e24e8..5d484919aad7cbd553103c414424bf488df272f7:/src/x11/colour.cpp diff --git a/src/x11/colour.cpp b/src/x11/colour.cpp index 37601ac3cf..1951c3e224 100644 --- a/src/x11/colour.cpp +++ b/src/x11/colour.cpp @@ -1,214 +1,296 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: colour.cpp +// Name: src/x11/colour.cpp // Purpose: wxColour class -// Author: Julian Smart +// Author: Julian Smart, Robert Roebling // Modified by: // Created: 17/09/98 // RCS-ID: $Id$ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence +// Copyright: (c) Julian Smart, Robert Roebling +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -//// TODO: make wxColour a ref-counted object, -//// so pixel values get shared. - -#ifdef __GNUG__ -#pragma implementation "colour.h" -#endif - #include "wx/gdicmn.h" -#include "wx/colour.h" #include "wx/app.h" -#ifdef __VMS__ -#pragma message disable nosimpint -#endif -#include -#ifdef __VMS__ -#pragma message enable nosimpint -#endif - #include "wx/x11/private.h" -IMPLEMENT_DYNAMIC_CLASS(wxColour, wxObject) +//----------------------------------------------------------------------------- +// wxColour +//----------------------------------------------------------------------------- -// Colour +class wxColourRefData: public wxObjectRefData +{ +public: + wxColourRefData() + { + m_color.red = 0; + m_color.green = 0; + m_color.blue = 0; + m_color.pixel = 0; + m_colormap = (WXColormap *) NULL; + m_hasPixel = false; + } + wxColourRefData(const wxColourRefData& data): + wxObjectRefData() + { + m_color = data.m_color; + m_colormap = data.m_colormap; + m_hasPixel = data.m_hasPixel; + } -wxColour::wxColour () + ~wxColourRefData() + { + FreeColour(); + } + + bool operator == (const wxColourRefData& data) const + { + return (m_colormap == data.m_colormap && + m_hasPixel == data.m_hasPixel && + m_color.red == data.m_color.red && + m_color.green == data.m_color.green && + m_color.blue == data.m_color.blue && + m_color.pixel == data.m_color.pixel); + } + + void FreeColour(); + void AllocColour( WXColormap cmap ); + + XColor m_color; + WXColormap m_colormap; + bool m_hasPixel; + + friend class wxColour; + + // reference counter for systems with <= 8-Bit display + static unsigned short colMapAllocCounter[ 256 ]; +}; + +unsigned short wxColourRefData::colMapAllocCounter[ 256 ] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +void wxColourRefData::FreeColour() { - m_isInit = FALSE; - m_red = m_blue = m_green = 0; - m_pixel = -1; + if (!m_colormap) + return; +#if !wxUSE_NANOX + if ( wxTheApp && + (wxTheApp->m_visualInfo->m_visualType == GrayScale || + wxTheApp->m_visualInfo->m_visualType == PseudoColor) ) + { + int idx = m_color.pixel; + colMapAllocCounter[ idx ] = colMapAllocCounter[ idx ] - 1; + + if (colMapAllocCounter[ idx ] == 0) + { + unsigned long pixel = m_color.pixel; + XFreeColors( wxGlobalDisplay(), (Colormap) m_colormap, &pixel, 1, 0 ); + } + } +#endif } -wxColour::wxColour (unsigned char r, unsigned char g, unsigned char b) +void wxColourRefData::AllocColour( WXColormap cmap ) { - m_red = r; - m_green = g; - m_blue = b; - m_isInit = TRUE; - m_pixel = -1; + if (m_hasPixel && (m_colormap == cmap)) + return; + + FreeColour(); + +#if !wxUSE_NANOX + if ((wxTheApp->m_visualInfo->m_visualType == GrayScale) || + (wxTheApp->m_visualInfo->m_visualType == PseudoColor)) + { + m_hasPixel = XAllocColor( wxGlobalDisplay(), (Colormap) cmap, &m_color ); + int idx = m_color.pixel; + colMapAllocCounter[ idx ] = colMapAllocCounter[ idx ] + 1; + } + else +#endif + { + m_hasPixel = XAllocColor( wxGlobalDisplay(), (Colormap) cmap, &m_color ); + } + + m_colormap = cmap; } -wxColour::wxColour (const wxColour& col) +//----------------------------------------------------------------------------- + +#define M_COLDATA ((wxColourRefData *)m_refData) + +#define SHIFT (8*(sizeof(short int)-sizeof(char))) + +IMPLEMENT_DYNAMIC_CLASS(wxColour,wxGDIObject) + +wxColour::wxColour( unsigned char red, unsigned char green, unsigned char blue ) { - m_red = col.m_red; - m_green = col.m_green; - m_blue = col.m_blue; - m_isInit = col.m_isInit; - m_pixel = col.m_pixel; + m_refData = new wxColourRefData(); +#if wxUSE_NANOX + M_COLDATA->m_color.red = ((unsigned short)red) ; + M_COLDATA->m_color.green = ((unsigned short)green) ; + M_COLDATA->m_color.blue = ((unsigned short)blue) ; +#else + M_COLDATA->m_color.red = ((unsigned short)red) << SHIFT; + M_COLDATA->m_color.green = ((unsigned short)green) << SHIFT; + M_COLDATA->m_color.blue = ((unsigned short)blue) << SHIFT; +#endif + M_COLDATA->m_color.pixel = 0; } -wxColour& wxColour::operator =(const wxColour& col) +/* static */ +wxColour wxColour::CreateByName(const wxString& name) { - m_red = col.m_red; - m_green = col.m_green; - m_blue = col.m_blue; - m_isInit = col.m_isInit; - m_pixel = col.m_pixel; - return *this; + wxColour col; + + Display *dpy = wxGlobalDisplay(); + WXColormap colormap = wxTheApp->GetMainColormap( dpy ); + XColor xcol; + if ( XParseColor( dpy, (Colormap)colormap, name.mb_str(), &xcol ) ) + { + wxColourRefData *refData = new wxColourRefData; + refData->m_colormap = colormap; + refData->m_color = xcol; + col.m_refData = refData; + } + + return col; } -void wxColour::InitFromName(const wxString& col) +void wxColour::InitFromName( const wxString &colourName ) { - wxColour *the_colour = wxTheColourDatabase->FindColour (col); - if (the_colour) + // check the cache first + wxColour col; + if ( wxTheColourDatabase ) + { + col = wxTheColourDatabase->Find(colourName); + } + + if ( !col.Ok() ) { - m_red = the_colour->Red (); - m_green = the_colour->Green (); - m_blue = the_colour->Blue (); - m_pixel = the_colour->m_pixel; - m_isInit = TRUE; + col = CreateByName(colourName); + } + + if ( col.Ok() ) + { + *this = col; } else { - m_red = 0; - m_green = 0; - m_blue = 0; - m_isInit = FALSE; + wxFAIL_MSG( wxT("wxColour: couldn't find colour") ); } } -wxColour::~wxColour () +wxColour::~wxColour() { } -void wxColour::Set (unsigned char r, unsigned char g, unsigned char b) +bool wxColour::operator == ( const wxColour& col ) const { - m_red = r; - m_green = g; - m_blue = b; - m_isInit = TRUE; - m_pixel = -1; + if (m_refData == col.m_refData) return true; + + if (!m_refData || !col.m_refData) return false; + + XColor *own = &(((wxColourRefData*)m_refData)->m_color); + XColor *other = &(((wxColourRefData*)col.m_refData)->m_color); + + return (own->red == other->red) + && (own->green == other->green) + && (own->blue == other->blue) ; + } -// Allocate a colour, or nearest colour, using the given display. -// If realloc is TRUE, ignore the existing pixel, otherwise just return -// the existing one. -// Returns the old or allocated pixel. +wxObjectRefData *wxColour::CreateRefData() const +{ + return new wxColourRefData; +} -// TODO: can this handle mono displays? If not, we should have an extra -// flag to specify whether this should be black or white by default. +wxObjectRefData *wxColour::CloneRefData(const wxObjectRefData *data) const +{ + return new wxColourRefData(*(wxColourRefData *)data); +} -int wxColour::AllocColour(WXDisplay* display, bool realloc) +void wxColour::Set( unsigned char red, unsigned char green, unsigned char blue ) { - if ((m_pixel != -1) && !realloc) - return m_pixel; - - XColor color; - color.red = (unsigned short) Red (); - color.red |= color.red << 8; - color.green = (unsigned short) Green (); - color.green |= color.green << 8; - color.blue = (unsigned short) Blue (); - color.blue |= color.blue << 8; - - color.flags = DoRed | DoGreen | DoBlue; - - WXColormap cmap = wxTheApp->GetMainColormap(display); - - if (!XAllocColor ((Display*) display, (Colormap) cmap, &color)) - { - m_pixel = wxGetBestMatchingPixel((Display*) display, &color,(Colormap) cmap); - return m_pixel; - } - else - { - m_pixel = (int) color.pixel; - return m_pixel; - } + AllocExclusive(); + +#if wxUSE_NANOX + M_COLDATA->m_color.red = ((unsigned short)red) ; + M_COLDATA->m_color.green = ((unsigned short)green) ; + M_COLDATA->m_color.blue = ((unsigned short)blue) ; +#else + M_COLDATA->m_color.red = ((unsigned short)red) << SHIFT; + M_COLDATA->m_color.green = ((unsigned short)green) << SHIFT; + M_COLDATA->m_color.blue = ((unsigned short)blue) << SHIFT; +#endif + M_COLDATA->m_color.pixel = 0; } -/*------------------------------------------- -Markus Emmenegger -Find the pixel value with an assigned color closest to the desired color -Used if color cell allocation fails -As the returned pixel value may be in use by another application, -the color might change anytime. -But in many cases, that is still better than always using black. --- -Chris Breeze -Improvements: -1) More efficient calculation of RGB distance of colour cell from -the desired colour. There is no need to take the sqrt of 'dist', and -since we are only interested in the top 8-bits of R, G and B we -can perform integer arithmetic. -2) Attempt to allocate a read-only colour when a close match is found. -A read-only colour will not change. -3) Fall back to the closest match if no read-only colours are available. - - Possible further improvements: - 1) Scan the lookup table and sort the colour cells in order of - increasing - distance from the desired colour. Then attempt to allocate a - read-only - colour starting from the nearest match. - 2) Linear RGB distance is not a particularly good method of colour - matching - (though it is quick). Converting the colour to HLS and then comparing - may give better matching. --------------------------------------------*/ - -int wxGetBestMatchingPixel(Display *display, XColor *desiredColor, Colormap cmap) -{ - if (cmap == (Colormap) NULL) - cmap = (Colormap) wxTheApp->GetMainColormap(display); - - int numPixVals = XDisplayCells(display, DefaultScreen (display)); - int mindist = 256 * 256 * 3; - int bestpixel = (int) BlackPixel (display, DefaultScreen (display)); - int red = desiredColor->red >> 8; - int green = desiredColor->green >> 8; - int blue = desiredColor->blue >> 8; - const int threshold = 2 * 2 * 3; // allow an error of up to 2 in R,G & B - - for (int pixelcount = 0; pixelcount < numPixVals; pixelcount++) - { - XColor matching_color; - matching_color.pixel = pixelcount; - XQueryColor(display,cmap,&matching_color); - - int delta_red = red - (matching_color.red >> 8); - int delta_green = green - (matching_color.green >> 8); - int delta_blue = blue - (matching_color.blue >> 8); - - int dist = delta_red * delta_red + - delta_green * delta_green + - delta_blue * delta_blue; - - if (dist <= threshold) - { - // try to allocate a read-only colour... - if (XAllocColor (display, cmap, &matching_color)) - { - return matching_color.pixel; - } - } - if (dist < mindist) - { - bestpixel = pixelcount; - mindist = dist; - } - } - return bestpixel; +unsigned char wxColour::Red() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid colour") ); + +#if wxUSE_NANOX + return (unsigned char) M_COLDATA->m_color.red ; +#else + return (unsigned char)(M_COLDATA->m_color.red >> SHIFT); +#endif +} + +unsigned char wxColour::Green() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid colour") ); + +#if wxUSE_NANOX + return (unsigned char) M_COLDATA->m_color.green ; +#else + return (unsigned char)(M_COLDATA->m_color.green >> SHIFT); +#endif +} + +unsigned char wxColour::Blue() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid colour") ); + +#if wxUSE_NANOX + return (unsigned char) M_COLDATA->m_color.blue ; +#else + return (unsigned char)(M_COLDATA->m_color.blue >> SHIFT); +#endif +} + +void wxColour::CalcPixel( WXColormap cmap ) +{ + wxCHECK_RET( Ok(), wxT("invalid colour") ); + + wxCHECK_RET( cmap, wxT("invalid colormap") ); + + M_COLDATA->AllocColour( cmap ); +} + +unsigned long wxColour::GetPixel() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid colour") ); + + return M_COLDATA->m_color.pixel; +} + +WXColor *wxColour::GetColor() const +{ + wxCHECK_MSG( Ok(), (WXColor *) NULL, wxT("invalid colour") ); + + return (WXColor*) &M_COLDATA->m_color; }