1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1998-2001 The LyX Team
8 *======================================================*/
13 #pragma implementation
16 #include "ColorHandler.h"
21 #include "frontends/GUIRunTime.h"
23 #include <boost/scoped_array.hpp>
27 #ifndef CXX_GLOBAL_CSTD
34 LyXColorHandler::LyXColorHandler()
36 display = GUIRunTime::x11Display();
37 drawable = XCreatePixmap(display,
38 RootWindow(display, GUIRunTime::x11Screen()),
40 GUIRunTime::x11VisualDepth());
42 colormap = GUIRunTime::x11Colormap();
44 for (int i = 0; i <= LColor::ignore; ++i) {
50 LyXColorHandler::~LyXColorHandler()
52 // Release all the registered GCs
53 for (int i = 0; i <= LColor::ignore; ++i) {
54 if (colorGCcache[i] != 0) {
55 XFreeGC(display, colorGCcache[i]);
58 // Iterate over the line cache and Free the GCs
59 for (LineGCCache::iterator lit = lineGCcache.begin();
60 lit != lineGCcache.end(); ++lit) {
61 XFreeGC(display, lit->second);
66 unsigned long LyXColorHandler::colorPixel(LColor::color c)
69 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
70 return val.foreground;
74 // Gets GC according to color
76 GC LyXColorHandler::getGCForeground(LColor::color c)
78 //if (lyxerr.debugging()) {
79 // lyxerr << "Painter drawable: " << drawable() << endl;
82 if (colorGCcache[c] != 0)
83 return colorGCcache[c];
87 string const s = lcolor.getX11Name(c);
90 // Look up the RGB values for the color, and an approximate
91 // color that we can hope to get on this display.
92 if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
93 lyxerr << _("LyX: Unknown X11 color ") << s
94 << _(" for ") << lcolor.getGUIName(c) << '\n'
95 << _(" Using black instead, sorry!") << endl;
96 unsigned long bla = BlackPixel(display,
97 DefaultScreen(display));
99 // Try the exact RGB values first, then the approximate.
100 } else if (XAllocColor(display, colormap, &xcol) != 0) {
101 if (lyxerr.debugging(Debug::GUI)) {
102 lyxerr << _("LyX: X11 color ") << s
103 << _(" allocated for ")
104 << lcolor.getGUIName(c) << endl;
106 val.foreground = xcol.pixel;
107 } else if (XAllocColor(display, colormap, &ccol)) {
108 lyxerr << _("LyX: Using approximated X11 color ") << s
109 << _(" allocated for ")
110 << lcolor.getGUIName(c) << endl;
111 val.foreground = xcol.pixel;
113 // Here we are traversing the current colormap to find
114 // the color closest to the one we want.
115 Visual * vi = DefaultVisual(display, DefaultScreen(display));
117 boost::scoped_array<XColor> cmap(new XColor[vi->map_entries]);
119 for (int i = 0; i < vi->map_entries; ++i) {
122 XQueryColors(display, colormap, cmap.get(), vi->map_entries);
124 // Walk through the cmap and look for close colors.
125 int closest_pixel = 0;
126 double closest_distance = 1e20; // we want to minimize this
128 for (int t = 0; t < vi->map_entries; ++t) {
129 // The Euclidean distance between two points in
130 // a three-dimensional space, the RGB color-cube,
131 // is used as the distance measurement between two
134 // Since square-root is monotonous, we don't have to
135 // take the square-root to find the minimum, and thus
136 // we use the squared distance instead to be faster.
138 // If we want to get fancy, we could convert the RGB
139 // coordinates to a different color-cube, maybe HSV,
140 // but the RGB cube seems to work great. (Asger)
141 distance = pow(cmap[t].red - xcol.red, 2.0) +
142 pow(cmap[t].green - xcol.green, 2.0) +
143 pow(cmap[t].blue - xcol.blue, 2.0);
144 if (distance < closest_distance) {
145 closest_distance = distance;
149 lyxerr << _("LyX: Couldn't allocate '") << s
150 << _("' for ") << lcolor.getGUIName(c)
151 << _(" with (r,g,b)=(")
152 << xcol.red << "," << xcol.green << ","
153 << xcol.blue << ").\n"
154 << _(" Using closest allocated "
155 "color with (r,g,b)=(")
156 << cmap[closest_pixel].red << ","
157 << cmap[closest_pixel].green << ","
158 << cmap[closest_pixel].blue << _(") instead.\n")
159 << _("Pixel [") << closest_pixel << _("] is used.")
161 val.foreground = cmap[closest_pixel].pixel;
164 val.function = GXcopy;
165 return colorGCcache[c] = XCreateGC(display, drawable,
166 GCForeground | GCFunction, &val);
171 GC LyXColorHandler::getGCLinepars(PainterBase::line_style ls,
172 PainterBase::line_width lw, LColor::color c)
174 //if (lyxerr.debugging()) {
175 // lyxerr << "Painter drawable: " << drawable() << endl;
178 int index = lw + (ls << 1) + (c << 6);
180 LineGCCache::iterator it = lineGCcache.find(index);
181 if (it != lineGCcache.end())
185 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
188 case PainterBase::line_thin:
191 case PainterBase::line_thick:
197 case PainterBase::line_solid:
198 val.line_style = LineSolid;
200 case PainterBase::line_onoffdash:
201 val.line_style = LineOnOffDash;
203 case PainterBase::line_doubledash:
204 val.line_style = LineDoubleDash;
209 val.cap_style = CapRound;
210 val.join_style = JoinRound;
211 val.function = GXcopy;
213 return lineGCcache[index] =
214 XCreateGC(display, drawable,
215 GCForeground | GCLineStyle | GCLineWidth |
216 GCCapStyle | GCJoinStyle | GCFunction, &val);
220 // update GC cache after color redefinition
221 void LyXColorHandler::updateColor (LColor::color c)
224 GC gc = colorGCcache[c];
226 XFreeGC(display, gc);
227 colorGCcache[c] = NULL;
233 for (int ls = 0; ls < 3; ++ls)
234 for (int lw = 0; lw < 2; ++lw) {
235 int const index = lw + (ls << 1) + (c << 6);
236 LineGCCache::iterator it = lineGCcache.find(index);
237 if (it != lineGCcache.end()) {
239 XFreeGC(display, gc);
240 lineGCcache.erase(it);
241 getGCLinepars(PainterBase::line_style(ls),
242 PainterBase::line_width(lw), c);
249 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;