]> icculus.org git repositories - dana/openbox.git/blob - render/render.c
now it even links.
[dana/openbox.git] / render / render.c
1 #include <X11/Xlib.h>
2 #include <X11/Xutil.h>
3 #include <GL/glx.h>
4 #include <glib.h>
5 #include "render.h"
6 #include "gradient.h"
7 #include "font.h"
8 #include "mask.h"
9 #include "color.h"
10 #include "image.h"
11 #include "theme.h"
12 #include "kernel/openbox.h"
13
14 #ifdef HAVE_STDLIB_H
15 #  include <stdlib.h>
16 #endif
17
18 int render_depth;
19 XVisualInfo render_visual_info;
20
21 Visual *render_visual;
22 Colormap render_colormap;
23
24 int render_red_offset = 0, render_green_offset = 0, render_blue_offset = 0;
25 int render_red_shift, render_green_shift, render_blue_shift;
26 int render_red_mask, render_green_mask, render_blue_mask;
27
28
29 GLXContext render_glx_context;
30
31 int render_glx_rating(XVisualInfo *v)
32 {
33     int er;
34     int rating = 0;
35     int val;
36     printf("evaluating visual %d\n", v->visualid);
37     glXGetConfig(ob_display, v, GLX_BUFFER_SIZE, &val);
38     printf("buffer size %d\n", val);
39
40     switch (val) {
41     case 32:
42         rating += 300;
43     break;
44     case 24:
45         rating += 200;
46     break;
47     case 16:
48         rating += 100;
49     break;
50     }
51
52     glXGetConfig(ob_display, v, GLX_LEVEL, &val);
53     printf("level %d\n", val);
54     if (val != 0)
55         rating = -10000;
56
57     glXGetConfig(ob_display, v, GLX_DEPTH_SIZE, &val);
58     printf("depth size %d\n", val);
59     switch (val) {
60     case 32:
61         rating += 30;
62     break;
63     case 24:
64         rating += 20;
65     break;
66     case 16:
67         rating += 10;
68     break;
69     case 0:
70         rating -= 10000;
71     }
72
73     glXGetConfig(ob_display, v, GLX_DOUBLEBUFFER, &val);
74     printf("double buffer %d\n", val);
75     if (val)
76         rating++;
77     return rating;
78 }
79
80 void render_startup(void)
81 {
82     int count, i = 0, val, best = 0, rate = 0, temp;
83     XVisualInfo vimatch, *vilist;
84
85     render_depth = DefaultDepth(ob_display, ob_screen);
86     render_visual = DefaultVisual(ob_display, ob_screen);
87     render_colormap = DefaultColormap(ob_display, ob_screen);
88
89     vimatch.screen = ob_screen;
90     vimatch.class = TrueColor;
91     vilist = XGetVisualInfo(ob_display, VisualScreenMask | VisualClassMask,
92                             &vimatch, &count);
93
94     if (vilist) {
95         printf("looking for a GL visualin %d visuals\n", count);
96         for (i = 0; i < count; i++) {
97             glXGetConfig(ob_display, &vilist[i], GLX_USE_GL, &val);
98             if (val) {
99                 temp = render_glx_rating(&vilist[i]);
100                 if (temp > rate) {
101                     best = i;
102                     rate = temp;
103                 }
104             }
105         }
106     }
107     if (rate > 0) {
108         printf("picked visual %d with rating %d\n", best, rate);
109         render_depth = vilist[best].depth;
110         render_visual = vilist[best].visual;
111         render_colormap = XCreateColormap(ob_display, ob_root, 
112                                           render_visual, AllocNone);
113         render_visual_info = vilist[best];
114         render_glx_context = glXCreateContext(ob_display, &render_visual_info,
115                                               NULL, True);
116         if (render_glx_context == NULL)
117             printf("sadness\n");
118         else {
119             paint = gl_paint;
120         }
121     }
122
123
124   switch (render_visual->class) {
125   case TrueColor:
126     truecolor_startup();
127     break;
128   default:
129     g_critical("unsupported visual class.\n");
130     exit(EXIT_FAILURE);
131
132   }
133 }
134
135 void truecolor_startup(void)
136 {
137   unsigned long red_mask, green_mask, blue_mask;
138   XImage *timage = NULL;
139
140   timage = XCreateImage(ob_display, render_visual, render_depth,
141                         ZPixmap, 0, NULL, 1, 1, 32, 0);
142   g_assert(timage != NULL);
143   /* find the offsets for each color in the visual's masks */
144   render_red_mask = red_mask = timage->red_mask;
145   render_green_mask = green_mask = timage->green_mask;
146   render_blue_mask = blue_mask = timage->blue_mask;
147
148   render_red_offset = 0;
149   render_green_offset = 0;
150   render_blue_offset = 0;
151
152   while (! (red_mask & 1))   { render_red_offset++;   red_mask   >>= 1; }
153   while (! (green_mask & 1)) { render_green_offset++; green_mask >>= 1; }
154   while (! (blue_mask & 1))  { render_blue_offset++;  blue_mask  >>= 1; }
155
156   render_red_shift = render_green_shift = render_blue_shift = 8;
157   while (red_mask)   { red_mask   >>= 1; render_red_shift--;   }
158   while (green_mask) { green_mask >>= 1; render_green_shift--; }
159   while (blue_mask)  { blue_mask  >>= 1; render_blue_shift--;  }
160   XFree(timage);
161 }
162
163 void render_shutdown(void)
164 {
165 }
166
167 Appearance *appearance_new(SurfaceType type, int numtex)
168 {
169   PlanarSurface *p;
170   Appearance *out;
171
172   out = g_new(Appearance, 1);
173   out->surface.type = type;
174   out->textures = numtex;
175   if (numtex) out->texture = g_new0(Texture, numtex);
176   else out->texture = NULL;
177
178   switch (type) {
179   case Surface_Planar:
180     p = &out->surface.data.planar;
181     p->primary = NULL;
182     p->secondary = NULL;
183     p->border_color = NULL;
184     p->bevel_dark = NULL;
185     p->bevel_light = NULL;
186     p->pixel_data = NULL;
187     break;
188   }
189   return out;
190 }
191
192 Appearance *appearance_copy(Appearance *orig)
193 {
194     PlanarSurface *spo, *spc;
195     Appearance *copy = g_new(Appearance, 1);
196     copy->surface.type = orig->surface.type;
197     switch (orig->surface.type) {
198     case Surface_Planar:
199         spo = &(orig->surface.data.planar);
200         spc = &(copy->surface.data.planar);
201         spc->grad = spo->grad;
202         spc->relief = spo->relief;
203         spc->bevel = spo->bevel;
204         if (spo->primary != NULL)
205             spc->primary = color_new(spo->primary->r,
206                                      spo->primary->g, 
207                                      spo->primary->b);
208         else spc->primary = NULL;
209
210         if (spo->secondary != NULL)
211             spc->secondary = color_new(spo->secondary->r,
212                                        spo->secondary->g,
213                                        spo->secondary->b);
214         else spc->secondary = NULL;
215
216         if (spo->border_color != NULL)
217             spc->border_color = color_new(spo->border_color->r,
218                                           spo->border_color->g,
219                                           spo->border_color->b);
220         else spc->border_color = NULL;
221
222         if (spo->bevel_dark != NULL)
223             spc->bevel_dark = color_new(spo->bevel_dark->r,
224                                         spo->bevel_dark->g,
225                                         spo->bevel_dark->b);
226         else spc->bevel_dark = NULL;
227
228         if (spo->bevel_light != NULL)
229             spc->bevel_light = color_new(spo->bevel_light->r,
230                                          spo->bevel_light->g,
231                                          spo->bevel_light->b);
232         else spc->bevel_light = NULL;
233
234         spc->interlaced = spo->interlaced;
235         spc->border = spo->border;
236         spc->pixel_data = NULL;
237     break;
238     }
239     copy->textures = orig->textures;
240     copy->texture = g_memdup(orig->texture, orig->textures * sizeof(Texture));
241     return copy;
242 }
243
244 void appearance_free(Appearance *a)
245 {
246     if (a) {
247         PlanarSurface *p;
248         if (a->textures)
249             g_free(a->texture);
250         if (a->surface.type == Surface_Planar) {
251             p = &a->surface.data.planar;
252             color_free(p->primary);
253             color_free(p->secondary);
254             color_free(p->border_color);
255             color_free(p->bevel_dark);
256             color_free(p->bevel_light);
257             g_free(p->pixel_data);
258         }
259         g_free(a);
260     }
261 }
262
263
264 void pixel32_to_pixmap(pixel32 *in, Pixmap out, int x, int y, int w, int h)
265 {
266     pixel32 *scratch;
267     XImage *im = NULL;
268     im = XCreateImage(ob_display, render_visual, render_depth,
269                       ZPixmap, 0, NULL, w, h, 32, 0);
270     g_assert(im != NULL);
271     im->byte_order = render_endian;
272 /* this malloc is a complete waste of time on normal 32bpp
273    as reduce_depth just sets im->data = data and returns
274 */
275     scratch = g_new(pixel32, im->width * im->height);
276     im->data = (char*) scratch;
277     reduce_depth(in, im);
278     XPutImage(ob_display, out, DefaultGC(ob_display, ob_screen),
279               im, 0, 0, x, y, w, h);
280     im->data = NULL;
281     XDestroyImage(im);
282     g_free(scratch);
283 }
284
285 void appearance_minsize(Appearance *l, int *w, int *h)
286 {
287     int i;
288     int m;
289     *w = *h = 1;
290
291     switch (l->surface.type) {
292     case Surface_Planar:
293         if (l->surface.data.planar.relief != Flat) {
294             switch (l->surface.data.planar.bevel) {
295             case Bevel1:
296                 *w = *h = 2;
297                 break;
298             case Bevel2:
299                 *w = *h = 4;
300                 break;
301             }
302         } else if (l->surface.data.planar.border)
303             *w = *h = 2;
304
305         for (i = 0; i < l->textures; ++i) {
306             switch (l->texture[i].type) {
307             case Bitmask:
308                 *w += l->texture[i].data.mask.mask->w;
309                 *h += l->texture[i].data.mask.mask->h;
310                 break;
311             case Text:
312                 m = font_measure_string(l->texture[i].data.text.font,
313                                         l->texture[i].data.text.string,
314                                         l->texture[i].data.text.shadow,
315                                         l->texture[i].data.text.offset);
316                 *w += m;
317                 m = font_height(l->texture[i].data.text.font,
318                                 l->texture[i].data.text.shadow,
319                                 l->texture[i].data.text.offset);
320                 *h += m;
321                 break;
322             case RGBA:
323                 *w += l->texture[i].data.rgba.width;
324                 *h += l->texture[i].data.rgba.height;
325                 break;
326             case NoTexture:
327                 break;
328             }
329         }
330         break;
331     }
332 }
333
334 gboolean render_pixmap_to_rgba(Pixmap pmap, Pixmap mask,
335                                int *w, int *h, pixel32 **data)
336 {
337     Window xr;
338     int xx, xy;
339     guint pw, ph, mw, mh, xb, xd, i, x, y, di;
340     XImage *xi, *xm = NULL;
341
342     if (!XGetGeometry(ob_display, pmap, &xr, &xx, &xy, &pw, &ph, &xb, &xd))
343         return FALSE;
344     if (mask) {
345         if (!XGetGeometry(ob_display, mask, &xr, &xx, &xy, &mw, &mh, &xb, &xd))
346             return FALSE;
347         if (pw != mw || ph != mh || xd != 1)
348             return FALSE;
349     }
350
351     xi = XGetImage(ob_display, pmap, 0, 0, pw, ph, 0xffffffff, ZPixmap);
352     if (!xi)
353         return FALSE;
354
355     if (mask) {
356         xm = XGetImage(ob_display, mask, 0, 0, mw, mh, 0xffffffff, ZPixmap);
357         if (!xm)
358             return FALSE;
359     }
360
361     *data = g_new(pixel32, pw * ph);
362     increase_depth(*data, xi);
363
364     if (mask) {
365         /* apply transparency from the mask */
366         di = 0;
367         for (i = 0, y = 0; y < ph; ++y) {
368             for (x = 0; x < pw; ++x, ++i) {
369                 if (!((((unsigned)xm->data[di + x / 8]) >> (x % 8)) & 0x1))
370                     (*data)[i] &= ~(0xff << default_alpha_offset);
371             }
372             di += xm->bytes_per_line;
373         }
374     }
375
376     *w = pw;
377     *h = ph;
378
379     return TRUE;
380 }
381
382 void gl_paint(Window win, Appearance *l)
383 {
384     int err;
385     Window root, child;
386     int i, transferred = 0, sw, b, d;
387     pixel32 *source, *dest;
388     Pixmap oldp;
389     int tempx, tempy, absx, absy, absw, absh;
390     int x = l->area.x;
391     int y = l->area.y;
392     int w = l->area.width;
393     int h = l->area.height;
394     Rect tarea; /* area in which to draw textures */
395     if (w <= 0 || h <= 0 || x+w <= 0 || y+h <= 0) return;
396
397     g_assert(l->surface.type == Surface_Planar);
398
399 printf("making %p, %p, %p current\n", ob_display, win, render_glx_context);
400     err = glXMakeCurrent(ob_display, win, render_glx_context);
401 g_assert(err != 0);
402
403             glMatrixMode(GL_MODELVIEW);
404             glLoadIdentity();
405             glMatrixMode(GL_PROJECTION);
406             glLoadIdentity();
407             glOrtho(0, 1376, 1032, 0, 0, 10);
408     if (XGetGeometry(ob_display, win, &root, &tempx, &tempy,
409                      &absw, &absh,  &b, &d) &&
410         XTranslateCoordinates(ob_display, win, root, tempx, tempy, 
411         &absx, &absy, &child))
412         printf("window at %d, %d (%d,%d)\n", absx, absy, absw, absh);
413     else
414         return;
415
416     glViewport(0, 0, 1376, 1032);
417     glMatrixMode(GL_MODELVIEW);
418     glTranslatef(-absx, 1032-absh-absy, 0);
419     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
420
421
422     if (l->surface.data.planar.grad == Background_ParentRelative) {
423         printf("crap\n");
424     } else
425         render_gl_gradient(&l->surface, absx+x, absy+y, absw, absh);
426
427     glXSwapBuffers(ob_display, win);
428 }