move some internal functions from render.h to instance.h
[dana/openbox.git] / render / instance.c
1 #include "render.h"
2 #include "instance.h"
3
4 static RrInstance *definst = NULL;
5
6 static void RrTrueColorSetup (RrInstance *inst);
7 static void RrPseudoColorSetup (RrInstance *inst);
8
9 RrInstance* RrInstanceNew (Display *display, gint screen)
10 {
11     definst = g_new (RrInstance, 1);
12     definst->display = display;
13     definst->screen = screen;
14
15     definst->depth = DefaultDepth(display, screen);
16     definst->visual = DefaultVisual(display, screen);
17     definst->colormap = DefaultColormap(display, screen);
18
19     definst->pseudo_colors = NULL;
20
21     definst->color_hash = g_hash_table_new(g_int_hash, g_int_equal);
22
23     switch (definst->visual->class) {
24     case TrueColor:
25         RrTrueColorSetup(definst);
26         break;
27     case PseudoColor:
28     case StaticColor:
29     case GrayScale:
30     case StaticGray:
31         RrPseudoColorSetup(definst);
32         break;
33     default:
34         g_critical("Unsupported visual class");
35         g_free (definst);
36         return definst = NULL;
37     }
38     return definst;
39 }
40
41 void RrTrueColorSetup (RrInstance *inst)
42 {
43   unsigned long red_mask, green_mask, blue_mask;
44   XImage *timage = NULL;
45
46   timage = XCreateImage(inst->display, inst->visual, inst->depth,
47                         ZPixmap, 0, NULL, 1, 1, 32, 0);
48   g_assert(timage != NULL);
49   /* find the offsets for each color in the visual's masks */
50   inst->red_mask = red_mask = timage->red_mask;
51   inst->green_mask = green_mask = timage->green_mask;
52   inst->blue_mask = blue_mask = timage->blue_mask;
53
54   inst->red_offset = 0;
55   inst->green_offset = 0;
56   inst->blue_offset = 0;
57
58   while (! (red_mask & 1))   { inst->red_offset++;   red_mask   >>= 1; }
59   while (! (green_mask & 1)) { inst->green_offset++; green_mask >>= 1; }
60   while (! (blue_mask & 1))  { inst->blue_offset++;  blue_mask  >>= 1; }
61
62   inst->red_shift = inst->green_shift = inst->blue_shift = 8;
63   while (red_mask)   { red_mask   >>= 1; inst->red_shift--;   }
64   while (green_mask) { green_mask >>= 1; inst->green_shift--; }
65   while (blue_mask)  { blue_mask  >>= 1; inst->blue_shift--;  }
66   XFree(timage);
67 }
68
69 #define RrPseudoNcolors(isnt) (1 << (inst->pseudo_bpc * 3))
70
71 void RrPseudoColorSetup (RrInstance *inst)
72 {
73     XColor icolors[256];
74     int tr, tg, tb, n, r, g, b, i, incolors, ii;
75     unsigned long dev;
76     int cpc, _ncolors;
77
78     /* determine the number of colors and the bits-per-color */
79     inst->pseudo_bpc = 2; /* XXX THIS SHOULD BE A USER OPTION */
80     g_assert(inst->pseudo_bpc >= 1);
81     _ncolors = RrPseudoNcolors(inst);
82
83     if (_ncolors > 1 << inst->depth) {
84         g_warning("PseudoRenderControl: Invalid colormap size. Resizing.\n");
85         inst->pseudo_bpc = 1 << (inst->depth/3) >> 3;
86         _ncolors = 1 << (inst->pseudo_bpc * 3);
87     }
88
89     /* build a color cube */
90     inst->pseudo_colors = g_new(XColor, _ncolors);
91     cpc = 1 << inst->pseudo_bpc; /* colors per channel */
92
93     for (n = 0, r = 0; r < cpc; r++)
94         for (g = 0; g < cpc; g++)
95             for (b = 0; b < cpc; b++, n++) {
96                 tr = (int)(((float)(r)/(float)(cpc-1)) * 0xFF);
97                 tg = (int)(((float)(g)/(float)(cpc-1)) * 0xFF);
98                 tb = (int)(((float)(b)/(float)(cpc-1)) * 0xFF);
99                 inst->pseudo_colors[n].red = tr | tr << 8;
100                 inst->pseudo_colors[n].green = tg | tg << 8;
101                 inst->pseudo_colors[n].blue = tb | tb << 8;
102                 /* used to track allocation */
103                 inst->pseudo_colors[n].flags = DoRed|DoGreen|DoBlue;
104             }
105
106     /* allocate the colors */
107     for (i = 0; i < _ncolors; i++)
108         if (!XAllocColor(inst->display, inst->colormap,
109                          &inst->pseudo_colors[i]))
110             inst->pseudo_colors[i].flags = 0; /* mark it as unallocated */
111
112     /* try allocate any colors that failed allocation above */
113
114     /* get the allocated values from the X server
115        (only the first 256 XXX why!?)
116      */
117     incolors = (((1 << inst->depth) > 256) ? 256 : (1 << inst->depth));
118     for (i = 0; i < incolors; i++)
119         icolors[i].pixel = i;
120     XQueryColors(inst->display, inst->colormap, icolors, incolors);
121
122     /* try match unallocated ones */
123     for (i = 0; i < _ncolors; i++) {
124         if (!inst->pseudo_colors[i].flags) { /* if it wasn't allocated... */
125             unsigned long closest = 0xffffffff, close = 0;
126             for (ii = 0; ii < incolors; ii++) {
127                 /* find deviations */
128                 r = (inst->pseudo_colors[i].red - icolors[ii].red) & 0xff;
129                 g = (inst->pseudo_colors[i].green - icolors[ii].green) & 0xff;
130                 b = (inst->pseudo_colors[i].blue - icolors[ii].blue) & 0xff;
131                 /* find a weighted absolute deviation */
132                 dev = (r * r) + (g * g) + (b * b);
133
134                 if (dev < closest) {
135                     closest = dev;
136                     close = ii;
137                 }
138             }
139
140             inst->pseudo_colors[i].red = icolors[close].red;
141             inst->pseudo_colors[i].green = icolors[close].green;
142             inst->pseudo_colors[i].blue = icolors[close].blue;
143             inst->pseudo_colors[i].pixel = icolors[close].pixel;
144
145             /* try alloc this closest color, it had better succeed! */
146             if (XAllocColor(inst->display, inst->colormap,
147                             &inst->pseudo_colors[i]))
148                 /* mark as alloced */
149                 inst->pseudo_colors[i].flags = DoRed|DoGreen|DoBlue;
150             else
151                 /* wtf has gone wrong, its already alloced for chissake! */
152                 g_assert_not_reached();
153         }
154     }
155 }
156
157 void RrInstanceFree (RrInstance *inst)
158 {
159     if (inst) {
160         if (inst == definst) definst = NULL;
161         g_free(inst->pseudo_colors);
162         g_hash_table_destroy(inst->color_hash);
163     }
164 }
165
166 Display* RrDisplay (const RrInstance *inst)
167 {
168     return (inst ? inst : definst)->display;
169 }
170
171 gint RrScreen (const RrInstance *inst)
172 {
173     return (inst ? inst : definst)->screen;
174 }
175
176 Window RrRootWindow (const RrInstance *inst)
177 {
178     return RootWindow (RrDisplay (inst), RrScreen (inst));
179 }
180
181 Visual *RrVisual (const RrInstance *inst)
182 {
183     return (inst ? inst : definst)->visual;
184 }
185
186 gint RrDepth (const RrInstance *inst)
187 {
188     return (inst ? inst : definst)->depth;
189 }
190
191 Colormap RrColormap (const RrInstance *inst)
192 {
193     return (inst ? inst : definst)->colormap;
194 }
195
196 gint RrRedOffset (const RrInstance *inst)
197 {
198     return (inst ? inst : definst)->red_offset;
199 }
200
201 gint RrGreenOffset (const RrInstance *inst)
202 {
203     return (inst ? inst : definst)->green_offset;
204 }
205
206 gint RrBlueOffset (const RrInstance *inst)
207 {
208     return (inst ? inst : definst)->blue_offset;
209 }
210
211 gint RrRedShift (const RrInstance *inst)
212 {
213     return (inst ? inst : definst)->red_shift;
214 }
215
216 gint RrGreenShift (const RrInstance *inst)
217 {
218     return (inst ? inst : definst)->green_shift;
219 }
220
221 gint RrBlueShift (const RrInstance *inst)
222 {
223     return (inst ? inst : definst)->blue_shift;
224 }
225
226 gint RrRedMask (const RrInstance *inst)
227 {
228     return (inst ? inst : definst)->red_mask;
229 }
230
231 gint RrGreenMask (const RrInstance *inst)
232 {
233     return (inst ? inst : definst)->green_mask;
234 }
235
236 gint RrBlueMask (const RrInstance *inst)
237 {
238     return (inst ? inst : definst)->blue_mask;
239 }
240
241 guint RrPseudoBPC (const RrInstance *inst)
242 {
243     return (inst ? inst : definst)->pseudo_bpc;
244 }
245
246 XColor *RrPseudoColors (const RrInstance *inst)
247 {
248     return (inst ? inst : definst)->pseudo_colors;
249 }
250
251 GHashTable* RrColorHash (const RrInstance *inst)
252 {
253     return (inst ? inst : definst)->color_hash;
254 }