]> git.lyx.org Git - lyx.git/blob - src/ColorHandler.C
ws change
[lyx.git] / src / 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 <cmath>
24
25 using std::endl;
26
27
28 LyXColorHandler::LyXColorHandler()
29 {
30         display = GUIRunTime::x11Display();
31         drawable = XCreatePixmap(display,
32                                  RootWindow(display, GUIRunTime::x11Screen()),
33                                  10, 10,
34                                  GUIRunTime::x11VisualDepth());
35
36         colormap = GUIRunTime::x11Colormap();
37         // Clear the GC cache
38         for (int i = 0; i <= LColor::ignore; ++i) {
39                 colorGCcache[i] = 0;
40         }
41 }
42
43
44 LyXColorHandler::~LyXColorHandler()
45 {
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]);
50                 }
51         }
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);
56         }
57 }
58
59
60 unsigned long LyXColorHandler::colorPixel(LColor::color c)
61 {
62         XGCValues val;
63         XGetGCValues(display, getGCForeground(c), GCForeground, &val);
64         return val.foreground;
65 }
66
67
68 // Gets GC according to color
69 // Uses caching
70 GC LyXColorHandler::getGCForeground(LColor::color c)
71 {
72         //if (lyxerr.debugging()) {
73         //      lyxerr << "Painter drawable: " << drawable() << endl;
74         //}
75
76         if (colorGCcache[c] != 0)
77                 return colorGCcache[c];
78
79         XColor xcol;
80         XColor ccol;
81         string const s = lcolor.getX11Name(c);
82         XGCValues val;
83
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));
92                 val.foreground = bla;
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;
99                 }
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;
106         } else {
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));
110
111                 boost::scoped_array<XColor> cmap(new XColor[vi->map_entries]);
112
113                 for (int i = 0; i < vi->map_entries; ++i) {
114                         cmap[i].pixel = i;
115                 }
116                 XQueryColors(display, colormap, cmap.get(), vi->map_entries);
117
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
121                 double distance = 0;
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
126                         // colors.
127
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.
131
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;
140                                 closest_pixel = t;
141                         }
142                 }
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.")
154                        << endl;
155                 val.foreground = cmap[closest_pixel].pixel;
156         }
157
158         val.function = GXcopy;
159         return colorGCcache[c] = XCreateGC(display, drawable,
160                                     GCForeground | GCFunction, &val);
161 }
162
163
164 // Gets GC for line
165 GC LyXColorHandler::getGCLinepars(PainterBase::line_style ls,
166                                   PainterBase::line_width lw, LColor::color c)
167 {
168         //if (lyxerr.debugging()) {
169         //      lyxerr << "Painter drawable: " << drawable() << endl;
170         //}
171
172         int index = lw + (ls << 1) + (c << 6);
173
174         LineGCCache::iterator it = lineGCcache.find(index);
175         if (it != lineGCcache.end())
176                 return it->second;
177
178         XGCValues val;
179         XGetGCValues(display, getGCForeground(c), GCForeground, &val);
180
181         switch (lw) {
182         case PainterBase::line_thin:
183                 val.line_width = 0;
184                 break;
185         case PainterBase::line_thick:
186                 val.line_width = 2;
187                 break;
188         }
189
190         switch (ls) {
191         case PainterBase::line_solid:
192                 val.line_style = LineSolid;
193                 break;
194         case PainterBase::line_onoffdash:
195                 val.line_style = LineOnOffDash;
196                 break;
197         case PainterBase::line_doubledash:
198                 val.line_style = LineDoubleDash;
199                 break;
200         }
201
202
203         val.cap_style = CapRound;
204         val.join_style = JoinRound;
205         val.function = GXcopy;
206
207         return lineGCcache[index] =
208                 XCreateGC(display, drawable,
209                           GCForeground | GCLineStyle | GCLineWidth |
210                           GCCapStyle | GCJoinStyle | GCFunction, &val);
211 }
212
213
214 // update GC cache after color redefinition
215 void LyXColorHandler::updateColor (LColor::color c)
216 {
217         // color GC cache
218         GC gc = colorGCcache[c];
219         if (gc != 0) {
220                 XFreeGC(display, gc);
221                 colorGCcache[c] = NULL;
222                 getGCForeground(c);
223         }
224
225         // line GC cache
226
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()) {
232                                 gc = it->second;
233                                 XFreeGC(display, gc);
234                                 lineGCcache.erase(it);
235                                 getGCLinepars(PainterBase::line_style(ls),
236                                               PainterBase::line_width(lw), c);
237                         }
238                 }
239
240 }
241
242 //
243 boost::scoped_ptr<LyXColorHandler> lyxColorHandler;