]> Dogcows Code - chaz/openbox/blob - render/render.c
remove non-planar surfaces
[chaz/openbox] / render / render.c
1 #include <X11/Xlib.h>
2 #include <X11/Xutil.h>
3
4 #ifdef USE_GL
5 # include <GL/glx.h>
6 #endif
7
8 #include <glib.h>
9 #include "render.h"
10 #include "gradient.h"
11 #include "font.h"
12 #include "mask.h"
13 #include "color.h"
14 #include "image.h"
15 #include "theme.h"
16 #include "kernel/openbox.h"
17
18 #ifdef HAVE_STDLIB_H
19 # include <stdlib.h>
20 #endif
21
22 int render_depth;
23 XVisualInfo render_visual_info;
24
25 Visual *render_visual;
26 Colormap render_colormap;
27
28 int render_red_offset = 0, render_green_offset = 0, render_blue_offset = 0;
29 int render_red_shift, render_green_shift, render_blue_shift;
30 int render_red_mask, render_green_mask, render_blue_mask;
31
32
33 #ifdef USE_GL
34
35 GLXContext render_glx_context;
36
37 int render_glx_rating(XVisualInfo *v)
38 {
39 int er;
40 int rating = 0;
41 int val;
42 printf("evaluating visual %d\n", v->visualid);
43 glXGetConfig(ob_display, v, GLX_BUFFER_SIZE, &val);
44 printf("buffer size %d\n", val);
45
46 switch (val) {
47 case 32:
48 rating += 300;
49 break;
50 case 24:
51 rating += 200;
52 break;
53 case 16:
54 rating += 100;
55 break;
56 }
57
58 glXGetConfig(ob_display, v, GLX_LEVEL, &val);
59 printf("level %d\n", val);
60 if (val != 0)
61 rating = -10000;
62
63 glXGetConfig(ob_display, v, GLX_DEPTH_SIZE, &val);
64 printf("depth size %d\n", val);
65 switch (val) {
66 case 32:
67 rating += 30;
68 break;
69 case 24:
70 rating += 20;
71 break;
72 case 16:
73 rating += 10;
74 break;
75 case 0:
76 rating -= 10000;
77 }
78
79 glXGetConfig(ob_display, v, GLX_DOUBLEBUFFER, &val);
80 printf("double buffer %d\n", val);
81 if (val)
82 rating++;
83 return rating;
84 }
85 #endif /* USE_GL */
86
87 void render_startup(void)
88 {
89 int count, i = 0, val, best = 0, rate = 0, temp;
90 XVisualInfo vimatch, *vilist;
91 paint = x_paint;
92
93 render_depth = DefaultDepth(ob_display, ob_screen);
94 render_visual = DefaultVisual(ob_display, ob_screen);
95 render_colormap = DefaultColormap(ob_display, ob_screen);
96
97 #ifdef USE_GL
98 vimatch.screen = ob_screen;
99 vimatch.class = TrueColor;
100 vilist = XGetVisualInfo(ob_display, VisualScreenMask | VisualClassMask,
101 &vimatch, &count);
102
103 if (vilist) {
104 printf("looking for a GL visualin %d visuals\n", count);
105 for (i = 0; i < count; i++) {
106 glXGetConfig(ob_display, &vilist[i], GLX_USE_GL, &val);
107 if (val) {
108 temp = render_glx_rating(&vilist[i]);
109 if (temp > rate) {
110 best = i;
111 rate = temp;
112 }
113 }
114 }
115 }
116 if (rate > 0) {
117 printf("picked visual %d with rating %d\n", best, rate);
118 render_depth = vilist[best].depth;
119 render_visual = vilist[best].visual;
120 render_colormap = XCreateColormap(ob_display, ob_root,
121 render_visual, AllocNone);
122 render_visual_info = vilist[best];
123 render_glx_context = glXCreateContext(ob_display, &render_visual_info,
124 NULL, True);
125 if (render_glx_context == NULL)
126 printf("sadness\n");
127 else {
128 paint = gl_paint;
129 }
130 }
131 #endif /*USE_GL*/
132
133
134 switch (render_visual->class) {
135 case TrueColor:
136 truecolor_startup();
137 break;
138 case PseudoColor:
139 case StaticColor:
140 case GrayScale:
141 case StaticGray:
142 pseudocolor_startup();
143 break;
144 default:
145 g_critical("unsupported visual class.\n");
146 exit(EXIT_FAILURE);
147
148 }
149 }
150
151 void truecolor_startup(void)
152 {
153 unsigned long red_mask, green_mask, blue_mask;
154 XImage *timage = NULL;
155
156 timage = XCreateImage(ob_display, render_visual, render_depth,
157 ZPixmap, 0, NULL, 1, 1, 32, 0);
158 g_assert(timage != NULL);
159 /* find the offsets for each color in the visual's masks */
160 render_red_mask = red_mask = timage->red_mask;
161 render_green_mask = green_mask = timage->green_mask;
162 render_blue_mask = blue_mask = timage->blue_mask;
163
164 render_red_offset = 0;
165 render_green_offset = 0;
166 render_blue_offset = 0;
167
168 while (! (red_mask & 1)) { render_red_offset++; red_mask >>= 1; }
169 while (! (green_mask & 1)) { render_green_offset++; green_mask >>= 1; }
170 while (! (blue_mask & 1)) { render_blue_offset++; blue_mask >>= 1; }
171
172 render_red_shift = render_green_shift = render_blue_shift = 8;
173 while (red_mask) { red_mask >>= 1; render_red_shift--; }
174 while (green_mask) { green_mask >>= 1; render_green_shift--; }
175 while (blue_mask) { blue_mask >>= 1; render_blue_shift--; }
176 XFree(timage);
177 }
178
179 void pseudocolor_startup(void)
180 {
181 XColor icolors[256];
182 int tr, tg, tb, n, r, g, b, i, incolors, ii;
183 unsigned long dev;
184 int cpc, _ncolors;
185 g_message("Initializing PseudoColor RenderControl\n");
186
187 /* determine the number of colors and the bits-per-color */
188 pseudo_bpc = 2; /* XXX THIS SHOULD BE A USER OPTION */
189 g_assert(pseudo_bpc >= 1);
190 _ncolors = pseudo_ncolors();
191
192 if (_ncolors > 1 << render_depth) {
193 g_warning("PseudoRenderControl: Invalid colormap size. Resizing.\n");
194 pseudo_bpc = 1 << (render_depth/3) >> 3;
195 _ncolors = 1 << (pseudo_bpc * 3);
196 }
197
198 /* build a color cube */
199 pseudo_colors = malloc(_ncolors * sizeof(XColor));
200 cpc = 1 << pseudo_bpc; /* colors per channel */
201
202 for (n = 0, r = 0; r < cpc; r++)
203 for (g = 0; g < cpc; g++)
204 for (b = 0; b < cpc; b++, n++) {
205 tr = (int)(((float)(r)/(float)(cpc-1)) * 0xFF);
206 tg = (int)(((float)(g)/(float)(cpc-1)) * 0xFF);
207 tb = (int)(((float)(b)/(float)(cpc-1)) * 0xFF);
208 pseudo_colors[n].red = tr | tr << 8;
209 pseudo_colors[n].green = tg | tg << 8;
210 pseudo_colors[n].blue = tb | tb << 8;
211 pseudo_colors[n].flags = DoRed|DoGreen|DoBlue; /* used to track
212 allocation */
213 }
214
215 /* allocate the colors */
216 for (i = 0; i < _ncolors; i++)
217 if (!XAllocColor(ob_display, render_colormap, &pseudo_colors[i]))
218 pseudo_colors[i].flags = 0; /* mark it as unallocated */
219
220 /* try allocate any colors that failed allocation above */
221
222 /* get the allocated values from the X server (only the first 256 XXX why!?)
223 */
224 incolors = (((1 << render_depth) > 256) ? 256 : (1 << render_depth));
225 for (i = 0; i < incolors; i++)
226 icolors[i].pixel = i;
227 XQueryColors(ob_display, render_colormap, icolors, incolors);
228
229 /* try match unallocated ones */
230 for (i = 0; i < _ncolors; i++) {
231 if (!pseudo_colors[i].flags) { /* if it wasn't allocated... */
232 unsigned long closest = 0xffffffff, close = 0;
233 for (ii = 0; ii < incolors; ii++) {
234 /* find deviations */
235 r = (pseudo_colors[i].red - icolors[ii].red) & 0xff;
236 g = (pseudo_colors[i].green - icolors[ii].green) & 0xff;
237 b = (pseudo_colors[i].blue - icolors[ii].blue) & 0xff;
238 /* find a weighted absolute deviation */
239 dev = (r * r) + (g * g) + (b * b);
240
241 if (dev < closest) {
242 closest = dev;
243 close = ii;
244 }
245 }
246
247 pseudo_colors[i].red = icolors[close].red;
248 pseudo_colors[i].green = icolors[close].green;
249 pseudo_colors[i].blue = icolors[close].blue;
250 pseudo_colors[i].pixel = icolors[close].pixel;
251
252 /* try alloc this closest color, it had better succeed! */
253 if (XAllocColor(ob_display, render_colormap, &pseudo_colors[i]))
254 pseudo_colors[i].flags = DoRed|DoGreen|DoBlue; /* mark as alloced */
255 else
256 g_assert(FALSE); /* wtf has gone wrong, its already alloced for
257 chissake! */
258 }
259 }
260 }
261
262 void x_paint(Window win, Appearance *l)
263 {
264 int i, transferred = 0, sw;
265 pixel32 *source, *dest;
266 Pixmap oldp;
267 int x = l->area.x;
268 int y = l->area.y;
269 int w = l->area.width;
270 int h = l->area.height;
271 Rect tarea; /* area in which to draw textures */
272
273 if (w <= 0 || h <= 0 || x+w <= 0 || y+h <= 0) return;
274
275 oldp = l->pixmap; /* save to free after changing the visible pixmap */
276 l->pixmap = XCreatePixmap(ob_display, ob_root, x+w, y+h, render_depth);
277 g_assert(l->pixmap != None);
278
279 if (l->xftdraw != NULL)
280 XftDrawDestroy(l->xftdraw);
281 l->xftdraw = XftDrawCreate(ob_display, l->pixmap, render_visual,
282 render_colormap);
283 g_assert(l->xftdraw != NULL);
284
285 g_free(l->surface.pixel_data);
286 l->surface.pixel_data = g_new(pixel32, w * h);
287
288
289 if (l->surface.grad == Background_ParentRelative) {
290 sw = l->surface.parent->area.width;
291 source = l->surface.parent->surface.pixel_data
292 + l->surface.parentx
293 + sw * l->surface.parenty;
294 dest = l->surface.pixel_data;
295 for (i = 0; i < h; i++, source += sw, dest += w) {
296 memcpy(dest, source, w * sizeof(pixel32));
297 }
298 }
299 else if (l->surface.grad == Background_Solid)
300 gradient_solid(l, x, y, w, h);
301 else gradient_render(&l->surface, w, h);
302
303 for (i = 0; i < l->textures; i++) {
304 tarea = l->texture[i].position;
305 if (l->surface.grad != Background_ParentRelative) {
306 if (l->surface.relief != Flat) {
307 switch (l->surface.bevel) {
308 case Bevel1:
309 tarea.x += 1; tarea.y += 1;
310 tarea.width -= 2; tarea.height -= 2;
311 break;
312 case Bevel2:
313 tarea.x += 2; tarea.y += 2;
314 tarea.width -= 4; tarea.height -= 4;
315 break;
316 }
317 } else if (l->surface.border) {
318 tarea.x += 1; tarea.y += 1;
319 tarea.width -= 2; tarea.height -= 2;
320 }
321 }
322
323 switch (l->texture[i].type) {
324 case Text:
325 if (!transferred) {
326 transferred = 1;
327 if (l->surface.grad != Background_Solid)
328 pixel32_to_pixmap(l->surface.pixel_data,
329 l->pixmap,x,y,w,h);
330 }
331 if (l->xftdraw == NULL) {
332 l->xftdraw = XftDrawCreate(ob_display, l->pixmap,
333 render_visual, render_colormap);
334 }
335 font_draw(l->xftdraw, &l->texture[i].data.text,
336 &tarea);
337 break;
338 case Bitmask:
339 if (!transferred) {
340 transferred = 1;
341 if (l->surface.grad != Background_Solid)
342 pixel32_to_pixmap(l->surface.pixel_data,
343 l->pixmap,x,y,w,h);
344 }
345 if (l->texture[i].data.mask.color->gc == None)
346 color_allocate_gc(l->texture[i].data.mask.color);
347 mask_draw(l->pixmap, &l->texture[i].data.mask,
348 &tarea);
349 break;
350 case RGBA:
351 image_draw(l->surface.pixel_data,
352 &l->texture[i].data.rgba,
353 &tarea, &l->area);
354 break;
355 }
356 }
357
358 if (!transferred) {
359 transferred = 1;
360 if (l->surface.grad != Background_Solid)
361 pixel32_to_pixmap(l->surface.pixel_data, l->pixmap
362 ,x,y,w,h);
363 }
364
365
366 XSetWindowBackgroundPixmap(ob_display, win, l->pixmap);
367 XClearWindow(ob_display, win);
368 if (oldp != None) XFreePixmap(ob_display, oldp);
369 }
370
371 void render_shutdown(void)
372 {
373 }
374
375 Appearance *appearance_new(int numtex)
376 {
377 Surface *p;
378 Appearance *out;
379
380 out = g_new(Appearance, 1);
381 out->textures = numtex;
382 out->xftdraw = NULL;
383 if (numtex) out->texture = g_new0(Texture, numtex);
384 else out->texture = NULL;
385 out->pixmap = None;
386
387 p = &out->surface;
388 p->primary = NULL;
389 p->secondary = NULL;
390 p->border_color = NULL;
391 p->bevel_dark = NULL;
392 p->bevel_light = NULL;
393 p->pixel_data = NULL;
394 return out;
395 }
396
397 Appearance *appearance_copy(Appearance *orig)
398 {
399 Surface *spo, *spc;
400 Appearance *copy = g_new(Appearance, 1);
401
402 spo = &(orig->surface);
403 spc = &(copy->surface);
404 spc->grad = spo->grad;
405 spc->relief = spo->relief;
406 spc->bevel = spo->bevel;
407 if (spo->primary != NULL)
408 spc->primary = color_new(spo->primary->r,
409 spo->primary->g,
410 spo->primary->b);
411 else spc->primary = NULL;
412
413 if (spo->secondary != NULL)
414 spc->secondary = color_new(spo->secondary->r,
415 spo->secondary->g,
416 spo->secondary->b);
417 else spc->secondary = NULL;
418
419 if (spo->border_color != NULL)
420 spc->border_color = color_new(spo->border_color->r,
421 spo->border_color->g,
422 spo->border_color->b);
423 else spc->border_color = NULL;
424
425 if (spo->bevel_dark != NULL)
426 spc->bevel_dark = color_new(spo->bevel_dark->r,
427 spo->bevel_dark->g,
428 spo->bevel_dark->b);
429 else spc->bevel_dark = NULL;
430
431 if (spo->bevel_light != NULL)
432 spc->bevel_light = color_new(spo->bevel_light->r,
433 spo->bevel_light->g,
434 spo->bevel_light->b);
435 else spc->bevel_light = NULL;
436
437 spc->interlaced = spo->interlaced;
438 spc->border = spo->border;
439 spc->pixel_data = NULL;
440
441 copy->textures = orig->textures;
442 copy->texture = g_memdup(orig->texture, orig->textures * sizeof(Texture));
443 copy->pixmap = None;
444 copy->xftdraw = NULL;
445 return copy;
446 }
447
448 void appearance_free(Appearance *a)
449 {
450 if (a) {
451 Surface *p;
452 if (a->pixmap != None) XFreePixmap(ob_display, a->pixmap);
453 if (a->xftdraw != NULL) XftDrawDestroy(a->xftdraw);
454 if (a->textures)
455 g_free(a->texture);
456 p = &a->surface;
457 color_free(p->primary);
458 color_free(p->secondary);
459 color_free(p->border_color);
460 color_free(p->bevel_dark);
461 color_free(p->bevel_light);
462 g_free(p->pixel_data);
463
464 g_free(a);
465 }
466 }
467
468
469 void pixel32_to_pixmap(pixel32 *in, Pixmap out, int x, int y, int w, int h)
470 {
471 pixel32 *scratch;
472 XImage *im = NULL;
473 im = XCreateImage(ob_display, render_visual, render_depth,
474 ZPixmap, 0, NULL, w, h, 32, 0);
475 g_assert(im != NULL);
476 im->byte_order = render_endian;
477 /* this malloc is a complete waste of time on normal 32bpp
478 as reduce_depth just sets im->data = data and returns
479 */
480 scratch = g_new(pixel32, im->width * im->height);
481 im->data = (char*) scratch;
482 reduce_depth(in, im);
483 XPutImage(ob_display, out, DefaultGC(ob_display, ob_screen),
484 im, 0, 0, x, y, w, h);
485 im->data = NULL;
486 XDestroyImage(im);
487 g_free(scratch);
488 }
489
490 void appearance_minsize(Appearance *l, int *w, int *h)
491 {
492 int i;
493 int m;
494 *w = *h = 1;
495
496 if (l->surface.relief != Flat) {
497 switch (l->surface.bevel) {
498 case Bevel1:
499 *w = *h = 2;
500 break;
501 case Bevel2:
502 *w = *h = 4;
503 break;
504 }
505 } else if (l->surface.border)
506 *w = *h = 2;
507
508 for (i = 0; i < l->textures; ++i) {
509 switch (l->texture[i].type) {
510 case Bitmask:
511 *w += l->texture[i].data.mask.mask->w;
512 *h += l->texture[i].data.mask.mask->h;
513 break;
514 case Text:
515 m = font_measure_string(l->texture[i].data.text.font,
516 l->texture[i].data.text.string,
517 l->texture[i].data.text.shadow,
518 l->texture[i].data.text.offset);
519 *w += m;
520 m = font_height(l->texture[i].data.text.font,
521 l->texture[i].data.text.shadow,
522 l->texture[i].data.text.offset);
523 *h += m;
524 break;
525 case RGBA:
526 *w += l->texture[i].data.rgba.width;
527 *h += l->texture[i].data.rgba.height;
528 break;
529 case NoTexture:
530 break;
531 }
532 }
533 }
534
535 gboolean render_pixmap_to_rgba(Pixmap pmap, Pixmap mask,
536 int *w, int *h, pixel32 **data)
537 {
538 Window xr;
539 int xx, xy;
540 guint pw, ph, mw, mh, xb, xd, i, x, y, di;
541 XImage *xi, *xm = NULL;
542
543 if (!XGetGeometry(ob_display, pmap, &xr, &xx, &xy, &pw, &ph, &xb, &xd))
544 return FALSE;
545 if (mask) {
546 if (!XGetGeometry(ob_display, mask, &xr, &xx, &xy, &mw, &mh, &xb, &xd))
547 return FALSE;
548 if (pw != mw || ph != mh || xd != 1)
549 return FALSE;
550 }
551
552 xi = XGetImage(ob_display, pmap, 0, 0, pw, ph, 0xffffffff, ZPixmap);
553 if (!xi)
554 return FALSE;
555
556 if (mask) {
557 xm = XGetImage(ob_display, mask, 0, 0, mw, mh, 0xffffffff, ZPixmap);
558 if (!xm)
559 return FALSE;
560 }
561
562 *data = g_new(pixel32, pw * ph);
563 increase_depth(*data, xi);
564
565 if (mask) {
566 /* apply transparency from the mask */
567 di = 0;
568 for (i = 0, y = 0; y < ph; ++y) {
569 for (x = 0; x < pw; ++x, ++i) {
570 if (!((((unsigned)xm->data[di + x / 8]) >> (x % 8)) & 0x1))
571 (*data)[i] &= ~(0xff << default_alpha_offset);
572 }
573 di += xm->bytes_per_line;
574 }
575 }
576
577 *w = pw;
578 *h = ph;
579
580 return TRUE;
581 }
582
583 #ifdef USE_GL
584 void gl_paint(Window win, Appearance *l)
585 {
586 int err;
587 Window root, child;
588 int i, transferred = 0, sw, b, d;
589 pixel32 *source, *dest;
590 Pixmap oldp;
591 int tempx, tempy, absx, absy, absw, absh;
592 int x = l->area.x;
593 int y = l->area.y;
594 int w = l->area.width;
595 int h = l->area.height;
596 Rect tarea; /* area in which to draw textures */
597 if (w <= 0 || h <= 0 || x+w <= 0 || y+h <= 0) return;
598
599 g_assert(l->surface.type == Surface_Planar);
600
601 printf("making %p, %p, %p current\n", ob_display, win, render_glx_context);
602 err = glXMakeCurrent(ob_display, win, render_glx_context);
603 g_assert(err != 0);
604
605 glMatrixMode(GL_MODELVIEW);
606 glLoadIdentity();
607 glMatrixMode(GL_PROJECTION);
608 glLoadIdentity();
609 glOrtho(0, 1376, 1032, 0, 0, 10);
610 if (XGetGeometry(ob_display, win, &root, &tempx, &tempy,
611 &absw, &absh, &b, &d) &&
612 XTranslateCoordinates(ob_display, win, root, tempx, tempy,
613 &absx, &absy, &child))
614 printf("window at %d, %d (%d,%d)\n", absx, absy, absw, absh);
615 else
616 return;
617
618 glViewport(0, 0, 1376, 1032);
619 glMatrixMode(GL_MODELVIEW);
620 glTranslatef(-absx, 1032-absh-absy, 0);
621 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
622
623
624 if (l->surface.grad == Background_ParentRelative) {
625 printf("crap\n");
626 } else
627 render_gl_gradient(&l->surface, absx+x, absy+y, absw, absh);
628
629 glXSwapBuffers(ob_display, win);
630 }
631
632 #endif /* USE_GL */
This page took 0.060636 seconds and 4 git commands to generate.