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 #pragma implementation
17 #include "ColorHandler.h"
24 #include <boost/scoped_array.hpp>
26 #ifndef CXX_GLOBAL_CSTD
32 #include FORMS_H_LOCATION
34 LyXColorHandler::LyXColorHandler()
36 display = fl_get_display();
37 drawable = XCreatePixmap(display,
38 RootWindow(display, fl_screen),
39 10, 10, fl_get_visual_depth());
41 colormap = fl_state[fl_get_vclass()].colormap;
43 for (int i = 0; i <= LColor::ignore; ++i) {
49 LyXColorHandler::~LyXColorHandler()
51 // Release all the registered GCs
52 for (int i = 0; i <= LColor::ignore; ++i) {
53 if (colorGCcache[i] != 0) {
54 XFreeGC(display, colorGCcache[i]);
57 // Iterate over the line cache and Free the GCs
58 for (LineGCCache::iterator lit = lineGCcache.begin();
59 lit != lineGCcache.end(); ++lit) {
60 XFreeGC(display, lit->second);
65 unsigned long LyXColorHandler::colorPixel(LColor::color c)
68 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
69 return val.foreground;
73 // Gets GC according to color
75 GC LyXColorHandler::getGCForeground(LColor::color c)
77 if (colorGCcache[c] != 0)
78 return colorGCcache[c];
82 string const s = lcolor.getX11Name(c);
85 // Look up the RGB values for the color, and an approximate
86 // color that we can hope to get on this display.
87 if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
88 lyxerr << _("LyX: Unknown X11 color ") << s
89 << _(" for ") << lcolor.getGUIName(c) << '\n'
90 << _(" Using black instead, sorry!") << endl;
91 unsigned long bla = BlackPixel(display,
92 DefaultScreen(display));
94 // Try the exact RGB values first, then the approximate.
95 } else if (XAllocColor(display, colormap, &xcol) != 0) {
96 if (lyxerr.debugging(Debug::GUI)) {
97 lyxerr << _("LyX: X11 color ") << s
98 << _(" allocated for ")
99 << lcolor.getGUIName(c) << endl;
101 val.foreground = xcol.pixel;
102 } else if (XAllocColor(display, colormap, &ccol)) {
103 lyxerr << _("LyX: Using approximated X11 color ") << s
104 << _(" allocated for ")
105 << lcolor.getGUIName(c) << endl;
106 val.foreground = xcol.pixel;
108 // Here we are traversing the current colormap to find
109 // the color closest to the one we want.
110 Visual * vi = DefaultVisual(display, DefaultScreen(display));
112 boost::scoped_array<XColor> cmap(new XColor[vi->map_entries]);
114 for (int i = 0; i < vi->map_entries; ++i) {
117 XQueryColors(display, colormap, cmap.get(), vi->map_entries);
119 // Walk through the cmap and look for close colors.
120 int closest_pixel = 0;
121 double closest_distance = 1e20; // we want to minimize this
123 for (int t = 0; t < vi->map_entries; ++t) {
124 // The Euclidean distance between two points in
125 // a three-dimensional space, the RGB color-cube,
126 // is used as the distance measurement between two
129 // Since square-root is monotonous, we don't have to
130 // take the square-root to find the minimum, and thus
131 // we use the squared distance instead to be faster.
133 // If we want to get fancy, we could convert the RGB
134 // coordinates to a different color-cube, maybe HSV,
135 // but the RGB cube seems to work great. (Asger)
136 distance = pow(cmap[t].red - xcol.red, 2.0) +
137 pow(cmap[t].green - xcol.green, 2.0) +
138 pow(cmap[t].blue - xcol.blue, 2.0);
139 if (distance < closest_distance) {
140 closest_distance = distance;
144 lyxerr << _("LyX: Couldn't allocate '") << s
145 << _("' for ") << lcolor.getGUIName(c)
146 << _(" with (r,g,b)=(")
147 << xcol.red << "," << xcol.green << ","
148 << xcol.blue << ").\n"
149 << _(" Using closest allocated "
150 "color with (r,g,b)=(")
151 << cmap[closest_pixel].red << ","
152 << cmap[closest_pixel].green << ","
153 << cmap[closest_pixel].blue << _(") instead.\n")
154 << _("Pixel [") << closest_pixel << _("] is used.")
156 val.foreground = cmap[closest_pixel].pixel;
159 val.function = GXcopy;
160 return colorGCcache[c] = XCreateGC(display, drawable,
161 GCForeground | GCFunction, &val);
166 GC LyXColorHandler::getGCLinepars(Painter::line_style ls,
167 Painter::line_width lw, LColor::color c)
169 //if (lyxerr.debugging()) {
170 // lyxerr << "Painter drawable: " << drawable() << endl;
173 int index = lw + (ls << 1) + (c << 6);
175 LineGCCache::iterator it = lineGCcache.find(index);
176 if (it != lineGCcache.end())
180 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
183 case Painter::line_thin:
186 case Painter::line_thick:
192 case Painter::line_solid:
193 val.line_style = LineSolid;
195 case Painter::line_onoffdash:
196 val.line_style = LineOnOffDash;
201 val.cap_style = CapRound;
202 val.join_style = JoinRound;
203 val.function = GXcopy;
205 return lineGCcache[index] =
206 XCreateGC(display, drawable,
207 GCForeground | GCLineStyle | GCLineWidth |
208 GCCapStyle | GCJoinStyle | GCFunction, &val);
212 // update GC cache after color redefinition
213 void LyXColorHandler::updateColor (LColor::color c)
216 GC gc = colorGCcache[c];
218 XFreeGC(display, gc);
219 colorGCcache[c] = NULL;
225 for (int ls = 0; ls < 3; ++ls)
226 for (int lw = 0; lw < 2; ++lw) {
227 int const index = lw + (ls << 1) + (c << 6);
228 LineGCCache::iterator it = lineGCcache.find(index);
229 if (it != lineGCcache.end()) {
231 XFreeGC(display, gc);
232 lineGCcache.erase(it);
233 getGCLinepars(Painter::line_style(ls),
234 Painter::line_width(lw), c);
241 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;