1 /**
2 * @file render.c
3 * @author Joe Wingbermuehle
4 * @date 2005-2006
5 *
6 * @brief Functions to render icons using the XRender extension.
7 *
8 */
9
10 #include "jwm.h"
11 #include "render.h"
12 #include "icon.h"
13 #include "image.h"
14 #include "main.h"
15 #include "color.h"
16 #include "misc.h"
17
18 /** Draw a scaled icon. */
PutScaledRenderIcon(const IconNode * icon,const ScaledIconNode * node,Drawable d,int x,int y,int width,int height)19 void PutScaledRenderIcon(const IconNode *icon,
20 const ScaledIconNode *node,
21 Drawable d, int x, int y, int width, int height)
22 {
23
24 #ifdef USE_XRENDER
25
26 Picture source;
27
28 Assert(icon);
29 Assert(haveRender);
30
31 source = node->image;
32 if(source != None) {
33
34 XRenderPictureAttributes pa;
35 XTransform xf;
36 int xscale, yscale;
37 int nwidth, nheight;
38 Picture dest;
39 Picture alpha = node->mask;
40 XRenderPictFormat *fp = JXRenderFindVisualFormat(display, rootVisual);
41 Assert(fp);
42
43 pa.subwindow_mode = IncludeInferiors;
44 dest = JXRenderCreatePicture(display, d, fp, CPSubwindowMode, &pa);
45
46 width = width == 0 ? node->width : width;
47 height = height == 0 ? node->height : height;
48 if(icon->preserveAspect) {
49 const int ratio = (icon->width << 16) / icon->height;
50 nwidth = Min(width, (height * ratio) >> 16);
51 nheight = Min(height, (nwidth << 16) / ratio);
52 nwidth = (nheight * ratio) >> 16;
53 nwidth = Max(1, nwidth);
54 nheight = Max(1, nheight);
55 x += (width - nwidth) / 2;
56 y += (height - nheight) / 2;
57 } else {
58 nwidth = width;
59 nheight = height;
60 }
61 xscale = (node->width << 16) / nwidth;
62 yscale = (node->height << 16) / nheight;
63
64 memset(&xf, 0, sizeof(xf));
65 xf.matrix[0][0] = xscale;
66 xf.matrix[1][1] = yscale;
67 xf.matrix[2][2] = 65536;
68 XRenderSetPictureTransform(display, source, &xf);
69 XRenderSetPictureFilter(display, source, FilterBest, NULL, 0);
70 XRenderSetPictureTransform(display, alpha, &xf);
71 XRenderSetPictureFilter(display, alpha, FilterBest, NULL, 0);
72
73 JXRenderComposite(display, PictOpOver, source, alpha, dest,
74 0, 0, 0, 0, x, y, width, height);
75
76 JXRenderFreePicture(display, dest);
77
78 }
79
80 #endif
81
82 }
83
84 /** Create a scaled icon. */
CreateScaledRenderIcon(ImageNode * image,long fg)85 ScaledIconNode *CreateScaledRenderIcon(ImageNode *image, long fg)
86 {
87
88 ScaledIconNode *result = NULL;
89
90 #ifdef USE_XRENDER
91
92 XRenderPictFormat *fp;
93 XColor color;
94 GC maskGC;
95 XImage *destImage;
96 XImage *destMask;
97 Pixmap pmap, mask;
98 const unsigned width = image->width;
99 const unsigned height = image->height;
100 unsigned perLine;
101 int x, y;
102 int maskLine;
103
104 Assert(haveRender);
105
106 result = Allocate(sizeof(ScaledIconNode));
107 result->fg = fg;
108 result->width = width;
109 result->height = height;
110
111 mask = JXCreatePixmap(display, rootWindow, width, height, 8);
112 maskGC = JXCreateGC(display, mask, 0, NULL);
113 pmap = JXCreatePixmap(display, rootWindow, width, height, rootDepth);
114
115 destImage = JXCreateImage(display, rootVisual, rootDepth,
116 ZPixmap, 0, NULL, width, height, 8, 0);
117 destImage->data = Allocate(sizeof(unsigned long) * width * height);
118
119 destMask = JXCreateImage(display, rootVisual, 8, ZPixmap,
120 0, NULL, width, height, 8, 0);
121 destMask->data = Allocate(width * height);
122
123 if(image->bitmap) {
124 perLine = (image->width >> 3) + ((image->width & 7) ? 1 : 0);
125 } else {
126 perLine = image->width;
127 }
128 maskLine = 0;
129 for(y = 0; y < height; y++) {
130 const int yindex = y * perLine;
131 for(x = 0; x < width; x++) {
132 if(image->bitmap) {
133
134 const int offset = yindex + (x >> 3);
135 const int mask = 1 << (x & 7);
136 unsigned long alpha = 0;
137 if(image->data[offset] & mask) {
138 alpha = 255;
139 XPutPixel(destImage, x, y, fg);
140 }
141 destMask->data[maskLine + x] = alpha;
142
143 } else {
144
145 const int index = 4 * (yindex + x);
146 const unsigned long alpha = image->data[index];
147 color.red = image->data[index + 1];
148 color.red |= color.red << 8;
149 color.green = image->data[index + 2];
150 color.green |= color.green << 8;
151 color.blue = image->data[index + 3];
152 color.blue |= color.blue << 8;
153
154 color.red = (color.red * alpha) >> 8;
155 color.green = (color.green * alpha) >> 8;
156 color.blue = (color.blue * alpha) >> 8;
157
158 GetColor(&color);
159 XPutPixel(destImage, x, y, color.pixel);
160 destMask->data[maskLine + x] = alpha;
161 }
162 }
163 maskLine += destMask->bytes_per_line;
164 }
165
166 /* Render the image data to the image pixmap. */
167 JXPutImage(display, pmap, rootGC, destImage, 0, 0, 0, 0, width, height);
168 Release(destImage->data);
169 destImage->data = NULL;
170 JXDestroyImage(destImage);
171
172 /* Render the alpha data to the mask pixmap. */
173 JXPutImage(display, mask, maskGC, destMask, 0, 0, 0, 0, width, height);
174 Release(destMask->data);
175 destMask->data = NULL;
176 JXDestroyImage(destMask);
177 JXFreeGC(display, maskGC);
178
179 /* Create the alpha picture. */
180 fp = JXRenderFindStandardFormat(display, PictStandardA8);
181 Assert(fp);
182 result->mask = JXRenderCreatePicture(display, mask, fp, 0, NULL);
183 JXFreePixmap(display, mask);
184
185 /* Create the render picture. */
186 fp = JXRenderFindVisualFormat(display, rootVisual);
187 Assert(fp);
188 result->image = JXRenderCreatePicture(display, pmap, fp, 0, NULL);
189 JXFreePixmap(display, pmap);
190
191 #endif
192
193 return result;
194
195 }
196