]> git.lyx.org Git - features.git/blob - src/frontends/xforms/ColorHandler.C
Compaq cxx 6.5 will now compile lyx.
[features.git] / src / frontends / xforms / ColorHandler.C
1 /* This file is part of
2  * ======================================================
3  *
4  *           LyX, The Document Processor
5  *
6  *          Copyright 1998-2001 The LyX Team
7  *
8  *======================================================*/
9
10 #include <config.h>
11
12 #ifdef __GNUG__
13 #pragma implementation
14 #endif
15
16 #include "ColorHandler.h"
17 #include "LColor.h"
18 #include "gettext.h"
19 #include "debug.h"
20
21 #include "frontends/GUIRunTime.h"
22
23 #include <boost/scoped_array.hpp>
24
25 #include <cmath>
26
27 #ifndef CXX_GLOBAL_CSTD
28 using std::pow;
29 #endif
30
31 using std::endl;
32
33
34 LyXColorHandler::LyXColorHandler()
35 {
36         display = GUIRunTime::x11Display();
37         drawable = XCreatePixmap(display,
38                                  RootWindow(display, GUIRunTime::x11Screen()),
39                                  10, 10,
40                                  GUIRunTime::x11VisualDepth());
41
42         colormap = GUIRunTime::x11Colormap();
43         // Clear the GC cache
44         for (int i = 0; i <= LColor::ignore; ++i) {
45                 colorGCcache[i] = 0;
46         }
47 }
48
49
50 LyXColorHandler::~LyXColorHandler()
51 {
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]);
56                 }
57         }
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);
62         }
63 }
64
65
66 unsigned long LyXColorHandler::colorPixel(LColor::color c)
67 {
68         XGCValues val;
69         XGetGCValues(display, getGCForeground(c), GCForeground, &val);
70         return val.foreground;
71 }
72
73
74 // Gets GC according to color
75 // Uses caching
76 GC LyXColorHandler::getGCForeground(LColor::color c)
77 {
78         //if (lyxerr.debugging()) {
79         //      lyxerr << "Painter drawable: " << drawable() << endl;
80         //}
81
82         if (colorGCcache[c] != 0)
83                 return colorGCcache[c];
84
85         XColor xcol;
86         XColor ccol;
87         string const s = lcolor.getX11Name(c);
88         XGCValues val;
89
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));
98                 val.foreground = bla;
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;
105                 }
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;
112         } else {
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));
116
117                 boost::scoped_array<XColor> cmap(new XColor[vi->map_entries]);
118
119                 for (int i = 0; i < vi->map_entries; ++i) {
120                         cmap[i].pixel = i;
121                 }
122                 XQueryColors(display, colormap, cmap.get(), vi->map_entries);
123
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
127                 double distance = 0;
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
132                         // colors.
133
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.
137
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;
146                                 closest_pixel = t;
147                         }
148                 }
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.")
160                        << endl;
161                 val.foreground = cmap[closest_pixel].pixel;
162         }
163
164         val.function = GXcopy;
165         return colorGCcache[c] = XCreateGC(display, drawable,
166                                     GCForeground | GCFunction, &val);
167 }
168
169
170 // Gets GC for line
171 GC LyXColorHandler::getGCLinepars(PainterBase::line_style ls,
172                                   PainterBase::line_width lw, LColor::color c)
173 {
174         //if (lyxerr.debugging()) {
175         //      lyxerr << "Painter drawable: " << drawable() << endl;
176         //}
177
178         int index = lw + (ls << 1) + (c << 6);
179
180         LineGCCache::iterator it = lineGCcache.find(index);
181         if (it != lineGCcache.end())
182                 return it->second;
183
184         XGCValues val;
185         XGetGCValues(display, getGCForeground(c), GCForeground, &val);
186
187         switch (lw) {
188         case PainterBase::line_thin:
189                 val.line_width = 0;
190                 break;
191         case PainterBase::line_thick:
192                 val.line_width = 2;
193                 break;
194         }
195
196         switch (ls) {
197         case PainterBase::line_solid:
198                 val.line_style = LineSolid;
199                 break;
200         case PainterBase::line_onoffdash:
201                 val.line_style = LineOnOffDash;
202                 break;
203         case PainterBase::line_doubledash:
204                 val.line_style = LineDoubleDash;
205                 break;
206         }
207
208
209         val.cap_style = CapRound;
210         val.join_style = JoinRound;
211         val.function = GXcopy;
212
213         return lineGCcache[index] =
214                 XCreateGC(display, drawable,
215                           GCForeground | GCLineStyle | GCLineWidth |
216                           GCCapStyle | GCJoinStyle | GCFunction, &val);
217 }
218
219
220 // update GC cache after color redefinition
221 void LyXColorHandler::updateColor (LColor::color c)
222 {
223         // color GC cache
224         GC gc = colorGCcache[c];
225         if (gc != 0) {
226                 XFreeGC(display, gc);
227                 colorGCcache[c] = NULL;
228                 getGCForeground(c);
229         }
230
231         // line GC cache
232
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()) {
238                                 gc = it->second;
239                                 XFreeGC(display, gc);
240                                 lineGCcache.erase(it);
241                                 getGCLinepars(PainterBase::line_style(ls),
242                                               PainterBase::line_width(lw), c);
243                         }
244                 }
245
246 }
247
248 //
249 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;