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 //XColor * cmap = new XColor[vi->map_entries];
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;
160 val.function = GXcopy;
161 return colorGCcache[c] = XCreateGC(display, drawable,
162 GCForeground | GCFunction, &val);
167 GC LyXColorHandler::getGCLinepars(PainterBase::line_style ls,
168 PainterBase::line_width lw, LColor::color c)
170 //if (lyxerr.debugging()) {
171 // lyxerr << "Painter drawable: " << drawable() << endl;
174 int index = lw + (ls << 1) + (c << 6);
176 LineGCCache::iterator it = lineGCcache.find(index);
177 if (it != lineGCcache.end())
181 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
184 case PainterBase::line_thin:
187 case PainterBase::line_thick:
193 case PainterBase::line_solid:
194 val.line_style = LineSolid;
196 case PainterBase::line_onoffdash:
197 val.line_style = LineOnOffDash;
199 case PainterBase::line_doubledash:
200 val.line_style = LineDoubleDash;
205 val.cap_style = CapRound;
206 val.join_style = JoinRound;
207 val.function = GXcopy;
209 return lineGCcache[index] =
210 XCreateGC(display, drawable,
211 GCForeground | GCLineStyle | GCLineWidth |
212 GCCapStyle | GCJoinStyle | GCFunction, &val);
216 // update GC cache after color redefinition
217 void LyXColorHandler::updateColor (LColor::color c)
220 GC gc = colorGCcache[c];
222 XFreeGC(display, gc);
223 colorGCcache[c] = NULL;
229 for (int ls = 0; ls < 3; ++ls)
230 for (int lw = 0; lw < 2; ++lw) {
231 int const index = lw + (ls << 1) + (c << 6);
232 LineGCCache::iterator it = lineGCcache.find(index);
233 if (it != lineGCcache.end()) {
235 XFreeGC(display, gc);
236 lineGCcache.erase(it);
237 getGCLinepars(PainterBase::line_style(ls),
238 PainterBase::line_width(lw), c);
245 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;