Update local copy of GPLv2 and FSF address in copyrights
[wmaker-crm.git] / src / texture.c
bloba18ed22891cc02200c9744033b20cbb049671e5b
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "wconfig.h"
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include <wraster.h>
32 #include "WindowMaker.h"
33 #include "texture.h"
34 #include "funcs.h"
36 extern WPreferences wPreferences;
38 static void bevelImage(RImage * image, int relief);
40 WTexSolid *wTextureMakeSolid(WScreen * scr, XColor * color)
42 WTexSolid *texture;
43 int gcm;
44 XGCValues gcv;
46 texture = wmalloc(sizeof(WTexture));
48 texture->type = WTEX_SOLID;
49 texture->subtype = 0;
51 XAllocColor(dpy, scr->w_colormap, color);
52 texture->normal = *color;
53 if (color->red == 0 && color->blue == 0 && color->green == 0) {
54 texture->light.red = 0xb6da;
55 texture->light.green = 0xb6da;
56 texture->light.blue = 0xb6da;
57 texture->dim.red = 0x6185;
58 texture->dim.green = 0x6185;
59 texture->dim.blue = 0x6185;
60 } else {
61 RColor rgb;
62 RHSVColor hsv, hsv2;
63 int v;
65 rgb.red = color->red >> 8;
66 rgb.green = color->green >> 8;
67 rgb.blue = color->blue >> 8;
68 RRGBtoHSV(&rgb, &hsv);
69 RHSVtoRGB(&hsv, &rgb);
70 hsv2 = hsv;
72 v = hsv.value * 16 / 10;
73 hsv.value = (v > 255 ? 255 : v);
74 RHSVtoRGB(&hsv, &rgb);
75 texture->light.red = rgb.red << 8;
76 texture->light.green = rgb.green << 8;
77 texture->light.blue = rgb.blue << 8;
79 hsv2.value = hsv2.value / 2;
80 RHSVtoRGB(&hsv2, &rgb);
81 texture->dim.red = rgb.red << 8;
82 texture->dim.green = rgb.green << 8;
83 texture->dim.blue = rgb.blue << 8;
85 texture->dark.red = 0;
86 texture->dark.green = 0;
87 texture->dark.blue = 0;
88 XAllocColor(dpy, scr->w_colormap, &texture->light);
89 XAllocColor(dpy, scr->w_colormap, &texture->dim);
90 XAllocColor(dpy, scr->w_colormap, &texture->dark);
92 gcm = GCForeground | GCBackground | GCGraphicsExposures;
93 gcv.graphics_exposures = False;
95 gcv.background = gcv.foreground = texture->light.pixel;
96 texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
98 gcv.background = gcv.foreground = texture->dim.pixel;
99 texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
101 gcv.background = gcv.foreground = texture->dark.pixel;
102 texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
104 gcv.background = gcv.foreground = color->pixel;
105 texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
107 return texture;
110 static int dummyErrorHandler(Display * foo, XErrorEvent * bar)
112 return 0;
115 void wTextureDestroy(WScreen * scr, WTexture * texture)
117 int i;
118 int count = 0;
119 unsigned long colors[8];
122 * some stupid servers don't like white or black being freed...
124 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
125 switch (texture->any.type) {
126 case WTEX_SOLID:
127 XFreeGC(dpy, texture->solid.light_gc);
128 XFreeGC(dpy, texture->solid.dark_gc);
129 XFreeGC(dpy, texture->solid.dim_gc);
130 if (CANFREE(texture->solid.light.pixel))
131 colors[count++] = texture->solid.light.pixel;
132 if (CANFREE(texture->solid.dim.pixel))
133 colors[count++] = texture->solid.dim.pixel;
134 if (CANFREE(texture->solid.dark.pixel))
135 colors[count++] = texture->solid.dark.pixel;
136 break;
138 case WTEX_PIXMAP:
139 RReleaseImage(texture->pixmap.pixmap);
140 break;
142 case WTEX_MHGRADIENT:
143 case WTEX_MVGRADIENT:
144 case WTEX_MDGRADIENT:
145 for (i = 0; texture->mgradient.colors[i] != NULL; i++) {
146 wfree(texture->mgradient.colors[i]);
148 wfree(texture->mgradient.colors);
149 break;
151 case WTEX_THGRADIENT:
152 case WTEX_TVGRADIENT:
153 case WTEX_TDGRADIENT:
154 RReleaseImage(texture->tgradient.pixmap);
155 break;
158 if (CANFREE(texture->any.color.pixel))
159 colors[count++] = texture->any.color.pixel;
160 if (count > 0) {
161 XErrorHandler oldhandler;
163 /* ignore error from buggy servers that don't know how
164 * to do reference counting for colors. */
165 XSync(dpy, 0);
166 oldhandler = XSetErrorHandler(dummyErrorHandler);
167 XFreeColors(dpy, scr->w_colormap, colors, count, 0);
168 XSync(dpy, 0);
169 XSetErrorHandler(oldhandler);
171 XFreeGC(dpy, texture->any.gc);
172 wfree(texture);
173 #undef CANFREE
176 WTexGradient *wTextureMakeGradient(WScreen * scr, int style, RColor * from, RColor * to)
178 WTexGradient *texture;
179 XGCValues gcv;
181 texture = wmalloc(sizeof(WTexture));
182 memset(texture, 0, sizeof(WTexture));
183 texture->type = style;
184 texture->subtype = 0;
186 texture->color1 = *from;
187 texture->color2 = *to;
189 texture->normal.red = (from->red + to->red) << 7;
190 texture->normal.green = (from->green + to->green) << 7;
191 texture->normal.blue = (from->blue + to->blue) << 7;
193 XAllocColor(dpy, scr->w_colormap, &texture->normal);
194 gcv.background = gcv.foreground = texture->normal.pixel;
195 gcv.graphics_exposures = False;
196 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
198 return texture;
201 WTexIGradient *wTextureMakeIGradient(WScreen * scr, int thickness1, RColor colors1[2],
202 int thickness2, RColor colors2[2])
204 WTexIGradient *texture;
205 XGCValues gcv;
206 int i;
208 texture = wmalloc(sizeof(WTexture));
209 memset(texture, 0, sizeof(WTexture));
210 texture->type = WTEX_IGRADIENT;
211 for (i = 0; i < 2; i++) {
212 texture->colors1[i] = colors1[i];
213 texture->colors2[i] = colors2[i];
215 texture->thickness1 = thickness1;
216 texture->thickness2 = thickness2;
217 if (thickness1 >= thickness2) {
218 texture->normal.red = (colors1[0].red + colors1[1].red) << 7;
219 texture->normal.green = (colors1[0].green + colors1[1].green) << 7;
220 texture->normal.blue = (colors1[0].blue + colors1[1].blue) << 7;
221 } else {
222 texture->normal.red = (colors2[0].red + colors2[1].red) << 7;
223 texture->normal.green = (colors2[0].green + colors2[1].green) << 7;
224 texture->normal.blue = (colors2[0].blue + colors2[1].blue) << 7;
226 XAllocColor(dpy, scr->w_colormap, &texture->normal);
227 gcv.background = gcv.foreground = texture->normal.pixel;
228 gcv.graphics_exposures = False;
229 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
231 return texture;
234 WTexMGradient *wTextureMakeMGradient(WScreen * scr, int style, RColor ** colors)
236 WTexMGradient *texture;
237 XGCValues gcv;
238 int i;
240 texture = wmalloc(sizeof(WTexture));
241 memset(texture, 0, sizeof(WTexture));
242 texture->type = style;
243 texture->subtype = 0;
245 i = 0;
246 while (colors[i] != NULL)
247 i++;
248 i--;
249 texture->normal.red = (colors[0]->red << 8);
250 texture->normal.green = (colors[0]->green << 8);
251 texture->normal.blue = (colors[0]->blue << 8);
253 texture->colors = colors;
255 XAllocColor(dpy, scr->w_colormap, &texture->normal);
256 gcv.background = gcv.foreground = texture->normal.pixel;
257 gcv.graphics_exposures = False;
258 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
260 return texture;
263 WTexPixmap *wTextureMakePixmap(WScreen * scr, int style, char *pixmap_file, XColor * color)
265 WTexPixmap *texture;
266 XGCValues gcv;
267 RImage *image;
268 char *file;
270 file = FindImage(wPreferences.pixmap_path, pixmap_file);
271 if (!file) {
272 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
273 return NULL;
275 image = RLoadImage(scr->rcontext, file, 0);
276 if (!image) {
277 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
278 wfree(file);
279 return NULL;
281 wfree(file);
283 texture = wmalloc(sizeof(WTexture));
284 memset(texture, 0, sizeof(WTexture));
285 texture->type = WTEX_PIXMAP;
286 texture->subtype = style;
288 texture->normal = *color;
290 XAllocColor(dpy, scr->w_colormap, &texture->normal);
291 gcv.background = gcv.foreground = texture->normal.pixel;
292 gcv.graphics_exposures = False;
293 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
295 texture->pixmap = image;
297 return texture;
300 WTexTGradient *wTextureMakeTGradient(WScreen * scr, int style, RColor * from, RColor * to,
301 char *pixmap_file, int opacity)
303 WTexTGradient *texture;
304 XGCValues gcv;
305 RImage *image;
306 char *file;
308 file = FindImage(wPreferences.pixmap_path, pixmap_file);
309 if (!file) {
310 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
311 return NULL;
313 image = RLoadImage(scr->rcontext, file, 0);
314 if (!image) {
315 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
316 wfree(file);
317 return NULL;
319 wfree(file);
321 texture = wmalloc(sizeof(WTexture));
322 memset(texture, 0, sizeof(WTexture));
323 texture->type = style;
325 texture->opacity = opacity;
327 texture->color1 = *from;
328 texture->color2 = *to;
330 texture->normal.red = (from->red + to->red) << 7;
331 texture->normal.green = (from->green + to->green) << 7;
332 texture->normal.blue = (from->blue + to->blue) << 7;
334 XAllocColor(dpy, scr->w_colormap, &texture->normal);
335 gcv.background = gcv.foreground = texture->normal.pixel;
336 gcv.graphics_exposures = False;
337 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
339 texture->pixmap = image;
341 return texture;
344 RImage *wTextureRenderImage(WTexture * texture, int width, int height, int relief)
346 RImage *image = NULL;
347 RColor color1;
348 int d;
349 int subtype;
351 switch (texture->any.type) {
352 case WTEX_SOLID:
353 image = RCreateImage(width, height, False);
355 color1.red = texture->solid.normal.red >> 8;
356 color1.green = texture->solid.normal.green >> 8;
357 color1.blue = texture->solid.normal.blue >> 8;
358 color1.alpha = 255;
360 RClearImage(image, &color1);
361 break;
363 case WTEX_PIXMAP:
364 if (texture->pixmap.subtype == WTP_TILE) {
365 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
366 } else if (texture->pixmap.subtype == WTP_CENTER) {
367 color1.red = texture->pixmap.normal.red >> 8;
368 color1.green = texture->pixmap.normal.green >> 8;
369 color1.blue = texture->pixmap.normal.blue >> 8;
370 color1.alpha = 255;
371 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height, &color1);
372 } else {
373 image = RScaleImage(texture->pixmap.pixmap, width, height);
375 break;
377 case WTEX_IGRADIENT:
378 image = RRenderInterwovenGradient(width, height,
379 texture->igradient.colors1,
380 texture->igradient.thickness1,
381 texture->igradient.colors2, texture->igradient.thickness2);
382 break;
384 case WTEX_HGRADIENT:
385 subtype = RGRD_HORIZONTAL;
386 goto render_gradient;
388 case WTEX_VGRADIENT:
389 subtype = RGRD_VERTICAL;
390 goto render_gradient;
392 case WTEX_DGRADIENT:
393 subtype = RGRD_DIAGONAL;
394 render_gradient:
396 image = RRenderGradient(width, height, &texture->gradient.color1,
397 &texture->gradient.color2, subtype);
398 break;
400 case WTEX_MHGRADIENT:
401 subtype = RGRD_HORIZONTAL;
402 goto render_mgradient;
404 case WTEX_MVGRADIENT:
405 subtype = RGRD_VERTICAL;
406 goto render_mgradient;
408 case WTEX_MDGRADIENT:
409 subtype = RGRD_DIAGONAL;
410 render_mgradient:
411 image = RRenderMultiGradient(width, height, &(texture->mgradient.colors[1]), subtype);
412 break;
414 case WTEX_THGRADIENT:
415 subtype = RGRD_HORIZONTAL;
416 goto render_tgradient;
418 case WTEX_TVGRADIENT:
419 subtype = RGRD_VERTICAL;
420 goto render_tgradient;
422 case WTEX_TDGRADIENT:
423 subtype = RGRD_DIAGONAL;
424 render_tgradient:
426 RImage *grad;
428 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
429 if (!image)
430 break;
432 grad = RRenderGradient(width, height, &texture->tgradient.color1,
433 &texture->tgradient.color2, subtype);
434 if (!grad) {
435 RReleaseImage(image);
436 image = NULL;
437 break;
440 RCombineImagesWithOpaqueness(image, grad, texture->tgradient.opacity);
441 RReleaseImage(grad);
443 break;
444 default:
445 puts("ERROR in wTextureRenderImage()");
446 image = NULL;
447 break;
450 if (!image) {
451 RColor gray;
453 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
455 image = RCreateImage(width, height, False);
456 if (image == NULL) {
457 wwarning(_("could not allocate image buffer"));
458 return NULL;
461 gray.red = 190;
462 gray.green = 190;
463 gray.blue = 190;
464 gray.alpha = 255;
465 RClearImage(image, &gray);
468 /* render bevel */
470 switch (relief) {
471 case WREL_ICON:
472 d = RBEV_RAISED3;
473 break;
475 case WREL_RAISED:
476 d = RBEV_RAISED2;
477 break;
479 case WREL_SUNKEN:
480 d = RBEV_SUNKEN;
481 break;
483 case WREL_FLAT:
484 d = 0;
485 break;
487 case WREL_MENUENTRY:
488 d = -WREL_MENUENTRY;
489 break;
491 default:
492 d = 0;
495 if (d > 0) {
496 RBevelImage(image, d);
497 } else if (d < 0) {
498 bevelImage(image, -d);
501 return image;
504 static void bevelImage(RImage * image, int relief)
506 int width = image->width;
507 int height = image->height;
508 RColor color;
510 switch (relief) {
511 case WREL_MENUENTRY:
512 color.red = color.green = color.blue = 80;
513 color.alpha = 0;
514 /**/ ROperateLine(image, RAddOperation, 1, 0, width - 2, 0, &color);
515 /**/ ROperateLine(image, RAddOperation, 0, 0, 0, height - 1, &color);
517 color.red = color.green = color.blue = 40;
518 color.alpha = 0;
519 ROperateLine(image, RSubtractOperation, width - 1, 0, width - 1, height - 1, &color);
521 /**/ ROperateLine(image, RSubtractOperation, 1, height - 2, width - 2, height - 2, &color);
523 color.red = color.green = color.blue = 0;
524 color.alpha = 255;
525 RDrawLine(image, 0, height - 1, width - 1, height - 1, &color);
526 /**/ break;
531 void wDrawBevel(Drawable d, unsigned width, unsigned height, WTexSolid * texture, int relief)
533 GC light, dim, dark;
534 XSegment segs[4];
536 if (relief == WREL_FLAT)
537 return;
539 light = texture->light_gc;
540 dim = texture->dim_gc;
541 dark = texture->dark_gc;
542 switch (relief) {
543 case WREL_FLAT:
544 return;
545 case WREL_MENUENTRY:
546 case WREL_RAISED:
547 case WREL_ICON:
548 segs[0].x1 = 1;
549 segs[0].x2 = width - 2;
550 segs[0].y2 = segs[0].y1 = height - 2;
551 segs[1].x1 = width - 2;
552 segs[1].y1 = 1;
553 segs[1].x2 = width - 2;
554 segs[1].y2 = height - 2;
555 if (wPreferences.new_style == TS_NEXT) {
556 XDrawSegments(dpy, d, dark, segs, 2);
557 } else {
558 XDrawSegments(dpy, d, dim, segs, 2);
560 segs[0].x1 = 0;
561 segs[0].x2 = width - 1;
562 segs[0].y2 = segs[0].y1 = height - 1;
563 segs[1].x1 = segs[1].x2 = width - 1;
564 segs[1].y1 = 0;
565 segs[1].y2 = height - 1;
566 if (wPreferences.new_style == TS_NEXT) {
567 XDrawSegments(dpy, d, light, segs, 2);
568 } else {
569 XDrawSegments(dpy, d, dark, segs, 2);
571 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
572 segs[0].x2 = width - 2;
573 segs[1].x1 = segs[1].y1 = 0;
574 segs[1].x2 = 0;
575 segs[1].y2 = height - 2;
576 if (wPreferences.new_style == TS_NEXT) {
577 XDrawSegments(dpy, d, dark, segs, 2);
578 } else {
579 XDrawSegments(dpy, d, light, segs, 2);
581 if (relief == WREL_ICON) {
582 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
583 segs[0].x2 = width - 2;
584 segs[1].x1 = segs[1].y1 = 1;
585 segs[1].x2 = 1;
586 segs[1].y2 = height - 2;
587 XDrawSegments(dpy, d, light, segs, 2);
589 break;