]> git.saurik.com Git - wxWidgets.git/blob - src/motif/colour.cpp
Fix another crash when conversion fails in Unix PostScript code.
[wxWidgets.git] / src / motif / colour.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/colour.cpp
3 // Purpose: wxColour class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 17/09/98
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 //// TODO: make wxColour a ref-counted object,
12 //// so pixel values get shared.
13
14 // For compilers that support precompilation, includes "wx.h".
15 #include "wx/wxprec.h"
16
17 #include "wx/colour.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/app.h"
21 #include "wx/gdicmn.h"
22 #endif
23
24 #ifdef __VMS__
25 #pragma message disable nosimpint
26 #endif
27 #include <Xm/Xm.h>
28 #ifdef __VMS__
29 #pragma message enable nosimpint
30 #endif
31
32 #include "wx/motif/private.h"
33
34 wxCOMPILE_TIME_ASSERT( sizeof(WXPixel) == sizeof(Pixel), PixelSizeIsOk );
35
36 // Colour
37
38 void wxColour::Init()
39 {
40 m_isInit = false;
41 m_red = m_blue = m_green = 0;
42 m_pixel = -1;
43 }
44
45 wxColour::wxColour(const wxColour& col)
46 {
47 *this = col;
48 }
49
50 wxColour& wxColour::operator =(const wxColour& col)
51 {
52 m_red = col.m_red;
53 m_green = col.m_green;
54 m_blue = col.m_blue;
55 m_isInit = col.m_isInit;
56 m_pixel = col.m_pixel;
57 return *this;
58 }
59
60 wxColour::~wxColour()
61 {
62 }
63
64 void wxColour::InitRGBA(unsigned char r, unsigned char g, unsigned char b,
65 unsigned char WXUNUSED(a))
66 {
67 m_red = r;
68 m_green = g;
69 m_blue = b;
70 m_isInit = true;
71 m_pixel = -1;
72 }
73
74 // Allocate a colour, or nearest colour, using the given display.
75 // If realloc is true, ignore the existing pixel, otherwise just return
76 // the existing one.
77 // Returns the old or allocated pixel.
78
79 // TODO: can this handle mono displays? If not, we should have an extra
80 // flag to specify whether this should be black or white by default.
81
82 WXPixel wxColour::AllocColour(WXDisplay* display, bool realloc)
83 {
84 if ((m_pixel != -1) && !realloc)
85 return m_pixel;
86
87 XColor color;
88 color.red = (unsigned short) Red ();
89 color.red |= (unsigned short)(color.red << 8);
90 color.green = (unsigned short) Green ();
91 color.green |= (unsigned short)(color.green << 8);
92 color.blue = (unsigned short) Blue ();
93 color.blue |= (unsigned short)(color.blue << 8);
94
95 color.flags = DoRed | DoGreen | DoBlue;
96
97 WXColormap cmap = wxTheApp->GetMainColormap(display);
98
99 if (!XAllocColor ((Display*) display, (Colormap) cmap, &color))
100 {
101 m_pixel = wxGetBestMatchingPixel((Display*) display, &color,(Colormap) cmap);
102 return m_pixel;
103 }
104 else
105 {
106 m_pixel = (WXPixel) color.pixel;
107 return m_pixel;
108 }
109 }
110
111 /*-------------------------------------------
112 Markus Emmenegger <mege@iqe.ethz.ch>
113 Find the pixel value with an assigned color closest to the desired color
114 Used if color cell allocation fails
115 As the returned pixel value may be in use by another application,
116 the color might change anytime.
117 But in many cases, that is still better than always using black.
118 --
119 Chris Breeze <chris@hel.co.uk>
120 Improvements:
121 1) More efficient calculation of RGB distance of colour cell from
122 the desired colour. There is no need to take the sqrt of 'dist', and
123 since we are only interested in the top 8-bits of R, G and B we
124 can perform integer arithmetic.
125 2) Attempt to allocate a read-only colour when a close match is found.
126 A read-only colour will not change.
127 3) Fall back to the closest match if no read-only colours are available.
128
129 Possible further improvements:
130 1) Scan the lookup table and sort the colour cells in order of
131 increasing
132 distance from the desired colour. Then attempt to allocate a
133 read-only
134 colour starting from the nearest match.
135 2) Linear RGB distance is not a particularly good method of colour
136 matching
137 (though it is quick). Converting the colour to HLS and then comparing
138 may give better matching.
139 -------------------------------------------*/
140
141 WXPixel wxGetBestMatchingPixel(Display *display, XColor *desiredColor, Colormap cmap)
142 {
143 if (cmap == (Colormap) NULL)
144 cmap = (Colormap) wxTheApp->GetMainColormap(display);
145
146 int numPixVals = XDisplayCells(display, DefaultScreen (display));
147 int mindist = 256 * 256 * 3;
148 Pixel bestpixel = BlackPixel (display, DefaultScreen (display));
149 int red = desiredColor->red >> 8;
150 int green = desiredColor->green >> 8;
151 int blue = desiredColor->blue >> 8;
152 const int threshold = 2 * 2 * 3; // allow an error of up to 2 in R,G & B
153
154 for (int pixelcount = 0; pixelcount < numPixVals; pixelcount++)
155 {
156 XColor matching_color;
157 matching_color.pixel = pixelcount;
158 XQueryColor(display,cmap,&matching_color);
159
160 int delta_red = red - (matching_color.red >> 8);
161 int delta_green = green - (matching_color.green >> 8);
162 int delta_blue = blue - (matching_color.blue >> 8);
163
164 int dist = delta_red * delta_red +
165 delta_green * delta_green +
166 delta_blue * delta_blue;
167
168 if (dist <= threshold)
169 {
170 // try to allocate a read-only colour...
171 if (XAllocColor (display, cmap, &matching_color))
172 {
173 return matching_color.pixel;
174 }
175 }
176 if (dist < mindist)
177 {
178 bestpixel = pixelcount;
179 mindist = dist;
180 }
181 }
182 return bestpixel;
183 }