3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS
14 #include "ColorHandler.h"
19 #include <boost/scoped_array.hpp>
20 #include "support/BoostFormat.h"
24 #ifndef CXX_GLOBAL_CSTD
30 #include "lyx_forms.h"
32 LyXColorHandler::LyXColorHandler()
34 display = fl_get_display();
35 drawable = XCreatePixmap(display,
36 RootWindow(display, fl_screen),
37 10, 10, fl_get_visual_depth());
39 colormap = fl_state[fl_get_vclass()].colormap;
41 for (int i = 0; i <= LColor::ignore; ++i) {
47 LyXColorHandler::~LyXColorHandler()
49 // Release all the registered GCs
50 for (int i = 0; i <= LColor::ignore; ++i) {
51 if (colorGCcache[i] != 0) {
52 XFreeGC(display, colorGCcache[i]);
55 // Iterate over the line cache and Free the GCs
56 for (LineGCCache::iterator lit = lineGCcache.begin();
57 lit != lineGCcache.end(); ++lit) {
58 XFreeGC(display, lit->second);
63 unsigned long LyXColorHandler::colorPixel(LColor::color c)
66 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
67 return val.foreground;
71 // Gets GC according to color
73 GC LyXColorHandler::getGCForeground(LColor::color c)
75 if (colorGCcache[c] != 0)
76 return colorGCcache[c];
80 string const s = lcolor.getX11Name(c);
83 // Look up the RGB values for the color, and an approximate
84 // color that we can hope to get on this display.
85 if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
87 lyxerr << boost::format(
88 _("LyX: Unknown X11 color %1$s for %2$s\n"
89 " Using black instead, sorry!"))
91 % lcolor.getGUIName(c)
94 lyxerr << _("LyX: Unknown X11 color ") << s << _(" for ")
95 << lcolor.getGUIName(c)
96 << _("\n Using black instead, sorry!") << endl;
98 unsigned long bla = BlackPixel(display,
99 DefaultScreen(display));
100 val.foreground = bla;
101 // Try the exact RGB values first, then the approximate.
102 } else if (XAllocColor(display, colormap, &xcol) != 0) {
103 if (lyxerr.debugging(Debug::GUI)) {
105 lyxerr << boost::format(
106 _("LyX: X11 color %1$s allocated for %2$s"))
108 % lcolor.getGUIName(c)
111 lyxerr << _("LyX: X11 color ") << s
112 << _(" allocated for ") << lcolor.getGUIName(c)
116 val.foreground = xcol.pixel;
117 } else if (XAllocColor(display, colormap, &ccol)) {
119 lyxerr << boost::format(
120 _("LyX: Using approximated X11 color %1$s"
121 " allocated for %2$s"))
123 % lcolor.getGUIName(c)
126 lyxerr << _("LyX: Using approximated X11 color ") << s
127 << _(" allocated for ") << lcolor.getGUIName(c)
130 val.foreground = xcol.pixel;
132 // Here we are traversing the current colormap to find
133 // the color closest to the one we want.
134 Visual * vi = DefaultVisual(display, DefaultScreen(display));
136 boost::scoped_array<XColor> cmap(new XColor[vi->map_entries]);
138 for (int i = 0; i < vi->map_entries; ++i) {
141 XQueryColors(display, colormap, cmap.get(), vi->map_entries);
143 // Walk through the cmap and look for close colors.
144 int closest_pixel = 0;
145 double closest_distance = 1e20; // we want to minimize this
147 for (int t = 0; t < vi->map_entries; ++t) {
148 // The Euclidean distance between two points in
149 // a three-dimensional space, the RGB color-cube,
150 // is used as the distance measurement between two
153 // Since square-root is monotonous, we don't have to
154 // take the square-root to find the minimum, and thus
155 // we use the squared distance instead to be faster.
157 // If we want to get fancy, we could convert the RGB
158 // coordinates to a different color-cube, maybe HSV,
159 // but the RGB cube seems to work great. (Asger)
160 distance = pow(cmap[t].red - xcol.red, 2.0) +
161 pow(cmap[t].green - xcol.green, 2.0) +
162 pow(cmap[t].blue - xcol.blue, 2.0);
163 if (distance < closest_distance) {
164 closest_distance = distance;
170 lyxerr << boost::format(
171 _("LyX: Couldn't allocate '%1$s' for %2$s"
172 " with (r,g,b)=(%3$d,%4$d,%5$d).\n"
173 " Using closest allocated color"
174 " with (r,g,b)=(%6$d,%7$d,%8$d) instead.\n"
175 "Pixel [%9$d] is used."))
177 % lcolor.getGUIName(c)
178 % xcol.red % xcol.green % xcol.blue
179 % cmap[closest_pixel].red
180 % cmap[closest_pixel].green
181 % cmap[closest_pixel].blue
185 lyxerr << _("LyX: Couldn't allocate '") << s
186 << _("' for ") << lcolor.getGUIName(c)
187 << _(" with (r,g,b)=(")
188 << xcol.red << ',' << xcol.green << ',' << xcol.blue
190 << _(" Using closest allocated color with (r,g,b)=(")
191 << cmap[closest_pixel].red << ','
192 << cmap[closest_pixel].green << ','
193 << cmap[closest_pixel].blue
194 << _(") instead.\nPixel [")
195 << closest_pixel << _("] is used.")
198 val.foreground = cmap[closest_pixel].pixel;
201 val.function = GXcopy;
202 return colorGCcache[c] = XCreateGC(display, drawable,
203 GCForeground | GCFunction, &val);
208 GC LyXColorHandler::getGCLinepars(Painter::line_style ls,
209 Painter::line_width lw, LColor::color c)
211 //if (lyxerr.debugging()) {
212 // lyxerr << "Painter drawable: " << drawable() << endl;
215 int index = lw + (ls << 1) + (c << 6);
217 LineGCCache::iterator it = lineGCcache.find(index);
218 if (it != lineGCcache.end())
222 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
225 case Painter::line_thin:
228 case Painter::line_thick:
234 case Painter::line_solid:
235 val.line_style = LineSolid;
237 case Painter::line_onoffdash:
238 val.line_style = LineOnOffDash;
243 val.cap_style = CapRound;
244 val.join_style = JoinRound;
245 val.function = GXcopy;
247 return lineGCcache[index] =
248 XCreateGC(display, drawable,
249 GCForeground | GCLineStyle | GCLineWidth |
250 GCCapStyle | GCJoinStyle | GCFunction, &val);
254 // update GC cache after color redefinition
255 void LyXColorHandler::updateColor (LColor::color c)
258 GC gc = colorGCcache[c];
260 XFreeGC(display, gc);
261 colorGCcache[c] = NULL;
267 for (int ls = 0; ls < 3; ++ls)
268 for (int lw = 0; lw < 2; ++lw) {
269 int const index = lw + (ls << 1) + (c << 6);
270 LineGCCache::iterator it = lineGCcache.find(index);
271 if (it != lineGCcache.end()) {
273 XFreeGC(display, gc);
274 lineGCcache.erase(it);
275 getGCLinepars(Painter::line_style(ls),
276 Painter::line_width(lw), c);
283 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;