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"
28 LyXColorHandler::LyXColorHandler()
30 display = GUIRunTime::x11Display();
31 drawable = XCreatePixmap(display,
32 RootWindow(display, GUIRunTime::x11Screen()),
34 GUIRunTime::x11VisualDepth());
36 colormap = GUIRunTime::x11Colormap();
38 for (int i = 0; i <= LColor::ignore; ++i) {
44 LyXColorHandler::~LyXColorHandler()
46 // Release all the registered GCs
47 for (int i = 0; i <= LColor::ignore; ++i) {
48 if (colorGCcache[i] != 0) {
49 XFreeGC(display, colorGCcache[i]);
52 // Iterate over the line cache and Free the GCs
53 for (LineGCCache::iterator lit = lineGCcache.begin();
54 lit != lineGCcache.end(); ++lit) {
55 XFreeGC(display, lit->second);
60 unsigned long LyXColorHandler::colorPixel(LColor::color c)
63 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
64 return val.foreground;
68 // Gets GC according to color
70 GC LyXColorHandler::getGCForeground(LColor::color c)
72 //if (lyxerr.debugging()) {
73 // lyxerr << "Painter drawable: " << drawable() << endl;
76 if (colorGCcache[c] != 0)
77 return colorGCcache[c];
81 string const s = lcolor.getX11Name(c);
84 // Look up the RGB values for the color, and an approximate
85 // color that we can hope to get on this display.
86 if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
87 lyxerr << _("LyX: Unknown X11 color ") << s
88 << _(" for ") << lcolor.getGUIName(c) << '\n'
89 << _(" Using black instead, sorry!.") << endl;
90 unsigned long bla = BlackPixel(display,
91 DefaultScreen(display));
93 // Try the exact RGB values first, then the approximate.
94 } else if (XAllocColor(display, colormap, &xcol) != 0) {
95 if (lyxerr.debugging(Debug::GUI)) {
96 lyxerr << _("LyX: X11 color ") << s
97 << _(" allocated for ")
98 << lcolor.getGUIName(c) << endl;
100 val.foreground = xcol.pixel;
101 } else if (XAllocColor(display, colormap, &ccol)) {
102 lyxerr << _("LyX: Using approximated X11 color ") << s
103 << _(" allocated for ")
104 << lcolor.getGUIName(c) << endl;
105 val.foreground = xcol.pixel;
107 // Here we are traversing the current colormap to find
108 // the color closest to the one we want.
109 Visual * vi = DefaultVisual(display, DefaultScreen(display));
111 boost::scoped_array<XColor> cmap(new XColor[vi->map_entries]);
113 for (int i = 0; i < vi->map_entries; ++i) {
116 XQueryColors(display, colormap, cmap.get(), vi->map_entries);
118 // Walk through the cmap and look for close colors.
119 int closest_pixel = 0;
120 double closest_distance = 1e20; // we want to minimize this
122 for (int t = 0; t < vi->map_entries; ++t) {
123 // The Euclidean distance between two points in
124 // a three-dimensional space, the RGB color-cube,
125 // is used as the distance measurement between two
128 // Since square-root is monotonous, we don't have to
129 // take the square-root to find the minimum, and thus
130 // we use the squared distance instead to be faster.
132 // If we want to get fancy, we could convert the RGB
133 // coordinates to a different color-cube, maybe HSV,
134 // but the RGB cube seems to work great. (Asger)
135 distance = pow(cmap[t].red - xcol.red, 2.0) +
136 pow(cmap[t].green - xcol.green, 2.0) +
137 pow(cmap[t].blue - xcol.blue, 2.0);
138 if (distance < closest_distance) {
139 closest_distance = distance;
143 lyxerr << _("LyX: Couldn't allocate '") << s
144 << _("' for ") << lcolor.getGUIName(c)
145 << _(" with (r,g,b)=(")
146 << xcol.red << "," << xcol.green << ","
147 << xcol.blue << ").\n"
148 << _(" Using closest allocated "
149 "color with (r,g,b)=(")
150 << cmap[closest_pixel].red << ","
151 << cmap[closest_pixel].green << ","
152 << cmap[closest_pixel].blue << _(") instead.\n")
153 << _("Pixel [") << closest_pixel << _("] is used.")
155 val.foreground = cmap[closest_pixel].pixel;
158 val.function = GXcopy;
159 return colorGCcache[c] = XCreateGC(display, drawable,
160 GCForeground | GCFunction, &val);
165 GC LyXColorHandler::getGCLinepars(PainterBase::line_style ls,
166 PainterBase::line_width lw, LColor::color c)
168 //if (lyxerr.debugging()) {
169 // lyxerr << "Painter drawable: " << drawable() << endl;
172 int index = lw + (ls << 1) + (c << 6);
174 LineGCCache::iterator it = lineGCcache.find(index);
175 if (it != lineGCcache.end())
179 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
182 case PainterBase::line_thin:
185 case PainterBase::line_thick:
191 case PainterBase::line_solid:
192 val.line_style = LineSolid;
194 case PainterBase::line_onoffdash:
195 val.line_style = LineOnOffDash;
197 case PainterBase::line_doubledash:
198 val.line_style = LineDoubleDash;
203 val.cap_style = CapRound;
204 val.join_style = JoinRound;
205 val.function = GXcopy;
207 return lineGCcache[index] =
208 XCreateGC(display, drawable,
209 GCForeground | GCLineStyle | GCLineWidth |
210 GCCapStyle | GCJoinStyle | GCFunction, &val);
214 // update GC cache after color redefinition
215 void LyXColorHandler::updateColor (LColor::color c)
218 GC gc = colorGCcache[c];
220 XFreeGC(display, gc);
221 colorGCcache[c] = NULL;
227 for (int ls = 0; ls < 3; ++ls)
228 for (int lw = 0; lw < 2; ++lw) {
229 int const index = lw + (ls << 1) + (c << 6);
230 LineGCCache::iterator it = lineGCcache.find(index);
231 if (it != lineGCcache.end()) {
233 XFreeGC(display, gc);
234 lineGCcache.erase(it);
235 getGCLinepars(PainterBase::line_style(ls),
236 PainterBase::line_width(lw), c);
243 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;