1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1998-2001 The LyX Team
8 *======================================================*/
13 #pragma implementation
18 #include "frontends/GUIRunTime.h"
19 #include "ColorHandler.h"
26 LyXColorHandler::LyXColorHandler()
28 display = GUIRunTime::x11Display();
29 drawable = XCreatePixmap(display,
30 RootWindow(display, GUIRunTime::x11Screen()),
32 GUIRunTime::x11VisualDepth());
34 colormap = GUIRunTime::x11Colormap();
36 for (int i = 0; i <= LColor::ignore; ++i) {
42 LyXColorHandler::~LyXColorHandler()
44 // Release all the registered GCs
45 for (int i = 0; i <= LColor::ignore; ++i) {
46 if (colorGCcache[i] != 0) {
47 XFreeGC(display, colorGCcache[i]);
50 // Iterate over the line cache and Free the GCs
51 for (LineGCCache::iterator lit = lineGCcache.begin();
52 lit != lineGCcache.end(); ++lit) {
53 XFreeGC(display, (*lit).second);
58 unsigned long LyXColorHandler::colorPixel(LColor::color c)
61 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
62 return val.foreground;
66 // Gets GC according to color
68 GC LyXColorHandler::getGCForeground(LColor::color c)
70 //if (lyxerr.debugging()) {
71 // lyxerr << "Painter drawable: " << drawable() << endl;
74 if (colorGCcache[c] != 0) return colorGCcache[c];
77 string s = lcolor.getX11Name(c);
80 // Look up the RGB values for the color, and an approximate
81 // color that we can hope to get on this display.
82 if (XLookupColor(display, colormap, s.c_str(), &xcol, &ccol) == 0) {
83 lyxerr << _("LyX: Unknown X11 color ") << s
84 << _(" for ") << lcolor.getGUIName(c) << '\n'
85 << _(" Using black instead, sorry!.") << endl;
86 unsigned long bla = BlackPixel(display,
87 DefaultScreen(display));
89 // Try the exact RGB values first, then the approximate.
90 } else if (XAllocColor(display, colormap, &xcol) != 0) {
91 if (lyxerr.debugging()) {
92 lyxerr << _("LyX: X11 color ") << s
93 << _(" allocated for ")
94 << lcolor.getGUIName(c) << endl;
96 val.foreground = xcol.pixel;
97 } else if (XAllocColor(display, colormap, &ccol)) {
98 lyxerr << _("LyX: Using approximated X11 color ") << s
99 << _(" allocated for ")
100 << lcolor.getGUIName(c) << endl;
101 val.foreground = xcol.pixel;
103 // Here we are traversing the current colormap to find
104 // the color closest to the one we want.
105 Visual * vi = DefaultVisual(display, DefaultScreen(display));
107 XColor * cmap = new XColor[vi->map_entries];
109 for (int i = 0; i < vi->map_entries; ++i) {
112 XQueryColors(display, colormap, cmap, vi->map_entries);
114 // Walk through the cmap and look for close colors.
115 int closest_pixel = 0;
116 double closest_distance = 1e20; // we want to minimize this
118 for (int t = 0; t < vi->map_entries; ++t) {
119 // The Euclidean distance between two points in
120 // a three-dimensional space, the RGB color-cube,
121 // is used as the distance measurement between two
124 // Since square-root is monotonous, we don't have to
125 // take the square-root to find the minimum, and thus
126 // we use the squared distance instead to be faster.
128 // If we want to get fancy, we could convert the RGB
129 // coordinates to a different color-cube, maybe HSV,
130 // but the RGB cube seems to work great. (Asger)
131 distance = pow(cmap[t].red - xcol.red, 2.0) +
132 pow(cmap[t].green - xcol.green, 2.0) +
133 pow(cmap[t].blue - xcol.blue, 2.0);
134 if (distance < closest_distance) {
135 closest_distance = distance;
139 lyxerr << _("LyX: Couldn't allocate '") << s
140 << _("' for ") << lcolor.getGUIName(c)
141 << _(" with (r,g,b)=(")
142 << xcol.red << "," << xcol.green << ","
143 << xcol.blue << ").\n"
144 << _(" Using closest allocated "
145 "color with (r,g,b)=(")
146 << cmap[closest_pixel].red << ","
147 << cmap[closest_pixel].green << ","
148 << cmap[closest_pixel].blue << _(") instead.\n")
149 << _("Pixel [") << closest_pixel << _("] is used.")
151 val.foreground = cmap[closest_pixel].pixel;
155 val.function = GXcopy;
156 return colorGCcache[c] = XCreateGC(display, drawable,
157 GCForeground | GCFunction, &val);
162 GC LyXColorHandler::getGCLinepars(PainterBase::line_style ls,
163 PainterBase::line_width lw, LColor::color c)
165 //if (lyxerr.debugging()) {
166 // lyxerr << "Painter drawable: " << drawable() << endl;
169 int index = lw + (ls << 1) + (c << 3);
171 if (lineGCcache.find(index) != lineGCcache.end())
172 return lineGCcache[index];
175 XGetGCValues(display, getGCForeground(c), GCForeground, &val);
178 case PainterBase::line_thin: val.line_width = 0; break;
179 case PainterBase::line_thick: val.line_width = 2; break;
183 case PainterBase::line_solid: val.line_style = LineSolid; break;
184 case PainterBase::line_onoffdash: val.line_style = LineOnOffDash; break;
185 case PainterBase::line_doubledash: val.line_style = LineDoubleDash; break;
189 val.cap_style = CapRound;
190 val.join_style = JoinRound;
191 val.function = GXcopy;
193 return lineGCcache[index] =
194 XCreateGC(display, drawable,
195 GCForeground | GCLineStyle | GCLineWidth |
196 GCCapStyle | GCJoinStyle | GCFunction, &val);
200 // update GC cache after color redefinition
201 void LyXColorHandler::updateColor (LColor::color c)
204 GC gc = colorGCcache[c];
206 XFreeGC(display, gc);
207 colorGCcache[c] = NULL;
214 for (ls=0; ls<3; ++ls)
215 for (lw=0; lw<2; ++lw) {
216 index = lw + (ls << 1) + (c << 3);
217 if (lineGCcache.find(index) != lineGCcache.end()) {
218 gc = lineGCcache[index];
220 lineGCcache.erase(index);
221 getGCLinepars(PainterBase::line_style(ls),
222 PainterBase::line_width(lw), c);
229 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;