1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 render.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
5 Copyright (c) 2003 Derek Foreman
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
21 #include <X11/Xutil.h>
37 static void pixel_data_to_pixmap(RrAppearance *l,
38 gint x, gint y, gint w, gint h);
40 void RrPaint(RrAppearance *a, Window win, gint w, gint h)
42 int i, transferred = 0, sw;
43 RrPixel32 *source, *dest;
45 RrRect tarea; /* area in which to draw textures */
48 if (w <= 0 || h <= 0) return;
50 resized = (a->w != w || a->h != h);
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));
57 g_assert(a->pixmap != None);
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);
67 g_free(a->surface.pixel_data);
68 a->surface.pixel_data = g_new(RrPixel32, w * h);
70 if (a->surface.grad == RR_SURFACE_PARENTREL) {
71 g_assert (a->surface.parent);
72 g_assert (a->surface.parent->w);
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));
86 RrMargins(a, &l, &t, &r, &b);
87 RECT_SET(tarea, l, t, w - l - r, h - t - b);
90 for (i = 0; i < a->textures; i++) {
91 switch (a->texture[i].type) {
97 if (a->surface.grad != RR_SURFACE_SOLID)
98 pixel_data_to_pixmap(a, 0, 0, w, h);
100 if (a->xftdraw == NULL) {
101 a->xftdraw = XftDrawCreate(RrDisplay(a->inst), a->pixmap,
103 RrColormap(a->inst));
105 RrFontDraw(a->xftdraw, &a->texture[i].data.text, &tarea);
107 case RR_TEXTURE_LINE_ART:
110 if (a->surface.grad != RR_SURFACE_SOLID)
111 pixel_data_to_pixmap(a, 0, 0, w, h);
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);
120 case RR_TEXTURE_MASK:
123 if (a->surface.grad != RR_SURFACE_SOLID)
124 pixel_data_to_pixmap(a, 0, 0, w, h);
126 RrPixmapMaskDraw(a->pixmap, &a->texture[i].data.mask, &tarea);
128 case RR_TEXTURE_RGBA:
129 g_assert(!transferred);
130 RrImageDraw(a->surface.pixel_data,
131 &a->texture[i].data.rgba,
140 if (a->surface.grad != RR_SURFACE_SOLID)
141 pixel_data_to_pixmap(a, 0, 0, w, h);
144 XSetWindowBackgroundPixmap(RrDisplay(a->inst), win, a->pixmap);
145 XClearWindow(RrDisplay(a->inst), win);
146 if (oldp) XFreePixmap(RrDisplay(a->inst), oldp);
149 RrAppearance *RrAppearanceNew(const RrInstance *inst, gint numtex)
153 out = g_new0(RrAppearance, 1);
155 out->textures = numtex;
156 if (numtex) out->texture = g_new0(RrTexture, numtex);
161 RrAppearance *RrAppearanceCopy(RrAppearance *orig)
163 RrSurface *spo, *spc;
164 RrAppearance *copy = g_new(RrAppearance, 1);
167 copy->inst = orig->inst;
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,
179 else spc->primary = NULL;
181 if (spo->secondary != NULL)
182 spc->secondary = RrColorNew(copy->inst,
186 else spc->secondary = NULL;
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;
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;
202 if (spo->bevel_dark != NULL)
203 spc->bevel_dark = RrColorNew(copy->inst,
207 else spc->bevel_dark = NULL;
209 if (spo->bevel_light != NULL)
210 spc->bevel_light = RrColorNew(copy->inst,
213 spo->bevel_light->b);
214 else spc->bevel_light = NULL;
216 spc->interlaced = spo->interlaced;
217 spc->border = spo->border;
219 spc->parentx = spc->parenty = 0;
220 spc->pixel_data = NULL;
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;
230 copy->xftdraw = NULL;
231 copy->w = copy->h = 0;
235 void RrAppearanceFree(RrAppearance *a)
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;
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);
264 static void pixel_data_to_pixmap(RrAppearance *l,
265 gint x, gint y, gint w, gint h)
267 RrPixel32 *in, *scratch;
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);
274 in = l->surface.pixel_data;
277 /* this malloc is a complete waste of time on normal 32bpp
278 as reduce_depth just sets im->data = data and returns
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);
291 void RrMargins (RrAppearance *a, gint *l, gint *t, gint *r, gint *b)
293 *l = *t = *r = *b = 0;
295 if (a->surface.grad != RR_SURFACE_PARENTREL) {
296 if (a->surface.relief != RR_RELIEF_FLAT) {
297 switch (a->surface.bevel) {
299 *l = *t = *r = *b = 1;
302 *l = *t = *r = *b = 2;
305 } else if (a->surface.border) {
306 *l = *t = *r = *b = 1;
311 void RrMinsize(RrAppearance *a, gint *w, gint *h)
318 for (i = 0; i < a->textures; ++i) {
319 switch (a->texture[i].type) {
320 case RR_TEXTURE_NONE:
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);
326 case RR_TEXTURE_TEXT:
327 m = RrFontMeasureString(a->texture[i].data.text.font,
328 a->texture[i].data.text.string);
330 m = RrFontHeight(a->texture[i].data.text.font);
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);
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));
346 RrMargins(a, &l, &t, &r, &b);
355 gboolean RrPixmapToRGBA(const RrInstance *inst,
356 Pixmap pmap, Pixmap mask,
357 gint *w, gint *h, RrPixel32 **data)
361 guint pw, ph, mw, mh, xb, xd, i, x, y, di;
362 XImage *xi, *xm = NULL;
364 if (!XGetGeometry(RrDisplay(inst),
365 pmap, &xr, &xx, &xy, &pw, &ph, &xb, &xd))
368 if (!XGetGeometry(RrDisplay(inst), mask,
369 &xr, &xx, &xy, &mw, &mh, &xb, &xd))
371 if (pw != mw || ph != mh || xd != 1)
375 xi = XGetImage(RrDisplay(inst), pmap,
376 0, 0, pw, ph, 0xffffffff, ZPixmap);
381 xm = XGetImage(RrDisplay(inst), mask,
382 0, 0, mw, mh, 0xffffffff, ZPixmap);
389 *data = g_new(RrPixel32, pw * ph);
390 RrIncreaseDepth(inst, *data, xi);
393 /* apply transparency from the mask */
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);
400 di += xm->bytes_per_line;