]> Dogcows Code - chaz/openbox/blob - render/render.c
smarter picking valid focus cycle targets
[chaz/openbox] / render / render.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 render.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
5 Copyright (c) 2003 Derek Foreman
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22
23 #include "render.h"
24 #include "gradient.h"
25 #include "font.h"
26 #include "mask.h"
27 #include "color.h"
28 #include "image.h"
29 #include "theme.h"
30
31 #include <glib.h>
32
33 #ifdef HAVE_STDLIB_H
34 # include <stdlib.h>
35 #endif
36
37 static void pixel_data_to_pixmap(RrAppearance *l,
38 gint x, gint y, gint w, gint h);
39
40 void RrPaint(RrAppearance *a, Window win, gint w, gint h)
41 {
42 int i, transferred = 0, sw;
43 RrPixel32 *source, *dest;
44 Pixmap oldp;
45 RrRect tarea; /* area in which to draw textures */
46 gboolean resized;
47
48 if (w <= 0 || h <= 0) return;
49
50 resized = (a->w != w || a->h != h);
51
52 oldp = a->pixmap; /* save to free after changing the visible pixmap */
53 a->pixmap = XCreatePixmap(RrDisplay(a->inst),
54 RrRootWindow(a->inst),
55 w, h, RrDepth(a->inst));
56
57 g_assert(a->pixmap != None);
58 a->w = w;
59 a->h = h;
60
61 if (a->xftdraw != NULL)
62 XftDrawDestroy(a->xftdraw);
63 a->xftdraw = XftDrawCreate(RrDisplay(a->inst), a->pixmap,
64 RrVisual(a->inst), RrColormap(a->inst));
65 g_assert(a->xftdraw != NULL);
66
67 g_free(a->surface.pixel_data);
68 a->surface.pixel_data = g_new(RrPixel32, w * h);
69
70 if (a->surface.grad == RR_SURFACE_PARENTREL) {
71 g_assert (a->surface.parent);
72 g_assert (a->surface.parent->w);
73
74 sw = a->surface.parent->w;
75 source = (a->surface.parent->surface.pixel_data +
76 a->surface.parentx + sw * a->surface.parenty);
77 dest = a->surface.pixel_data;
78 for (i = 0; i < h; i++, source += sw, dest += w) {
79 memcpy(dest, source, w * sizeof(RrPixel32));
80 }
81 } else
82 RrRender(a, w, h);
83
84 {
85 gint l, t, r, b;
86 RrMargins(a, &l, &t, &r, &b);
87 RECT_SET(tarea, l, t, w - l - r, h - t - b);
88 }
89
90 for (i = 0; i < a->textures; i++) {
91 switch (a->texture[i].type) {
92 case RR_TEXTURE_NONE:
93 break;
94 case RR_TEXTURE_TEXT:
95 if (!transferred) {
96 transferred = 1;
97 if (a->surface.grad != RR_SURFACE_SOLID)
98 pixel_data_to_pixmap(a, 0, 0, w, h);
99 }
100 if (a->xftdraw == NULL) {
101 a->xftdraw = XftDrawCreate(RrDisplay(a->inst), a->pixmap,
102 RrVisual(a->inst),
103 RrColormap(a->inst));
104 }
105 RrFontDraw(a->xftdraw, &a->texture[i].data.text, &tarea);
106 break;
107 case RR_TEXTURE_LINE_ART:
108 if (!transferred) {
109 transferred = 1;
110 if (a->surface.grad != RR_SURFACE_SOLID)
111 pixel_data_to_pixmap(a, 0, 0, w, h);
112 }
113 XDrawLine(RrDisplay(a->inst), a->pixmap,
114 RrColorGC(a->texture[i].data.lineart.color),
115 a->texture[i].data.lineart.x1,
116 a->texture[i].data.lineart.y1,
117 a->texture[i].data.lineart.x2,
118 a->texture[i].data.lineart.y2);
119 break;
120 case RR_TEXTURE_MASK:
121 if (!transferred) {
122 transferred = 1;
123 if (a->surface.grad != RR_SURFACE_SOLID)
124 pixel_data_to_pixmap(a, 0, 0, w, h);
125 }
126 RrPixmapMaskDraw(a->pixmap, &a->texture[i].data.mask, &tarea);
127 break;
128 case RR_TEXTURE_RGBA:
129 g_assert(!transferred);
130 RrImageDraw(a->surface.pixel_data,
131 &a->texture[i].data.rgba,
132 a->w, a->h,
133 &tarea);
134 break;
135 }
136 }
137
138 if (!transferred) {
139 transferred = 1;
140 if (a->surface.grad != RR_SURFACE_SOLID)
141 pixel_data_to_pixmap(a, 0, 0, w, h);
142 }
143
144 XSetWindowBackgroundPixmap(RrDisplay(a->inst), win, a->pixmap);
145 XClearWindow(RrDisplay(a->inst), win);
146 if (oldp) XFreePixmap(RrDisplay(a->inst), oldp);
147 }
148
149 RrAppearance *RrAppearanceNew(const RrInstance *inst, gint numtex)
150 {
151 RrAppearance *out;
152
153 out = g_new0(RrAppearance, 1);
154 out->inst = inst;
155 out->textures = numtex;
156 if (numtex) out->texture = g_new0(RrTexture, numtex);
157
158 return out;
159 }
160
161 RrAppearance *RrAppearanceCopy(RrAppearance *orig)
162 {
163 RrSurface *spo, *spc;
164 RrAppearance *copy = g_new(RrAppearance, 1);
165 gint i;
166
167 copy->inst = orig->inst;
168
169 spo = &(orig->surface);
170 spc = &(copy->surface);
171 spc->grad = spo->grad;
172 spc->relief = spo->relief;
173 spc->bevel = spo->bevel;
174 if (spo->primary != NULL)
175 spc->primary = RrColorNew(copy->inst,
176 spo->primary->r,
177 spo->primary->g,
178 spo->primary->b);
179 else spc->primary = NULL;
180
181 if (spo->secondary != NULL)
182 spc->secondary = RrColorNew(copy->inst,
183 spo->secondary->r,
184 spo->secondary->g,
185 spo->secondary->b);
186 else spc->secondary = NULL;
187
188 if (spo->border_color != NULL)
189 spc->border_color = RrColorNew(copy->inst,
190 spo->border_color->r,
191 spo->border_color->g,
192 spo->border_color->b);
193 else spc->border_color = NULL;
194
195 if (spo->interlace_color != NULL)
196 spc->interlace_color = RrColorNew(copy->inst,
197 spo->interlace_color->r,
198 spo->interlace_color->g,
199 spo->interlace_color->b);
200 else spc->interlace_color = NULL;
201
202 if (spo->bevel_dark != NULL)
203 spc->bevel_dark = RrColorNew(copy->inst,
204 spo->bevel_dark->r,
205 spo->bevel_dark->g,
206 spo->bevel_dark->b);
207 else spc->bevel_dark = NULL;
208
209 if (spo->bevel_light != NULL)
210 spc->bevel_light = RrColorNew(copy->inst,
211 spo->bevel_light->r,
212 spo->bevel_light->g,
213 spo->bevel_light->b);
214 else spc->bevel_light = NULL;
215
216 spc->interlaced = spo->interlaced;
217 spc->border = spo->border;
218 spc->parent = NULL;
219 spc->parentx = spc->parenty = 0;
220 spc->pixel_data = NULL;
221
222 copy->textures = orig->textures;
223 copy->texture = g_memdup(orig->texture,
224 orig->textures * sizeof(RrTexture));
225 for (i = 0; i < copy->textures; ++i)
226 if (copy->texture[i].type == RR_TEXTURE_RGBA) {
227 copy->texture[i].data.rgba.cache = NULL;
228 }
229 copy->pixmap = None;
230 copy->xftdraw = NULL;
231 copy->w = copy->h = 0;
232 return copy;
233 }
234
235 void RrAppearanceFree(RrAppearance *a)
236 {
237 gint i;
238
239 if (a) {
240 RrSurface *p;
241 if (a->pixmap != None) XFreePixmap(RrDisplay(a->inst), a->pixmap);
242 if (a->xftdraw != NULL) XftDrawDestroy(a->xftdraw);
243 for (i = 0; i < a->textures; ++i)
244 if (a->texture[i].type == RR_TEXTURE_RGBA) {
245 g_free(a->texture[i].data.rgba.cache);
246 a->texture[i].data.rgba.cache = NULL;
247 }
248 if (a->textures)
249 g_free(a->texture);
250 p = &a->surface;
251 RrColorFree(p->primary);
252 RrColorFree(p->secondary);
253 RrColorFree(p->border_color);
254 RrColorFree(p->interlace_color);
255 RrColorFree(p->bevel_dark);
256 RrColorFree(p->bevel_light);
257 g_free(p->pixel_data);
258
259 g_free(a);
260 }
261 }
262
263
264 static void pixel_data_to_pixmap(RrAppearance *l,
265 gint x, gint y, gint w, gint h)
266 {
267 RrPixel32 *in, *scratch;
268 Pixmap out;
269 XImage *im = NULL;
270 im = XCreateImage(RrDisplay(l->inst), RrVisual(l->inst), RrDepth(l->inst),
271 ZPixmap, 0, NULL, w, h, 32, 0);
272 g_assert(im != NULL);
273
274 in = l->surface.pixel_data;
275 out = l->pixmap;
276
277 /* this malloc is a complete waste of time on normal 32bpp
278 as reduce_depth just sets im->data = data and returns
279 */
280 scratch = g_new(RrPixel32, im->width * im->height);
281 im->data = (char*) scratch;
282 RrReduceDepth(l->inst, in, im);
283 XPutImage(RrDisplay(l->inst), out,
284 DefaultGC(RrDisplay(l->inst), RrScreen(l->inst)),
285 im, 0, 0, x, y, w, h);
286 im->data = NULL;
287 XDestroyImage(im);
288 g_free(scratch);
289 }
290
291 void RrMargins (RrAppearance *a, gint *l, gint *t, gint *r, gint *b)
292 {
293 *l = *t = *r = *b = 0;
294
295 if (a->surface.grad != RR_SURFACE_PARENTREL) {
296 if (a->surface.relief != RR_RELIEF_FLAT) {
297 switch (a->surface.bevel) {
298 case RR_BEVEL_1:
299 *l = *t = *r = *b = 1;
300 break;
301 case RR_BEVEL_2:
302 *l = *t = *r = *b = 2;
303 break;
304 }
305 } else if (a->surface.border) {
306 *l = *t = *r = *b = 1;
307 }
308 }
309 }
310
311 void RrMinsize(RrAppearance *a, gint *w, gint *h)
312 {
313 gint i;
314 gint m;
315 gint l, t, r, b;
316 *w = *h = 0;
317
318 for (i = 0; i < a->textures; ++i) {
319 switch (a->texture[i].type) {
320 case RR_TEXTURE_NONE:
321 break;
322 case RR_TEXTURE_MASK:
323 *w = MAX(*w, a->texture[i].data.mask.mask->width);
324 *h = MAX(*h, a->texture[i].data.mask.mask->height);
325 break;
326 case RR_TEXTURE_TEXT:
327 m = RrFontMeasureString(a->texture[i].data.text.font,
328 a->texture[i].data.text.string);
329 *w = MAX(*w, m);
330 m = RrFontHeight(a->texture[i].data.text.font);
331 *h += MAX(*h, m);
332 break;
333 case RR_TEXTURE_RGBA:
334 *w += MAX(*w, a->texture[i].data.rgba.width);
335 *h += MAX(*h, a->texture[i].data.rgba.height);
336 break;
337 case RR_TEXTURE_LINE_ART:
338 *w += MAX(*w, MAX(a->texture[i].data.lineart.x1,
339 a->texture[i].data.lineart.x2));
340 *h += MAX(*h, MAX(a->texture[i].data.lineart.y1,
341 a->texture[i].data.lineart.y2));
342 break;
343 }
344 }
345
346 RrMargins(a, &l, &t, &r, &b);
347
348 *w += l + r;
349 *h += t + b;
350
351 if (*w < 1) *w = 1;
352 if (*h < 1) *h = 1;
353 }
354
355 gboolean RrPixmapToRGBA(const RrInstance *inst,
356 Pixmap pmap, Pixmap mask,
357 gint *w, gint *h, RrPixel32 **data)
358 {
359 Window xr;
360 gint xx, xy;
361 guint pw, ph, mw, mh, xb, xd, i, x, y, di;
362 XImage *xi, *xm = NULL;
363
364 if (!XGetGeometry(RrDisplay(inst),
365 pmap, &xr, &xx, &xy, &pw, &ph, &xb, &xd))
366 return FALSE;
367 if (mask) {
368 if (!XGetGeometry(RrDisplay(inst), mask,
369 &xr, &xx, &xy, &mw, &mh, &xb, &xd))
370 return FALSE;
371 if (pw != mw || ph != mh || xd != 1)
372 return FALSE;
373 }
374
375 xi = XGetImage(RrDisplay(inst), pmap,
376 0, 0, pw, ph, 0xffffffff, ZPixmap);
377 if (!xi)
378 return FALSE;
379
380 if (mask) {
381 xm = XGetImage(RrDisplay(inst), mask,
382 0, 0, mw, mh, 0xffffffff, ZPixmap);
383 if (!xm) {
384 XDestroyImage(xi);
385 return FALSE;
386 }
387 }
388
389 *data = g_new(RrPixel32, pw * ph);
390 RrIncreaseDepth(inst, *data, xi);
391
392 if (mask) {
393 /* apply transparency from the mask */
394 di = 0;
395 for (i = 0, y = 0; y < ph; ++y) {
396 for (x = 0; x < pw; ++x, ++i) {
397 if (!((((unsigned)xm->data[di + x / 8]) >> (x % 8)) & 0x1))
398 (*data)[i] &= ~(0xff << RrDefaultAlphaOffset);
399 }
400 di += xm->bytes_per_line;
401 }
402 }
403
404 *w = pw;
405 *h = ph;
406
407 XDestroyImage(xi);
408 if (mask)
409 XDestroyImage(xm);
410
411 return TRUE;
412 }
This page took 0.052624 seconds and 4 git commands to generate.