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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25 #include <X11/Xutil.h>
39 #include "WindowMaker.h"
44 extern WPreferences wPreferences;
46 static void bevelImage(RImage * image, int relief);
48 WTexSolid *wTextureMakeSolid(WScreen * scr, XColor * color)
54 texture = wmalloc(sizeof(WTexture));
56 texture->type = WTEX_SOLID;
59 XAllocColor(dpy, scr->w_colormap, color);
60 texture->normal = *color;
61 if (color->red == 0 && color->blue == 0 && color->green == 0) {
62 texture->light.red = 0xb6da;
63 texture->light.green = 0xb6da;
64 texture->light.blue = 0xb6da;
65 texture->dim.red = 0x6185;
66 texture->dim.green = 0x6185;
67 texture->dim.blue = 0x6185;
73 rgb.red = color->red >> 8;
74 rgb.green = color->green >> 8;
75 rgb.blue = color->blue >> 8;
76 RRGBtoHSV(&rgb, &hsv);
77 RHSVtoRGB(&hsv, &rgb);
80 v = hsv.value * 16 / 10;
81 hsv.value = (v > 255 ? 255 : v);
82 RHSVtoRGB(&hsv, &rgb);
83 texture->light.red = rgb.red << 8;
84 texture->light.green = rgb.green << 8;
85 texture->light.blue = rgb.blue << 8;
87 hsv2.value = hsv2.value / 2;
88 RHSVtoRGB(&hsv2, &rgb);
89 texture->dim.red = rgb.red << 8;
90 texture->dim.green = rgb.green << 8;
91 texture->dim.blue = rgb.blue << 8;
93 texture->dark.red = 0;
94 texture->dark.green = 0;
95 texture->dark.blue = 0;
96 XAllocColor(dpy, scr->w_colormap, &texture->light);
97 XAllocColor(dpy, scr->w_colormap, &texture->dim);
98 XAllocColor(dpy, scr->w_colormap, &texture->dark);
100 gcm = GCForeground | GCBackground | GCGraphicsExposures;
101 gcv.graphics_exposures = False;
103 gcv.background = gcv.foreground = texture->light.pixel;
104 texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
106 gcv.background = gcv.foreground = texture->dim.pixel;
107 texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
109 gcv.background = gcv.foreground = texture->dark.pixel;
110 texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
112 gcv.background = gcv.foreground = color->pixel;
113 texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
118 static int dummyErrorHandler(Display * foo, XErrorEvent * bar)
121 wwarning("your server is buggy. Tell the author if some error related to color occurs");
126 void wTextureDestroy(WScreen * scr, WTexture * texture)
130 unsigned long colors[8];
133 if (texture == NULL) {
134 printf("BUG: trying to free NULL texture\n");
140 * some stupid servers don't like white or black being freed...
142 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
143 switch (texture->any.type) {
145 XFreeGC(dpy, texture->solid.light_gc);
146 XFreeGC(dpy, texture->solid.dark_gc);
147 XFreeGC(dpy, texture->solid.dim_gc);
148 if (CANFREE(texture->solid.light.pixel))
149 colors[count++] = texture->solid.light.pixel;
150 if (CANFREE(texture->solid.dim.pixel))
151 colors[count++] = texture->solid.dim.pixel;
152 if (CANFREE(texture->solid.dark.pixel))
153 colors[count++] = texture->solid.dark.pixel;
157 RReleaseImage(texture->pixmap.pixmap);
160 case WTEX_MHGRADIENT:
161 case WTEX_MVGRADIENT:
162 case WTEX_MDGRADIENT:
163 for (i = 0; texture->mgradient.colors[i] != NULL; i++) {
164 wfree(texture->mgradient.colors[i]);
166 wfree(texture->mgradient.colors);
169 case WTEX_THGRADIENT:
170 case WTEX_TVGRADIENT:
171 case WTEX_TDGRADIENT:
172 RReleaseImage(texture->tgradient.pixmap);
175 #ifdef TEXTURE_PLUGIN
178 if (texture->function.handle) {
179 dlclose(texture->function.handle);
182 for (i = 0; i < texture->function.argc; i++) {
183 wfree(texture->function.argv[i]);
185 wfree(texture->function.argv);
187 #endif /* TEXTURE_PLUGIN */
189 if (CANFREE(texture->any.color.pixel))
190 colors[count++] = texture->any.color.pixel;
192 XErrorHandler oldhandler;
194 /* ignore error from buggy servers that don't know how
195 * to do reference counting for colors. */
197 oldhandler = XSetErrorHandler(dummyErrorHandler);
198 XFreeColors(dpy, scr->w_colormap, colors, count, 0);
200 XSetErrorHandler(oldhandler);
202 XFreeGC(dpy, texture->any.gc);
207 WTexGradient *wTextureMakeGradient(WScreen * scr, int style, RColor * from, RColor * to)
209 WTexGradient *texture;
212 texture = wmalloc(sizeof(WTexture));
213 memset(texture, 0, sizeof(WTexture));
214 texture->type = style;
215 texture->subtype = 0;
217 texture->color1 = *from;
218 texture->color2 = *to;
220 texture->normal.red = (from->red + to->red) << 7;
221 texture->normal.green = (from->green + to->green) << 7;
222 texture->normal.blue = (from->blue + to->blue) << 7;
224 XAllocColor(dpy, scr->w_colormap, &texture->normal);
225 gcv.background = gcv.foreground = texture->normal.pixel;
226 gcv.graphics_exposures = False;
227 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
232 WTexIGradient *wTextureMakeIGradient(WScreen * scr, int thickness1, RColor colors1[2],
233 int thickness2, RColor colors2[2])
235 WTexIGradient *texture;
239 texture = wmalloc(sizeof(WTexture));
240 memset(texture, 0, sizeof(WTexture));
241 texture->type = WTEX_IGRADIENT;
242 for (i = 0; i < 2; i++) {
243 texture->colors1[i] = colors1[i];
244 texture->colors2[i] = colors2[i];
246 texture->thickness1 = thickness1;
247 texture->thickness2 = thickness2;
248 if (thickness1 >= thickness2) {
249 texture->normal.red = (colors1[0].red + colors1[1].red) << 7;
250 texture->normal.green = (colors1[0].green + colors1[1].green) << 7;
251 texture->normal.blue = (colors1[0].blue + colors1[1].blue) << 7;
253 texture->normal.red = (colors2[0].red + colors2[1].red) << 7;
254 texture->normal.green = (colors2[0].green + colors2[1].green) << 7;
255 texture->normal.blue = (colors2[0].blue + colors2[1].blue) << 7;
257 XAllocColor(dpy, scr->w_colormap, &texture->normal);
258 gcv.background = gcv.foreground = texture->normal.pixel;
259 gcv.graphics_exposures = False;
260 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
265 WTexMGradient *wTextureMakeMGradient(WScreen * scr, int style, RColor ** colors)
267 WTexMGradient *texture;
271 texture = wmalloc(sizeof(WTexture));
272 memset(texture, 0, sizeof(WTexture));
273 texture->type = style;
274 texture->subtype = 0;
277 while (colors[i] != NULL)
280 texture->normal.red = (colors[0]->red << 8);
281 texture->normal.green = (colors[0]->green << 8);
282 texture->normal.blue = (colors[0]->blue << 8);
284 texture->colors = colors;
286 XAllocColor(dpy, scr->w_colormap, &texture->normal);
287 gcv.background = gcv.foreground = texture->normal.pixel;
288 gcv.graphics_exposures = False;
289 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
294 WTexPixmap *wTextureMakePixmap(WScreen * scr, int style, char *pixmap_file, XColor * color)
301 file = FindImage(wPreferences.pixmap_path, pixmap_file);
303 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
306 image = RLoadImage(scr->rcontext, file, 0);
308 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
314 texture = wmalloc(sizeof(WTexture));
315 memset(texture, 0, sizeof(WTexture));
316 texture->type = WTEX_PIXMAP;
317 texture->subtype = style;
319 texture->normal = *color;
321 XAllocColor(dpy, scr->w_colormap, &texture->normal);
322 gcv.background = gcv.foreground = texture->normal.pixel;
323 gcv.graphics_exposures = False;
324 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
326 texture->pixmap = image;
331 WTexTGradient *wTextureMakeTGradient(WScreen * scr, int style, RColor * from, RColor * to,
332 char *pixmap_file, int opacity)
334 WTexTGradient *texture;
339 file = FindImage(wPreferences.pixmap_path, pixmap_file);
341 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
344 image = RLoadImage(scr->rcontext, file, 0);
346 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
352 texture = wmalloc(sizeof(WTexture));
353 memset(texture, 0, sizeof(WTexture));
354 texture->type = style;
356 texture->opacity = opacity;
358 texture->color1 = *from;
359 texture->color2 = *to;
361 texture->normal.red = (from->red + to->red) << 7;
362 texture->normal.green = (from->green + to->green) << 7;
363 texture->normal.blue = (from->blue + to->blue) << 7;
365 XAllocColor(dpy, scr->w_colormap, &texture->normal);
366 gcv.background = gcv.foreground = texture->normal.pixel;
367 gcv.graphics_exposures = False;
368 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
370 texture->pixmap = image;
375 #ifdef TEXTURE_PLUGIN
376 WTexFunction *wTextureMakeFunction(WScreen * scr, char *lib, char *func, int argc, char **argv)
378 XColor fallbackColor;
380 WTexFunction *texture;
382 texture = wmalloc(sizeof(WTexture));
383 texture->type = WTEX_FUNCTION;
384 texture->handle = NULL;
386 texture->argc = argc;
387 texture->argv = argv;
389 fallbackColor.red = 0x8000;
390 fallbackColor.green = 0x8000;
391 fallbackColor.blue = 0x8000;
393 gcv.background = gcv.foreground = fallbackColor.pixel;
394 gcv.graphics_exposures = False;
395 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
398 /* open the library */
399 texture->handle = dlopen(lib, RTLD_LAZY);
400 if (!texture->handle) {
401 wwarning(_("library \"%s\" cound not be opened."), lib);
407 /* find the function */
408 texture->render = dlsym(texture->handle, func);
409 if (!texture->render) {
410 wwarning(_("function \"%s\" not found in library \"%s\""), func, lib);
412 dlclose(texture->handle);
417 wwarning(_("function textures not supported on this system, sorry."));
423 #endif /* TEXTURE_PLUGIN */
425 RImage *wTextureRenderImage(WTexture * texture, int width, int height, int relief)
427 RImage *image = NULL;
432 switch (texture->any.type) {
434 image = RCreateImage(width, height, False);
436 color1.red = texture->solid.normal.red >> 8;
437 color1.green = texture->solid.normal.green >> 8;
438 color1.blue = texture->solid.normal.blue >> 8;
441 RClearImage(image, &color1);
445 if (texture->pixmap.subtype == WTP_TILE) {
446 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
447 } else if (texture->pixmap.subtype == WTP_CENTER) {
448 color1.red = texture->pixmap.normal.red >> 8;
449 color1.green = texture->pixmap.normal.green >> 8;
450 color1.blue = texture->pixmap.normal.blue >> 8;
452 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height, &color1);
454 image = RScaleImage(texture->pixmap.pixmap, width, height);
459 image = RRenderInterwovenGradient(width, height,
460 texture->igradient.colors1,
461 texture->igradient.thickness1,
462 texture->igradient.colors2, texture->igradient.thickness2);
466 subtype = RGRD_HORIZONTAL;
467 goto render_gradient;
470 subtype = RGRD_VERTICAL;
471 goto render_gradient;
474 subtype = RGRD_DIAGONAL;
477 image = RRenderGradient(width, height, &texture->gradient.color1,
478 &texture->gradient.color2, subtype);
481 case WTEX_MHGRADIENT:
482 subtype = RGRD_HORIZONTAL;
483 goto render_mgradient;
485 case WTEX_MVGRADIENT:
486 subtype = RGRD_VERTICAL;
487 goto render_mgradient;
489 case WTEX_MDGRADIENT:
490 subtype = RGRD_DIAGONAL;
492 image = RRenderMultiGradient(width, height, &(texture->mgradient.colors[1]), subtype);
495 case WTEX_THGRADIENT:
496 subtype = RGRD_HORIZONTAL;
497 goto render_tgradient;
499 case WTEX_TVGRADIENT:
500 subtype = RGRD_VERTICAL;
501 goto render_tgradient;
503 case WTEX_TDGRADIENT:
504 subtype = RGRD_DIAGONAL;
509 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
513 grad = RRenderGradient(width, height, &texture->tgradient.color1,
514 &texture->tgradient.color2, subtype);
516 RReleaseImage(image);
521 RCombineImagesWithOpaqueness(image, grad, texture->tgradient.opacity);
526 #ifdef TEXTURE_PLUGIN
529 if (texture->function.render) {
530 image = texture->function.render(texture->function.argc, texture->function.argv,
531 width, height, relief);
535 RErrorCode = RERR_INTERNAL;
538 #endif /* TEXTURE_PLUGIN */
541 puts("ERROR in wTextureRenderImage()");
549 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
551 image = RCreateImage(width, height, False);
553 wwarning(_("could not allocate image buffer"));
561 RClearImage(image, &gray);
592 RBevelImage(image, d);
594 bevelImage(image, -d);
600 static void bevelImage(RImage * image, int relief)
602 int width = image->width;
603 int height = image->height;
608 color.red = color.green = color.blue = 80;
610 /**/ ROperateLine(image, RAddOperation, 1, 0, width - 2, 0, &color);
611 /**/ ROperateLine(image, RAddOperation, 0, 0, 0, height - 1, &color);
613 color.red = color.green = color.blue = 40;
615 ROperateLine(image, RSubtractOperation, width - 1, 0, width - 1, height - 1, &color);
617 /**/ ROperateLine(image, RSubtractOperation, 1, height - 2, width - 2, height - 2, &color);
619 color.red = color.green = color.blue = 0;
621 RDrawLine(image, 0, height - 1, width - 1, height - 1, &color);
627 void wDrawBevel(Drawable d, unsigned width, unsigned height, WTexSolid * texture, int relief)
632 if (relief == WREL_FLAT)
635 light = texture->light_gc;
636 dim = texture->dim_gc;
637 dark = texture->dark_gc;
645 segs[0].x2 = width - 2;
646 segs[0].y2 = segs[0].y1 = height - 2;
647 segs[1].x1 = width - 2;
649 segs[1].x2 = width - 2;
650 segs[1].y2 = height - 2;
651 XDrawSegments(dpy, d, dim, segs, 2);
653 segs[0].x2 = width - 1;
654 segs[0].y2 = segs[0].y1 = height - 1;
655 segs[1].x1 = segs[1].x2 = width - 1;
657 segs[1].y2 = height - 1;
658 XDrawSegments(dpy, d, dark, segs, 2);
659 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
660 segs[0].x2 = width - 2;
661 segs[1].x1 = segs[1].y1 = 0;
663 segs[1].y2 = height - 2;
664 XDrawSegments(dpy, d, light, segs, 2);
665 if (relief == WREL_ICON) {
666 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
667 segs[0].x2 = width - 2;
668 segs[1].x1 = segs[1].y1 = 1;
670 segs[1].y2 = height - 2;
671 XDrawSegments(dpy, d, light, segs, 2);
677 segs[0].x2 = width - 1;
678 segs[0].y2 = segs[0].y1 = 0;
679 segs[1].x1 = segs[1].x2 = 0;
681 segs[1].y2 = height - 1;
682 XDrawSegments(dpy, d, dark, segs, 2);
685 segs[0].y1 = segs[0].y2 = height - 1;
686 segs[0].x2 = width - 1;
687 segs[1].x2 = segs[1].x1 = width - 1;
689 segs[1].y2 = height - 1;
690 XDrawSegments(dpy, d, light, segs, 2);