]> Dogcows Code - chaz/openbox/blob - render/render.c
more unique error for unhandles image bit depths, remove debug prints
[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 g_assert(l->surface.type == Surface_Planar);
276
277 oldp = l->pixmap; /* save to free after changing the visible pixmap */
278 l->pixmap = XCreatePixmap(ob_display, ob_root, x+w, y+h, render_depth);
279 g_assert(l->pixmap != None);
280
281 if (l->xftdraw != NULL)
282 XftDrawDestroy(l->xftdraw);
283 l->xftdraw = XftDrawCreate(ob_display, l->pixmap, render_visual,
284 render_colormap);
285 g_assert(l->xftdraw != NULL);
286
287 g_free(l->surface.data.planar.pixel_data);
288 l->surface.data.planar.pixel_data = g_new(pixel32, w * h);
289
290
291 if (l->surface.data.planar.grad == Background_ParentRelative) {
292 sw = l->surface.data.planar.parent->area.width;
293 source = l->surface.data.planar.parent->surface.data.planar.pixel_data
294 + l->surface.data.planar.parentx
295 + sw * l->surface.data.planar.parenty;
296 dest = l->surface.data.planar.pixel_data;
297 for (i = 0; i < h; i++, source += sw, dest += w) {
298 memcpy(dest, source, w * sizeof(pixel32));
299 }
300 }
301 else if (l->surface.data.planar.grad == Background_Solid)
302 gradient_solid(l, x, y, w, h);
303 else gradient_render(&l->surface, w, h);
304
305 for (i = 0; i < l->textures; i++) {
306 tarea = l->texture[i].position;
307 if (l->surface.data.planar.grad != Background_ParentRelative) {
308 if (l->surface.data.planar.relief != Flat) {
309 switch (l->surface.data.planar.bevel) {
310 case Bevel1:
311 tarea.x += 1; tarea.y += 1;
312 tarea.width -= 2; tarea.height -= 2;
313 break;
314 case Bevel2:
315 tarea.x += 2; tarea.y += 2;
316 tarea.width -= 4; tarea.height -= 4;
317 break;
318 }
319 } else if (l->surface.data.planar.border) {
320 tarea.x += 1; tarea.y += 1;
321 tarea.width -= 2; tarea.height -= 2;
322 }
323 }
324
325 switch (l->texture[i].type) {
326 case Text:
327 if (!transferred) {
328 transferred = 1;
329 if (l->surface.data.planar.grad != Background_Solid)
330 pixel32_to_pixmap(l->surface.data.planar.pixel_data,
331 l->pixmap,x,y,w,h);
332 }
333 if (l->xftdraw == NULL) {
334 l->xftdraw = XftDrawCreate(ob_display, l->pixmap,
335 render_visual, render_colormap);
336 }
337 font_draw(l->xftdraw, &l->texture[i].data.text,
338 &tarea);
339 break;
340 case Bitmask:
341 if (!transferred) {
342 transferred = 1;
343 if (l->surface.data.planar.grad != Background_Solid)
344 pixel32_to_pixmap(l->surface.data.planar.pixel_data,
345 l->pixmap,x,y,w,h);
346 }
347 if (l->texture[i].data.mask.color->gc == None)
348 color_allocate_gc(l->texture[i].data.mask.color);
349 mask_draw(l->pixmap, &l->texture[i].data.mask,
350 &tarea);
351 break;
352 case RGBA:
353 image_draw(l->surface.data.planar.pixel_data,
354 &l->texture[i].data.rgba,
355 &tarea, &l->area);
356 break;
357 }
358 }
359
360 if (!transferred) {
361 transferred = 1;
362 if (l->surface.data.planar.grad != Background_Solid)
363 pixel32_to_pixmap(l->surface.data.planar.pixel_data, l->pixmap
364 ,x,y,w,h);
365 }
366
367
368 XSetWindowBackgroundPixmap(ob_display, win, l->pixmap);
369 XClearWindow(ob_display, win);
370 if (oldp != None) XFreePixmap(ob_display, oldp);
371 }
372
373 void render_shutdown(void)
374 {
375 }
376
377 Appearance *appearance_new(SurfaceType type, int numtex)
378 {
379 PlanarSurface *p;
380 Appearance *out;
381
382 out = g_new(Appearance, 1);
383 out->surface.type = type;
384 out->textures = numtex;
385 out->xftdraw = NULL;
386 if (numtex) out->texture = g_new0(Texture, numtex);
387 else out->texture = NULL;
388 out->pixmap = None;
389
390 switch (type) {
391 case Surface_Planar:
392 p = &out->surface.data.planar;
393 p->primary = NULL;
394 p->secondary = NULL;
395 p->border_color = NULL;
396 p->bevel_dark = NULL;
397 p->bevel_light = NULL;
398 p->pixel_data = NULL;
399 break;
400 }
401 return out;
402 }
403
404 Appearance *appearance_copy(Appearance *orig)
405 {
406 PlanarSurface *spo, *spc;
407 Appearance *copy = g_new(Appearance, 1);
408 copy->surface.type = orig->surface.type;
409 switch (orig->surface.type) {
410 case Surface_Planar:
411 spo = &(orig->surface.data.planar);
412 spc = &(copy->surface.data.planar);
413 spc->grad = spo->grad;
414 spc->relief = spo->relief;
415 spc->bevel = spo->bevel;
416 if (spo->primary != NULL)
417 spc->primary = color_new(spo->primary->r,
418 spo->primary->g,
419 spo->primary->b);
420 else spc->primary = NULL;
421
422 if (spo->secondary != NULL)
423 spc->secondary = color_new(spo->secondary->r,
424 spo->secondary->g,
425 spo->secondary->b);
426 else spc->secondary = NULL;
427
428 if (spo->border_color != NULL)
429 spc->border_color = color_new(spo->border_color->r,
430 spo->border_color->g,
431 spo->border_color->b);
432 else spc->border_color = NULL;
433
434 if (spo->bevel_dark != NULL)
435 spc->bevel_dark = color_new(spo->bevel_dark->r,
436 spo->bevel_dark->g,
437 spo->bevel_dark->b);
438 else spc->bevel_dark = NULL;
439
440 if (spo->bevel_light != NULL)
441 spc->bevel_light = color_new(spo->bevel_light->r,
442 spo->bevel_light->g,
443 spo->bevel_light->b);
444 else spc->bevel_light = NULL;
445
446 spc->interlaced = spo->interlaced;
447 spc->border = spo->border;
448 spc->pixel_data = NULL;
449 break;
450 }
451 copy->textures = orig->textures;
452 copy->texture = g_memdup(orig->texture, orig->textures * sizeof(Texture));
453 copy->pixmap = None;
454 copy->xftdraw = NULL;
455 return copy;
456 }
457
458 void appearance_free(Appearance *a)
459 {
460 if (a) {
461 PlanarSurface *p;
462 if (a->pixmap != None) XFreePixmap(ob_display, a->pixmap);
463 if (a->xftdraw != NULL) XftDrawDestroy(a->xftdraw);
464 if (a->textures)
465 g_free(a->texture);
466 if (a->surface.type == Surface_Planar) {
467 p = &a->surface.data.planar;
468 color_free(p->primary);
469 color_free(p->secondary);
470 color_free(p->border_color);
471 color_free(p->bevel_dark);
472 color_free(p->bevel_light);
473 g_free(p->pixel_data);
474 }
475 g_free(a);
476 }
477 }
478
479
480 void pixel32_to_pixmap(pixel32 *in, Pixmap out, int x, int y, int w, int h)
481 {
482 pixel32 *scratch;
483 XImage *im = NULL;
484 im = XCreateImage(ob_display, render_visual, render_depth,
485 ZPixmap, 0, NULL, w, h, 32, 0);
486 g_assert(im != NULL);
487 im->byte_order = render_endian;
488 /* this malloc is a complete waste of time on normal 32bpp
489 as reduce_depth just sets im->data = data and returns
490 */
491 scratch = g_new(pixel32, im->width * im->height);
492 im->data = (char*) scratch;
493 reduce_depth(in, im);
494 XPutImage(ob_display, out, DefaultGC(ob_display, ob_screen),
495 im, 0, 0, x, y, w, h);
496 im->data = NULL;
497 XDestroyImage(im);
498 g_free(scratch);
499 }
500
501 void appearance_minsize(Appearance *l, int *w, int *h)
502 {
503 int i;
504 int m;
505 *w = *h = 1;
506
507 switch (l->surface.type) {
508 case Surface_Planar:
509 if (l->surface.data.planar.relief != Flat) {
510 switch (l->surface.data.planar.bevel) {
511 case Bevel1:
512 *w = *h = 2;
513 break;
514 case Bevel2:
515 *w = *h = 4;
516 break;
517 }
518 } else if (l->surface.data.planar.border)
519 *w = *h = 2;
520
521 for (i = 0; i < l->textures; ++i) {
522 switch (l->texture[i].type) {
523 case Bitmask:
524 *w += l->texture[i].data.mask.mask->w;
525 *h += l->texture[i].data.mask.mask->h;
526 break;
527 case Text:
528 m = font_measure_string(l->texture[i].data.text.font,
529 l->texture[i].data.text.string,
530 l->texture[i].data.text.shadow,
531 l->texture[i].data.text.offset);
532 *w += m;
533 m = font_height(l->texture[i].data.text.font,
534 l->texture[i].data.text.shadow,
535 l->texture[i].data.text.offset);
536 *h += m;
537 break;
538 case RGBA:
539 *w += l->texture[i].data.rgba.width;
540 *h += l->texture[i].data.rgba.height;
541 break;
542 case NoTexture:
543 break;
544 }
545 }
546 break;
547 }
548 }
549
550 gboolean render_pixmap_to_rgba(Pixmap pmap, Pixmap mask,
551 int *w, int *h, pixel32 **data)
552 {
553 Window xr;
554 int xx, xy;
555 guint pw, ph, mw, mh, xb, xd, i, x, y, di;
556 XImage *xi, *xm = NULL;
557
558 if (!XGetGeometry(ob_display, pmap, &xr, &xx, &xy, &pw, &ph, &xb, &xd))
559 return FALSE;
560 if (mask) {
561 if (!XGetGeometry(ob_display, mask, &xr, &xx, &xy, &mw, &mh, &xb, &xd))
562 return FALSE;
563 if (pw != mw || ph != mh || xd != 1)
564 return FALSE;
565 }
566
567 xi = XGetImage(ob_display, pmap, 0, 0, pw, ph, 0xffffffff, ZPixmap);
568 if (!xi)
569 return FALSE;
570
571 if (mask) {
572 xm = XGetImage(ob_display, mask, 0, 0, mw, mh, 0xffffffff, ZPixmap);
573 if (!xm)
574 return FALSE;
575 }
576
577 *data = g_new(pixel32, pw * ph);
578 increase_depth(*data, xi);
579
580 if (mask) {
581 /* apply transparency from the mask */
582 di = 0;
583 for (i = 0, y = 0; y < ph; ++y) {
584 for (x = 0; x < pw; ++x, ++i) {
585 if (!((((unsigned)xm->data[di + x / 8]) >> (x % 8)) & 0x1))
586 (*data)[i] &= ~(0xff << default_alpha_offset);
587 }
588 di += xm->bytes_per_line;
589 }
590 }
591
592 *w = pw;
593 *h = ph;
594
595 return TRUE;
596 }
597
598 #ifdef USE_GL
599 void gl_paint(Window win, Appearance *l)
600 {
601 int err;
602 Window root, child;
603 int i, transferred = 0, sw, b, d;
604 pixel32 *source, *dest;
605 Pixmap oldp;
606 int tempx, tempy, absx, absy, absw, absh;
607 int x = l->area.x;
608 int y = l->area.y;
609 int w = l->area.width;
610 int h = l->area.height;
611 Rect tarea; /* area in which to draw textures */
612 if (w <= 0 || h <= 0 || x+w <= 0 || y+h <= 0) return;
613
614 g_assert(l->surface.type == Surface_Planar);
615
616 printf("making %p, %p, %p current\n", ob_display, win, render_glx_context);
617 err = glXMakeCurrent(ob_display, win, render_glx_context);
618 g_assert(err != 0);
619
620 glMatrixMode(GL_MODELVIEW);
621 glLoadIdentity();
622 glMatrixMode(GL_PROJECTION);
623 glLoadIdentity();
624 glOrtho(0, 1376, 1032, 0, 0, 10);
625 if (XGetGeometry(ob_display, win, &root, &tempx, &tempy,
626 &absw, &absh, &b, &d) &&
627 XTranslateCoordinates(ob_display, win, root, tempx, tempy,
628 &absx, &absy, &child))
629 printf("window at %d, %d (%d,%d)\n", absx, absy, absw, absh);
630 else
631 return;
632
633 glViewport(0, 0, 1376, 1032);
634 glMatrixMode(GL_MODELVIEW);
635 glTranslatef(-absx, 1032-absh-absy, 0);
636 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
637
638
639 if (l->surface.data.planar.grad == Background_ParentRelative) {
640 printf("crap\n");
641 } else
642 render_gl_gradient(&l->surface, absx+x, absy+y, absw, absh);
643
644 glXSwapBuffers(ob_display, win);
645 }
646
647 #endif /* USE_GL */
This page took 0.070316 seconds and 4 git commands to generate.