add RrColorGC
[mikachu/openbox.git] / render / color.c
1 #include "render.h"
2 #include "color.h"
3
4 #include <X11/Xlib.h>
5 #include <X11/Xutil.h>
6 #include <string.h>
7
8 void RrColorAllocateGC(RrColor *in)
9 {
10     XGCValues gcv;
11
12     gcv.foreground = in->pixel;
13     gcv.cap_style = CapProjecting;
14     in->gc = XCreateGC(RrDisplay(in->inst),
15                        RrRootWindow(in->inst),
16                        GCForeground | GCCapStyle, &gcv);
17 }
18
19 RrColor *RrColorParse(const RrInstance *inst, gchar *colorname)
20 {
21     XColor xcol;
22
23     g_assert(colorname != NULL);
24     /* get rgb values from colorname */
25
26     xcol.red = 0;
27     xcol.green = 0;
28     xcol.blue = 0;
29     xcol.pixel = 0;
30     if (!XParseColor(RrDisplay(inst), RrColormap(inst), colorname, &xcol)) {
31         g_warning("unable to parse color '%s'", colorname);
32         return NULL;
33     }
34     return RrColorNew(inst, xcol.red >> 8, xcol.green >> 8, xcol.blue >> 8);
35 }
36
37 RrColor *RrColorNew(const RrInstance *inst, gint r, gint g, gint b)
38 {
39     /* this should be replaced with something far cooler */
40     RrColor *out = NULL;
41     XColor xcol;
42     xcol.red = (r << 8) | r;
43     xcol.green = (g << 8) | g;
44     xcol.blue = (b << 8) | b;
45     if (XAllocColor(RrDisplay(inst), RrColormap(inst), &xcol)) {
46         out = g_new(RrColor, 1);
47         out->inst = inst;
48         out->r = xcol.red >> 8;
49         out->g = xcol.green >> 8;
50         out->b = xcol.blue >> 8;
51         out->gc = None;
52         out->pixel = xcol.pixel;
53     }
54     return out;
55 }
56
57 /*XXX same color could be pointed to twice, this might have to be a refcount*/
58
59 void RrColorFree(RrColor *c)
60 {
61     if (c) {
62         if (c->pixel) XFreeColors(RrDisplay(c->inst), RrColormap(c->inst),
63                                   &c->pixel, 1, 0);
64         if (c->gc) XFreeGC(RrDisplay(c->inst), c->gc);
65         g_free(c);
66     }
67 }
68
69 void RrReduceDepth(const RrInstance *inst, RrPixel32 *data, XImage *im)
70 {
71     int r, g, b;
72     int x,y;
73     RrPixel32 *p32 = (RrPixel32 *) im->data;
74     RrPixel16 *p16 = (RrPixel16 *) im->data;
75     unsigned char *p8 = (unsigned char *)im->data;
76     switch (im->bits_per_pixel) {
77     case 32:
78         if ((RrRedOffset(inst) != RrDefaultRedOffset) ||
79             (RrBlueOffset(inst) != RrDefaultBlueOffset) ||
80             (RrGreenOffset(inst) != RrDefaultGreenOffset)) {
81             for (y = 0; y < im->height; y++) {
82                 for (x = 0; x < im->width; x++) {
83                     r = (data[x] >> RrDefaultRedOffset) & 0xFF;
84                     g = (data[x] >> RrDefaultGreenOffset) & 0xFF;
85                     b = (data[x] >> RrDefaultBlueOffset) & 0xFF;
86                     p32[x] = (r << RrRedOffset(inst))
87                            + (g << RrGreenOffset(inst))
88                            + (b << RrBlueOffset(inst));
89                 }
90                 data += im->width;
91                 p32 += im->width;
92             } 
93         } else im->data = (char*) data;
94         break;
95     case 16:
96         for (y = 0; y < im->height; y++) {
97             for (x = 0; x < im->width; x++) {
98                 r = (data[x] >> RrDefaultRedOffset) & 0xFF;
99                 r = r >> RrRedShift(inst);
100                 g = (data[x] >> RrDefaultGreenOffset) & 0xFF;
101                 g = g >> RrGreenShift(inst);
102                 b = (data[x] >> RrDefaultBlueOffset) & 0xFF;
103                 b = b >> RrBlueShift(inst);
104                 p16[x] = (r << RrRedOffset(inst))
105                        + (g << RrGreenOffset(inst))
106                        + (b << RrBlueOffset(inst));
107             }
108             data += im->width;
109             p16 += im->bytes_per_line/2;
110         }
111     break;
112     case 8:
113         g_assert(RrVisual(inst)->class != TrueColor);
114         for (y = 0; y < im->height; y++) {
115             for (x = 0; x < im->width; x++) {
116                 p8[x] = RrPickColor(inst,
117                                     data[x] >> RrDefaultRedOffset,
118                                     data[x] >> RrDefaultGreenOffset,
119                                     data[x] >> RrDefaultBlueOffset)->pixel;
120         }
121         data += im->width;
122         p8 += im->bytes_per_line;
123   }
124
125     break;
126     default:
127         g_warning("your bit depth is currently unhandled\n");
128     }
129 }
130
131 XColor *RrPickColor(const RrInstance *inst, gint r, gint g, gint b) 
132 {
133   r = (r & 0xff) >> (8-RrPseudoBPC(inst));
134   g = (g & 0xff) >> (8-RrPseudoBPC(inst));
135   b = (b & 0xff) >> (8-RrPseudoBPC(inst));
136   return &RrPseudoColors(inst)[(r << (2*RrPseudoBPC(inst))) +
137                                (g << (1*RrPseudoBPC(inst))) +
138                                b];
139 }
140
141 static void swap_byte_order(XImage *im)
142 {
143     int x, y, di;
144
145     di = 0;
146     for (y = 0; y < im->height; ++y) {
147         for (x = 0; x < im->height; ++x) {
148             char *c = &im->data[di + x * im->bits_per_pixel / 8];
149             char t;
150
151             switch (im->bits_per_pixel) {
152             case 32:
153                 t = c[2];
154                 c[2] = c[3];
155                 c[3] = t;
156             case 16:
157                 t = c[0];
158                 c[0] = c[1];
159                 c[1] = t;
160             case 8:
161                 break;
162             default:
163                 g_warning("your bit depth is currently unhandled");
164             }
165         }
166         di += im->bytes_per_line;
167     }
168
169     if (im->byte_order == LSBFirst)
170         im->byte_order = MSBFirst;
171     else
172         im->byte_order = LSBFirst;
173 }
174
175 void RrIncreaseDepth(const RrInstance *inst, RrPixel32 *data, XImage *im)
176 {
177     int r, g, b;
178     int x,y;
179     RrPixel32 *p32 = (RrPixel32 *) im->data;
180     RrPixel16 *p16 = (RrPixel16 *) im->data;
181     unsigned char *p8 = (unsigned char *)im->data;
182
183     if (im->byte_order != LSBFirst)
184         swap_byte_order(im);
185
186     switch (im->bits_per_pixel) {
187     case 32:
188         for (y = 0; y < im->height; y++) {
189             for (x = 0; x < im->width; x++) {
190                 r = (p32[x] >> RrRedOffset(inst)) & 0xff;
191                 g = (p32[x] >> RrGreenOffset(inst)) & 0xff;
192                 b = (p32[x] >> RrBlueOffset(inst)) & 0xff;
193                 data[x] = (r << RrDefaultRedOffset)
194                     + (g << RrDefaultGreenOffset)
195                     + (b << RrDefaultBlueOffset)
196                     + (0xff << RrDefaultAlphaOffset);
197             }
198             data += im->width;
199             p32 += im->bytes_per_line/4;
200         }
201         break;
202     case 16:
203         for (y = 0; y < im->height; y++) {
204             for (x = 0; x < im->width; x++) {
205                 r = (p16[x] & RrRedMask(inst)) >>
206                     RrRedOffset(inst) <<
207                     RrRedShift(inst);
208                 g = (p16[x] & RrGreenMask(inst)) >>
209                     RrGreenOffset(inst) <<
210                     RrGreenShift(inst);
211                 b = (p16[x] & RrBlueMask(inst)) >>
212                     RrBlueOffset(inst) <<
213                     RrBlueShift(inst);
214                 data[x] = (r << RrDefaultRedOffset)
215                     + (g << RrDefaultGreenOffset)
216                     + (b << RrDefaultBlueOffset)
217                     + (0xff << RrDefaultAlphaOffset);
218             }
219             data += im->width;
220             p16 += im->bytes_per_line/2;
221         }
222         break;
223     case 8:
224         g_warning("this image bit depth is currently unhandled");
225         break;
226     case 1:
227         for (y = 0; y < im->height; y++) {
228             for (x = 0; x < im->width; x++) {
229                 if (!(((p8[x / 8]) >> (x % 8)) & 0x1))
230                     data[x] = 0xff << RrDefaultAlphaOffset; /* black */
231                 else
232                     data[x] = 0xffffffff; /* white */
233             }
234             data += im->width;
235             p8 += im->bytes_per_line;
236         }
237         break;
238     default:
239         g_warning("this image bit depth is currently unhandled");
240     }
241 }
242
243 int RrColorRed(const RrColor *c)
244 {
245     return c->r;
246 }
247
248 int RrColorGreen(const RrColor *c)
249 {
250     return c->g;
251 }
252
253 int RrColorBlue(const RrColor *c)
254 {
255     return c->b;
256 }
257
258 gulong RrColorPixel(const RrColor *c)
259 {
260     return c->pixel;
261 }
262
263 GC RrColorGC(RrColor *c) /* XXX make this const RrColor* when the GCs are in
264                             a cache.. if possible? */
265 {
266     if (!c->gc)
267         RrColorAllocateGC(c);
268     return c->gc;
269 }