]> Dogcows Code - chaz/openbox/blob - otk/rendercontrol.cc
Added the much sought after horizontal gradient
[chaz/openbox] / otk / rendercontrol.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #include "config.h"
4
5 #include "rendercontrol.hh"
6 #include "truerendercontrol.hh"
7 #include "pseudorendercontrol.hh"
8 #include "rendertexture.hh"
9 #include "rendercolor.hh"
10 #include "renderstyle.hh"
11 #include "display.hh"
12 #include "screeninfo.hh"
13 #include "surface.hh"
14 #include "font.hh"
15 #include "ustring.hh"
16 #include "property.hh"
17
18 extern "C" {
19 #ifdef HAVE_SYS_WAIT_H
20 # include <sys/wait.h>
21 #endif // HAVE_SYS_WAIT_H
22
23 #ifdef HAVE_UNISTD_H
24 # include <unistd.h>
25 #endif // HAVE_UNISTD_H
26
27 #include "../src/gettext.h"
28 #define _(str) gettext(str)
29 }
30
31 #include <cstdlib>
32
33 namespace otk {
34
35 RenderControl *RenderControl::createRenderControl(int screen)
36 {
37 // get the visual on the screen and return the correct type of RenderControl
38 int vclass = display->screenInfo(screen)->visual()->c_class;
39 switch (vclass) {
40 case TrueColor:
41 return new TrueRenderControl(screen);
42 case PseudoColor:
43 case StaticColor:
44 return new PseudoRenderControl(screen);
45 case GrayScale:
46 case StaticGray:
47 return new PseudoRenderControl(screen);
48 default:
49 printf(_("RenderControl: Unsupported visual %d specified. Aborting.\n"),
50 vclass);
51 ::exit(1);
52 }
53 }
54
55 RenderControl::RenderControl(int screen)
56 : _screen(screen)
57
58 {
59 printf("Initializing RenderControl\n");
60
61 }
62
63 RenderControl::~RenderControl()
64 {
65 printf("Destroying RenderControl\n");
66 }
67
68 void RenderControl::drawString(Surface& sf, const Font &font, int x, int y,
69 const RenderColor &color,
70 const ustring &string) const
71 {
72 assert(sf._screen == _screen);
73 XftDraw *d = sf._xftdraw;
74 assert(d); // this means that the background hasn't been rendered yet!
75
76 if (font._shadow) {
77 XftColor c;
78 c.color.red = 0;
79 c.color.green = 0;
80 c.color.blue = 0;
81 c.color.alpha = font._tint | font._tint << 8; // transparent shadow
82 c.pixel = BlackPixel(**display, _screen);
83
84 if (string.utf8())
85 XftDrawStringUtf8(d, &c, font._xftfont, x + font._offset,
86 font._xftfont->ascent + y + font._offset,
87 (FcChar8*)string.c_str(), string.bytes());
88 else
89 XftDrawString8(d, &c, font._xftfont, x + font._offset,
90 font._xftfont->ascent + y + font._offset,
91 (FcChar8*)string.c_str(), string.bytes());
92 }
93
94 XftColor c;
95 c.color.red = color.red() | color.red() << 8;
96 c.color.green = color.green() | color.green() << 8;
97 c.color.blue = color.blue() | color.blue() << 8;
98 c.pixel = color.pixel();
99 c.color.alpha = 0xff | 0xff << 8; // no transparency in Color yet
100
101 if (string.utf8())
102 XftDrawStringUtf8(d, &c, font._xftfont, x, font._xftfont->ascent + y,
103 (FcChar8*)string.c_str(), string.bytes());
104 else
105 XftDrawString8(d, &c, font._xftfont, x, font._xftfont->ascent + y,
106 (FcChar8*)string.c_str(), string.bytes());
107 return;
108 }
109
110 void RenderControl::drawSolidBackground(Surface& sf,
111 const RenderTexture& texture) const
112 {
113 assert(_screen == sf._screen);
114 assert(_screen == texture.color().screen());
115
116 if (texture.parentRelative()) return;
117
118 sf.setPixmap(texture.color());
119
120 int width = sf.size().width(), height = sf.size().height();
121 int left = 0, top = 0, right = width - 1, bottom = height - 1;
122
123 if (texture.interlaced())
124 for (int i = 0; i < height; i += 2)
125 XDrawLine(**display, sf.pixmap(), texture.interlaceColor().gc(),
126 0, i, width, i);
127
128 switch (texture.relief()) {
129 case RenderTexture::Raised:
130 switch (texture.bevel()) {
131 case RenderTexture::Bevel1:
132 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
133 left, bottom, right, bottom);
134 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
135 right, bottom, right, top);
136
137 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
138 left, top, right, top);
139 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
140 left, bottom, left, top);
141 break;
142 case RenderTexture::Bevel2:
143 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
144 left + 1, bottom - 2, right - 2, bottom - 2);
145 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
146 right - 2, bottom - 2, right - 2, top + 1);
147
148 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
149 left + 1, top + 1, right - 2, top + 1);
150 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
151 left + 1, bottom - 2, left + 1, top + 1);
152 break;
153 default:
154 assert(false); // unhandled RenderTexture::BevelType
155 }
156 break;
157 case RenderTexture::Sunken:
158 switch (texture.bevel()) {
159 case RenderTexture::Bevel1:
160 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
161 left, bottom, right, bottom);
162 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
163 right, bottom, right, top);
164
165 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
166 left, top, right, top);
167 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
168 left, bottom, left, top);
169 break;
170 case RenderTexture::Bevel2:
171 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
172 left + 1, bottom - 2, right - 2, bottom - 2);
173 XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
174 right - 2, bottom - 2, right - 2, top + 1);
175
176 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
177 left + 1, top + 1, right - 2, top + 1);
178 XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
179 left + 1, bottom - 2, left + 1, top + 1);
180 break;
181 default:
182 assert(false); // unhandled RenderTexture::BevelType
183 }
184 break;
185 case RenderTexture::Flat:
186 if (texture.border())
187 XDrawRectangle(**display, sf.pixmap(), texture.borderColor().gc(),
188 left, top, right, bottom);
189 break;
190 default:
191 assert(false); // unhandled RenderTexture::ReliefType
192 }
193 }
194
195 void RenderControl::drawMask(Surface &sf, const RenderColor &color,
196 const PixmapMask &mask) const
197 {
198 assert(_screen == sf._screen);
199 assert(_screen == color.screen());
200
201 if (mask.mask == None) return; // no mask given
202
203 int width = sf.size().width(), height = sf.size().height();
204
205 // set the clip region
206 int x = (width - mask.w) / 2, y = (height - mask.h) / 2;
207 XSetClipMask(**display, color.gc(), mask.mask);
208 XSetClipOrigin(**display, color.gc(), x, y);
209
210 // fill in the clipped region
211 XFillRectangle(**display, sf.pixmap(), color.gc(), x, y,
212 x + mask.w, y + mask.h);
213
214 // unset the clip region
215 XSetClipMask(**display, color.gc(), None);
216 XSetClipOrigin(**display, color.gc(), 0, 0);
217 }
218
219 void RenderControl::drawGradientBackground(
220 Surface &sf, const RenderTexture &texture) const
221 {
222 unsigned int r,g,b;
223 int w = sf.size().width(), h = sf.size().height();
224 int off, x;
225
226 const ScreenInfo *info = display->screenInfo(_screen);
227 XImage *im = XCreateImage(**display, info->visual(), info->depth(),
228 ZPixmap, 0, NULL, w, h, 32, 0);
229 im->byte_order = endian;
230
231 switch (texture.gradient()) {
232 case RenderTexture::Vertical:
233 verticalGradient(sf, texture);
234 break;
235 case RenderTexture::Horizontal:
236 horizontalGradient(sf, texture);
237 break;
238 case RenderTexture::Diagonal:
239 diagonalGradient(sf, texture);
240 break;
241 case RenderTexture::CrossDiagonal:
242 crossDiagonalGradient(sf, texture);
243 break;
244 default:
245 printf("unhandled gradient\n");
246 }
247
248 pixel32 *data = sf.pixelData();
249 pixel32 current;
250
251 if (texture.relief() == RenderTexture::Flat && texture.border()) {
252 r = texture.borderColor().red();
253 g = texture.borderColor().green();
254 b = texture.borderColor().blue();
255 current = (r << default_red_shift)
256 + (g << default_green_shift)
257 + (b << default_blue_shift);
258 for (off = 0, x = 0; x < w; ++x, off++) {
259 *(data + off) = current;
260 *(data + off + ((h-1) * w)) = current;
261 }
262 for (off = 0, x = 0; x < h; ++x, off++) {
263 *(data + (off * w)) = current;
264 *(data + (off * w) + w - 1) = current;
265 }
266 }
267
268 if (texture.relief() != RenderTexture::Flat) {
269 if (texture.bevel() == RenderTexture::Bevel1) {
270 for (off = 1, x = 1; x < w - 1; ++x, off++)
271 highlight(data + off,
272 data + off + (h-1) * w,
273 texture.relief()==RenderTexture::Raised);
274 for (off = 0, x = 0; x < h; ++x, off++)
275 highlight(data + off * w,
276 data + off * w + w - 1,
277 texture.relief()==RenderTexture::Raised);
278 }
279
280 if (texture.bevel() == RenderTexture::Bevel2) {
281 for (off = 2, x = 2; x < w - 2; ++x, off++)
282 highlight(data + off + w,
283 data + off + (h-2) * w,
284 texture.relief()==RenderTexture::Raised);
285 for (off = 1, x = 1; x < h-1; ++x, off++)
286 highlight(data + off * w + 1,
287 data + off * w + w - 2,
288 texture.relief()==RenderTexture::Raised);
289 }
290 }
291
292 reduceDepth(sf, im);
293 sf.setPixmap(im);
294 XDestroyImage(im);
295 }
296
297 void RenderControl::verticalGradient(Surface &sf,
298 const RenderTexture &texture) const
299 {
300 pixel32 *data = sf.pixelData();
301 pixel32 current;
302 float dr, dg, db;
303 unsigned int r,g,b;
304 int w = sf.size().width(), h = sf.size().height();
305
306 dr = (float)(texture.secondary_color().red() - texture.color().red());
307 dr/= (float)h;
308
309 dg = (float)(texture.secondary_color().green() - texture.color().green());
310 dg/= (float)h;
311
312 db = (float)(texture.secondary_color().blue() - texture.color().blue());
313 db/= (float)h;
314
315 for (int y = 0; y < h; ++y) {
316 r = texture.color().red() + (int)(dr * y);
317 g = texture.color().green() + (int)(dg * y);
318 b = texture.color().blue() + (int)(db * y);
319 current = (r << default_red_shift)
320 + (g << default_green_shift)
321 + (b << default_blue_shift);
322 for (int x = 0; x < w; ++x, ++data)
323 *data = current;
324 }
325 }
326
327 void RenderControl::horizontalGradient(Surface &sf,
328 const RenderTexture &texture) const
329 {
330 pixel32 *data = sf.pixelData();
331 pixel32 current;
332 float dr, dg, db;
333 unsigned int r,g,b;
334 int w = sf.size().width(), h = sf.size().height();
335
336 dr = (float)(texture.secondary_color().red() - texture.color().red());
337 dr/= (float)w;
338
339 dg = (float)(texture.secondary_color().green() - texture.color().green());
340 dg/= (float)w;
341
342 db = (float)(texture.secondary_color().blue() - texture.color().blue());
343 db/= (float)w;
344
345 for (int x = 0; x < w; ++x, ++data) {
346 r = texture.color().red() + (int)(dr * x);
347 g = texture.color().green() + (int)(dg * x);
348 b = texture.color().blue() + (int)(db * x);
349 current = (r << default_red_shift)
350 + (g << default_green_shift)
351 + (b << default_blue_shift);
352 for (int y = 0; y < h; ++y)
353 *(data + y*w) = current;
354 }
355 }
356
357 void RenderControl::diagonalGradient(Surface &sf,
358 const RenderTexture &texture) const
359 {
360 pixel32 *data = sf.pixelData();
361 pixel32 current;
362 float drx, dgx, dbx, dry, dgy, dby;
363 unsigned int r,g,b;
364 int w = sf.size().width(), h = sf.size().height();
365
366 for (int y = 0; y < h; ++y) {
367 drx = (float)(texture.secondary_color().red() - texture.color().red());
368 dry = drx/(float)h;
369 drx/= (float)w;
370
371 dgx = (float)(texture.secondary_color().green() - texture.color().green());
372 dgy = dgx/(float)h;
373 dgx/= (float)w;
374
375 dbx = (float)(texture.secondary_color().blue() - texture.color().blue());
376 dby = dbx/(float)h;
377 dbx/= (float)w;
378 for (int x = 0; x < w; ++x, ++data) {
379 r = texture.color().red() + ((int)(drx * x) + (int)(dry * y))/2;
380 g = texture.color().green() + ((int)(dgx * x) + (int)(dgy * y))/2;
381 b = texture.color().blue() + ((int)(dbx * x) + (int)(dby * y))/2;
382 current = (r << default_red_shift)
383 + (g << default_green_shift)
384 + (b << default_blue_shift);
385 *data = current;
386 }
387 }
388 }
389
390 void RenderControl::crossDiagonalGradient(
391 Surface &sf, const RenderTexture &texture) const
392 {
393 pixel32 *data = sf.pixelData();
394 pixel32 current;
395 float drx, dgx, dbx, dry, dgy, dby;
396 unsigned int r,g,b;
397 int w = sf.size().width(), h = sf.size().height();
398
399 for (int y = 0; y < h; ++y) {
400 drx = (float)(texture.secondary_color().red() - texture.color().red());
401 dry = drx/(float)h;
402 drx/= (float)w;
403
404 dgx = (float)(texture.secondary_color().green() - texture.color().green());
405 dgy = dgx/(float)h;
406 dgx/= (float)w;
407
408 dbx = (float)(texture.secondary_color().blue() - texture.color().blue());
409 dby = dbx/(float)h;
410 dbx/= (float)w;
411 for (int x = w; x > 0; --x, ++data) {
412 r = texture.color().red() + ((int)(drx * (x-1)) + (int)(dry * y))/2;
413 g = texture.color().green() + ((int)(dgx * (x-1)) + (int)(dgy * y))/2;
414 b = texture.color().blue() + ((int)(dbx * (x-1)) + (int)(dby * y))/2;
415 current = (r << default_red_shift)
416 + (g << default_green_shift)
417 + (b << default_blue_shift);
418 *data = current;
419 }
420 }
421 }
422
423 void RenderControl::highlight(pixel32 *x, pixel32 *y, bool raised) const
424 {
425 int r, g, b;
426
427 pixel32 *up, *down;
428 if (raised) {
429 up = x;
430 down = y;
431 } else {
432 up = y;
433 down = x;
434 }
435 r = (*up >> default_red_shift) & 0xFF;
436 r += r >> 1;
437 g = (*up >> default_green_shift) & 0xFF;
438 g += g >> 1;
439 b = (*up >> default_blue_shift) & 0xFF;
440 b += b >> 1;
441 if (r > 255) r = 255;
442 if (g > 255) g = 255;
443 if (b > 255) b = 255;
444 *up = (r << default_red_shift) + (g << default_green_shift)
445 + (b << default_blue_shift);
446
447 r = (*down >> default_red_shift) & 0xFF;
448 r = (r >> 1) + (r >> 2);
449 g = (*down >> default_green_shift) & 0xFF;
450 g = (g >> 1) + (g >> 2);
451 b = (*down >> default_blue_shift) & 0xFF;
452 b = (b >> 1) + (b >> 2);
453 *down = (r << default_red_shift) + (g << default_green_shift)
454 + (b << default_blue_shift);
455 }
456
457 void RenderControl::drawBackground(Surface& sf,
458 const RenderTexture &texture) const
459 {
460 assert(_screen == sf._screen);
461 assert(_screen == texture.color().screen());
462
463 if (texture.gradient() == RenderTexture::Solid)
464 drawSolidBackground(sf, texture);
465 else
466 drawGradientBackground(sf, texture);
467 }
468
469
470 void RenderControl::drawImage(Surface &sf, int w, int h,
471 unsigned long *data) const
472 {
473 pixel32 *bg = sf.pixelData();
474 int c, sfw, sfh;
475 unsigned int i, e, bgi;
476 sfw = sf.size().width();
477 sfh = sf.size().height();
478
479 if (w && h) {
480 // scale it
481 unsigned long *olddata = data;
482 unsigned long newdata[sfw*sfh];
483 double dx = w / (double)sfw;
484 double dy = h / (double)sfh;
485 double px = 0.0;
486 double py = 0.0;
487 int iy = 0;
488 for (i = 0, c = 0, e = sfw*sfh; i < e; ++i) {
489 newdata[i] = olddata[(int)px + iy];
490 if (++c >= sfw) {
491 c = 0;
492 px = 0;
493 py += dy;
494 iy = (int)py * w;
495 } else
496 px += dx;
497 }
498 data = newdata;
499
500 // apply the alpha channel
501 for (i = 0, c = 0, e = sfw*sfh; i < e; ++i, ++bgi) {
502 unsigned char alpha = data[i] >> 24;
503 unsigned char r = data[i] >> 16;
504 unsigned char g = data[i] >> 8;
505 unsigned char b = data[i];
506
507 // background color
508 unsigned char bgr = bg[i] >> default_red_shift;
509 unsigned char bgg = bg[i] >> default_green_shift;
510 unsigned char bgb = bg[i] >> default_blue_shift;
511
512 r = bgr + (((r - bgr) * alpha) >> 8);
513 g = bgg + (((g - bgg) * alpha) >> 8);
514 b = bgb + (((b - bgb) * alpha) >> 8);
515
516 bg[i] = (r << default_red_shift) | (g << default_green_shift) |
517 (b << default_blue_shift);
518 }
519 }
520
521 const ScreenInfo *info = display->screenInfo(_screen);
522 XImage *im = XCreateImage(**display, info->visual(), info->depth(),
523 ZPixmap, 0, NULL, sf.size().width(),
524 sf.size().height(), 32, 0);
525 im->byte_order = endian;
526
527 reduceDepth(sf, im);
528 sf.setPixmap(im);
529 XDestroyImage(im);
530 }
531
532 void RenderControl::drawImage(Surface &sf, Pixmap pixmap, Pixmap mask) const
533 {
534 int junk, sfw, sfh, w, h, depth, mw, mh, mdepth;
535 Window wjunk;
536 const ScreenInfo *info = display->screenInfo(_screen);
537 GC mgc = 0;
538
539 assert(pixmap != None);
540
541 sfw = sf.size().width();
542 sfh = sf.size().height();
543
544 XGetGeometry(**display, pixmap, &wjunk, &junk, &junk,
545 (unsigned int*)&w, (unsigned int*)&h,
546 (unsigned int*)&junk, (unsigned int*)&depth);
547 if (mask != None) {
548 XGetGeometry(**display, mask, &wjunk, &junk, &junk,
549 (unsigned int*)&mw, (unsigned int*)&mh,
550 (unsigned int*)&junk, (unsigned int*)&mdepth);
551 if (mw != w || mh != h || mdepth != 1)
552 return;
553 }
554
555 Pixmap p = XCreatePixmap(**display, info->rootWindow(), sfw, sfh,
556 info->depth());
557 Pixmap m;
558 if (mask == None)
559 m = None;
560 else {
561 m = XCreatePixmap(**display, info->rootWindow(), sfw, sfh, 1);
562 XGCValues gcv;
563 gcv.subwindow_mode = IncludeInferiors;
564 gcv.graphics_exposures = false;
565 mgc = XCreateGC(**display, m, GCGraphicsExposures |
566 GCSubwindowMode, &gcv);
567 }
568
569 // scale it
570 for (int y = sfh - 1; y >= 0; --y) {
571 int yy = y * h / sfh;
572 for (int x = sfw - 1; x >= 0; --x) {
573 int xx = x * w / sfw;
574 if (depth != info->depth()) {
575 XCopyPlane(**display, pixmap, p, DefaultGC(**display, _screen),
576 xx, yy, 1, 1, x, y, 1);
577 } else {
578 XCopyArea(**display, pixmap, p, DefaultGC(**display, _screen),
579 xx, yy, 1, 1, x, y);
580 }
581 if (mask != None)
582 XCopyArea(**display, mask, m, mgc, xx, yy, 1, 1, x, y);
583 }
584 }
585
586 XSetClipMask(**display, DefaultGC(**display, _screen), m);
587 XSetClipOrigin(**display, DefaultGC(**display, _screen), 0, 0);
588 XCopyArea(**display, p, sf.pixmap(), DefaultGC(**display, _screen), 0, 0,
589 sfw, sfh, 0, 0);
590 XSetClipMask(**display, DefaultGC(**display, _screen), None);
591
592 XFreePixmap(**display, p);
593 if (m != None) XFreePixmap(**display, m);
594 }
595
596 }
This page took 0.06347 seconds and 4 git commands to generate.