- Fixed crashing bug in menu.c
[wmaker-crm.git] / src / texture.c
blob670d1146be4a0a6fea94cf033e7566409792e804
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
5 *
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,
19 * USA.
22 #include "wconfig.h"
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
27 #ifdef TEXTURE_PLUGIN
28 # ifdef HAVE_DLFCN_H
29 # include <dlfcn.h>
30 # endif
31 #endif
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
37 #include <wraster.h>
39 #include "WindowMaker.h"
40 #include "wcore.h"
41 #include "texture.h"
42 #include "funcs.h"
44 extern WPreferences wPreferences;
47 static void bevelImage(RImage *image, int relief);
51 WTexSolid*
52 wTextureMakeSolid(WScreen *scr, XColor *color)
54 WTexSolid *texture;
55 int gcm;
56 XGCValues gcv;
58 texture = wmalloc(sizeof(WTexture));
60 texture->type = WTEX_SOLID;
61 texture->subtype = 0;
63 XAllocColor(dpy, scr->w_colormap, color);
64 texture->normal = *color;
65 if (color->red==0 && color->blue==0 && color->green == 0) {
66 texture->light.red = 0xb6da;
67 texture->light.green = 0xb6da;
68 texture->light.blue = 0xb6da;
69 texture->dim.red = 0x6185;
70 texture->dim.green = 0x6185;
71 texture->dim.blue = 0x6185;
72 } else {
73 RColor rgb;
74 RHSVColor hsv, hsv2;
75 int v;
77 rgb.red = color->red >> 8;
78 rgb.green = color->green >> 8;
79 rgb.blue = color->blue >> 8;
80 RRGBtoHSV(&rgb, &hsv);
81 RHSVtoRGB(&hsv, &rgb);
82 hsv2 = hsv;
84 v = hsv.value*16/10;
85 hsv.value = (v > 255 ? 255 : v);
86 RHSVtoRGB(&hsv, &rgb);
87 texture->light.red = rgb.red << 8;
88 texture->light.green = rgb.green << 8;
89 texture->light.blue = rgb.blue << 8;
91 hsv2.value = hsv2.value/2;
92 RHSVtoRGB(&hsv2, &rgb);
93 texture->dim.red = rgb.red << 8;
94 texture->dim.green = rgb.green << 8;
95 texture->dim.blue = rgb.blue << 8;
97 texture->dark.red = 0;
98 texture->dark.green = 0;
99 texture->dark.blue = 0;
100 XAllocColor(dpy, scr->w_colormap, &texture->light);
101 XAllocColor(dpy, scr->w_colormap, &texture->dim);
102 XAllocColor(dpy, scr->w_colormap, &texture->dark);
104 gcm = GCForeground|GCBackground|GCGraphicsExposures;
105 gcv.graphics_exposures = False;
107 gcv.background = gcv.foreground = texture->light.pixel;
108 texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
110 gcv.background = gcv.foreground = texture->dim.pixel;
111 texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
113 gcv.background = gcv.foreground = texture->dark.pixel;
114 texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
116 gcv.background = gcv.foreground = color->pixel;
117 texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
119 return texture;
123 static int
124 dummyErrorHandler(Display *foo, XErrorEvent *bar)
126 #ifdef DEBUG
127 wwarning("your server is buggy. Tell the author if some error related to color occurs");
128 #endif
129 return 0;
133 void
134 wTextureDestroy(WScreen *scr, WTexture *texture)
136 int i;
137 int count=0;
138 unsigned long colors[8];
140 #ifdef DEBUG
141 if (texture==NULL) {
142 printf("BUG: trying to free NULL texture\n");
143 return;
145 #endif
148 * some stupid servers don't like white or black being freed...
150 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
151 switch (texture->any.type) {
152 case WTEX_SOLID:
153 XFreeGC(dpy, texture->solid.light_gc);
154 XFreeGC(dpy, texture->solid.dark_gc);
155 XFreeGC(dpy, texture->solid.dim_gc);
156 if (CANFREE(texture->solid.light.pixel))
157 colors[count++] = texture->solid.light.pixel;
158 if (CANFREE(texture->solid.dim.pixel))
159 colors[count++] = texture->solid.dim.pixel;
160 if (CANFREE(texture->solid.dark.pixel))
161 colors[count++] = texture->solid.dark.pixel;
162 break;
164 case WTEX_PIXMAP:
165 RReleaseImage(texture->pixmap.pixmap);
166 break;
168 case WTEX_MHGRADIENT:
169 case WTEX_MVGRADIENT:
170 case WTEX_MDGRADIENT:
171 for (i=0; texture->mgradient.colors[i]!=NULL; i++) {
172 wfree(texture->mgradient.colors[i]);
174 wfree(texture->mgradient.colors);
175 break;
177 case WTEX_THGRADIENT:
178 case WTEX_TVGRADIENT:
179 case WTEX_TDGRADIENT:
180 RReleaseImage(texture->tgradient.pixmap);
181 break;
183 #ifdef TEXTURE_PLUGIN
184 case WTEX_FUNCTION:
185 #ifdef HAVE_DLFCN_H
186 if (texture->function.handle) {
187 dlclose(texture->function.handle);
189 #endif
190 for (i = 0; i < texture->function.argc; i++) {
191 wfree(texture->function.argv[i]);
193 wfree(texture->function.argv);
194 break;
195 #endif /* TEXTURE_PLUGIN */
197 if (CANFREE(texture->any.color.pixel))
198 colors[count++] = texture->any.color.pixel;
199 if (count > 0) {
200 XErrorHandler oldhandler;
202 /* ignore error from buggy servers that don't know how
203 * to do reference counting for colors. */
204 XSync(dpy,0);
205 oldhandler = XSetErrorHandler(dummyErrorHandler);
206 XFreeColors(dpy, scr->w_colormap, colors, count, 0);
207 XSync(dpy,0);
208 XSetErrorHandler(oldhandler);
210 XFreeGC(dpy, texture->any.gc);
211 wfree(texture);
212 #undef CANFREE
217 WTexGradient*
218 wTextureMakeGradient(WScreen *scr, int style, RColor *from, RColor *to)
220 WTexGradient *texture;
221 XGCValues gcv;
224 texture = wmalloc(sizeof(WTexture));
225 memset(texture, 0, sizeof(WTexture));
226 texture->type = style;
227 texture->subtype = 0;
229 texture->color1 = *from;
230 texture->color2 = *to;
232 texture->normal.red = (from->red + to->red)<<7;
233 texture->normal.green = (from->green + to->green)<<7;
234 texture->normal.blue = (from->blue + to->blue)<<7;
236 XAllocColor(dpy, scr->w_colormap, &texture->normal);
237 gcv.background = gcv.foreground = texture->normal.pixel;
238 gcv.graphics_exposures = False;
239 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
240 |GCGraphicsExposures, &gcv);
242 return texture;
248 WTexIGradient*
249 wTextureMakeIGradient(WScreen *scr, int thickness1, RColor colors1[2],
250 int thickness2, RColor colors2[2])
252 WTexIGradient *texture;
253 XGCValues gcv;
254 int i;
257 texture = wmalloc(sizeof(WTexture));
258 memset(texture, 0, sizeof(WTexture));
259 texture->type = WTEX_IGRADIENT;
260 for (i = 0; i < 2; i++) {
261 texture->colors1[i] = colors1[i];
262 texture->colors2[i] = colors2[i];
264 texture->thickness1 = thickness1;
265 texture->thickness2 = thickness2;
266 if (thickness1 >= thickness2) {
267 texture->normal.red = (colors1[0].red + colors1[1].red)<<7;
268 texture->normal.green = (colors1[0].green + colors1[1].green)<<7;
269 texture->normal.blue = (colors1[0].blue + colors1[1].blue)<<7;
270 } else {
271 texture->normal.red = (colors2[0].red + colors2[1].red)<<7;
272 texture->normal.green = (colors2[0].green + colors2[1].green)<<7;
273 texture->normal.blue = (colors2[0].blue + colors2[1].blue)<<7;
275 XAllocColor(dpy, scr->w_colormap, &texture->normal);
276 gcv.background = gcv.foreground = texture->normal.pixel;
277 gcv.graphics_exposures = False;
278 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
279 |GCGraphicsExposures, &gcv);
281 return texture;
286 WTexMGradient*
287 wTextureMakeMGradient(WScreen *scr, int style, RColor **colors)
289 WTexMGradient *texture;
290 XGCValues gcv;
291 int i;
294 texture = wmalloc(sizeof(WTexture));
295 memset(texture, 0, sizeof(WTexture));
296 texture->type = style;
297 texture->subtype = 0;
299 i=0;
300 while (colors[i]!=NULL) i++;
301 i--;
302 texture->normal.red = (colors[0]->red<<8);
303 texture->normal.green = (colors[0]->green<<8);
304 texture->normal.blue = (colors[0]->blue<<8);
306 texture->colors = colors;
308 XAllocColor(dpy, scr->w_colormap, &texture->normal);
309 gcv.background = gcv.foreground = texture->normal.pixel;
310 gcv.graphics_exposures = False;
311 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
312 |GCGraphicsExposures, &gcv);
314 return texture;
319 WTexPixmap*
320 wTextureMakePixmap(WScreen *scr, int style, char *pixmap_file, XColor *color)
322 WTexPixmap *texture;
323 XGCValues gcv;
324 RImage *image;
325 char *file;
327 file = FindImage(wPreferences.pixmap_path, pixmap_file);
328 if (!file) {
329 wwarning(_("image file \"%s\" used as texture could not be found."),
330 pixmap_file);
331 return NULL;
333 image = RLoadImage(scr->rcontext, file, 0);
334 if (!image) {
335 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
336 RMessageForError(RErrorCode));
337 wfree(file);
338 return NULL;
340 wfree(file);
342 texture = wmalloc(sizeof(WTexture));
343 memset(texture, 0, sizeof(WTexture));
344 texture->type = WTEX_PIXMAP;
345 texture->subtype = style;
347 texture->normal = *color;
349 XAllocColor(dpy, scr->w_colormap, &texture->normal);
350 gcv.background = gcv.foreground = texture->normal.pixel;
351 gcv.graphics_exposures = False;
352 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
353 |GCGraphicsExposures, &gcv);
355 texture->pixmap = image;
357 return texture;
360 WTexTGradient*
361 wTextureMakeTGradient(WScreen *scr, int style, RColor *from, RColor *to,
362 char *pixmap_file, int opacity)
364 WTexTGradient *texture;
365 XGCValues gcv;
366 RImage *image;
367 char *file;
369 file = FindImage(wPreferences.pixmap_path, pixmap_file);
370 if (!file) {
371 wwarning(_("image file \"%s\" used as texture could not be found."),
372 pixmap_file);
373 return NULL;
375 image = RLoadImage(scr->rcontext, file, 0);
376 if (!image) {
377 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
378 RMessageForError(RErrorCode));
379 wfree(file);
380 return NULL;
382 wfree(file);
384 texture = wmalloc(sizeof(WTexture));
385 memset(texture, 0, sizeof(WTexture));
386 texture->type = style;
388 texture->opacity = opacity;
390 texture->color1 = *from;
391 texture->color2 = *to;
393 texture->normal.red = (from->red + to->red)<<7;
394 texture->normal.green = (from->green + to->green)<<7;
395 texture->normal.blue = (from->blue + to->blue)<<7;
397 XAllocColor(dpy, scr->w_colormap, &texture->normal);
398 gcv.background = gcv.foreground = texture->normal.pixel;
399 gcv.graphics_exposures = False;
400 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
401 |GCGraphicsExposures, &gcv);
403 texture->pixmap = image;
405 return texture;
409 #ifdef TEXTURE_PLUGIN
410 WTexFunction*
411 wTextureMakeFunction(WScreen *scr, char *lib, char *func, int argc, char **argv)
413 XColor fallbackColor;
414 XGCValues gcv;
415 WTexFunction *texture;
417 texture = wmalloc(sizeof(WTexture));
418 texture->type = WTEX_FUNCTION;
419 texture->handle = NULL;
420 texture->render = 0;
421 texture->argc = argc;
422 texture->argv = argv;
424 fallbackColor.red = 0x8000;
425 fallbackColor.green = 0x8000;
426 fallbackColor.blue = 0x8000;
428 gcv.background = gcv.foreground = fallbackColor.pixel;
429 gcv.graphics_exposures = False;
430 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
431 |GCGraphicsExposures, &gcv);
433 # ifdef HAVE_DLFCN_H
434 /* open the library */
435 texture->handle = dlopen(lib, RTLD_LAZY);
436 if (!texture->handle) {
437 wwarning(_("library \"%s\" cound not be opened."), lib);
438 wfree(argv);
439 wfree(texture);
440 return NULL;
443 /* find the function */
444 texture->render = dlsym(texture->handle, func);
445 if (!texture->render) {
446 wwarning(_("function \"%s\" not found in library \"%s\""), func, lib);
447 wfree(argv);
448 dlclose(texture->handle);
449 wfree(texture);
450 return NULL;
452 # else
453 wwarning(_("function textures not supported on this system, sorry."));
454 # endif
456 /* success! */
457 return texture;
459 #endif /* TEXTURE_PLUGIN */
462 RImage*
463 wTextureRenderImage(WTexture *texture, int width, int height,
464 int relief)
466 RImage *image = NULL;
467 RColor color1;
468 int d;
469 int subtype;
471 switch (texture->any.type) {
472 case WTEX_SOLID:
473 image = RCreateImage(width, height, False);
475 color1.red = texture->solid.normal.red >> 8;
476 color1.green = texture->solid.normal.green >> 8;
477 color1.blue = texture->solid.normal.blue >> 8;
478 color1.alpha = 255;
480 RClearImage(image, &color1);
481 break;
483 case WTEX_PIXMAP:
484 if (texture->pixmap.subtype == WTP_TILE) {
485 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
486 } else if (texture->pixmap.subtype == WTP_CENTER) {
487 color1.red = texture->pixmap.normal.red>>8;
488 color1.green = texture->pixmap.normal.green>>8;
489 color1.blue = texture->pixmap.normal.blue>>8;
490 color1.alpha = 255;
491 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height,
492 &color1);
493 } else {
494 image = RScaleImage(texture->pixmap.pixmap, width, height);
496 break;
498 case WTEX_IGRADIENT:
499 image = RRenderInterwovenGradient(width, height,
500 texture->igradient.colors1,
501 texture->igradient.thickness1,
502 texture->igradient.colors2,
503 texture->igradient.thickness2);
504 break;
506 case WTEX_HGRADIENT:
507 subtype = RGRD_HORIZONTAL;
508 goto render_gradient;
510 case WTEX_VGRADIENT:
511 subtype = RGRD_VERTICAL;
512 goto render_gradient;
514 case WTEX_DGRADIENT:
515 subtype = RGRD_DIAGONAL;
516 render_gradient:
518 image = RRenderGradient(width, height, &texture->gradient.color1,
519 &texture->gradient.color2, subtype);
520 break;
522 case WTEX_MHGRADIENT:
523 subtype = RGRD_HORIZONTAL;
524 goto render_mgradient;
526 case WTEX_MVGRADIENT:
527 subtype = RGRD_VERTICAL;
528 goto render_mgradient;
530 case WTEX_MDGRADIENT:
531 subtype = RGRD_DIAGONAL;
532 render_mgradient:
533 image = RRenderMultiGradient(width, height,
534 &(texture->mgradient.colors[1]),
535 subtype);
536 break;
538 case WTEX_THGRADIENT:
539 subtype = RGRD_HORIZONTAL;
540 goto render_tgradient;
542 case WTEX_TVGRADIENT:
543 subtype = RGRD_VERTICAL;
544 goto render_tgradient;
546 case WTEX_TDGRADIENT:
547 subtype = RGRD_DIAGONAL;
548 render_tgradient:
550 RImage *grad;
552 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
553 if (!image)
554 break;
556 grad = RRenderGradient(width, height, &texture->tgradient.color1,
557 &texture->tgradient.color2, subtype);
558 if (!grad) {
559 RReleaseImage(image);
560 image = NULL;
561 break;
564 RCombineImagesWithOpaqueness(image, grad,
565 texture->tgradient.opacity);
566 RReleaseImage(grad);
568 break;
570 #ifdef TEXTURE_PLUGIN
571 case WTEX_FUNCTION:
572 #ifdef HAVE_DLFCN_H
573 if (texture->function.render) {
574 image = texture->function.render (
575 texture->function.argc, texture->function.argv,
576 width, height, relief);
578 #endif
579 if (!image) {
580 RErrorCode = RERR_INTERNAL;
582 break;
583 #endif /* TEXTURE_PLUGIN */
585 default:
586 puts("ERROR in wTextureRenderImage()");
587 image = NULL;
588 break;
591 if (!image) {
592 RColor gray;
594 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
596 image = RCreateImage(width, height, False);
597 if (image == NULL) {
598 wwarning(_("could not allocate image buffer"));
599 return NULL;
602 gray.red = 190;
603 gray.green = 190;
604 gray.blue = 190;
605 gray.alpha = 255;
606 RClearImage(image, &gray);
610 /* render bevel */
612 switch (relief) {
613 case WREL_ICON:
614 d = RBEV_RAISED3;
615 break;
617 case WREL_RAISED:
618 d = RBEV_RAISED2;
619 break;
621 case WREL_SUNKEN:
622 d = RBEV_SUNKEN;
623 break;
625 case WREL_FLAT:
626 d = 0;
627 break;
629 case WREL_MENUENTRY:
630 d = -WREL_MENUENTRY;
631 break;
633 default:
634 d = 0;
637 if (d > 0) {
638 RBevelImage(image, d);
639 } else if (d < 0) {
640 bevelImage(image, -d);
643 return image;
648 static void
649 bevelImage(RImage *image, int relief)
651 int width = image->width;
652 int height = image->height;
653 RColor color;
655 switch (relief) {
656 case WREL_MENUENTRY:
657 color.red = color.green = color.blue = 80;
658 color.alpha = 0;
659 /**/
660 ROperateLine(image, RAddOperation, 1, 0, width-2, 0, &color);
661 /**/
663 ROperateLine(image, RAddOperation, 0, 0, 0, height-1, &color);
665 color.red = color.green = color.blue = 40;
666 color.alpha = 0;
667 ROperateLine(image, RSubtractOperation, width-1, 0, width-1,
668 height-1, &color);
670 /**/
671 ROperateLine(image, RSubtractOperation, 1, height-2, width-2,
672 height-2, &color);
674 color.red = color.green = color.blue = 0;
675 color.alpha = 255;
676 RDrawLine(image, 0, height-1, width-1, height-1, &color);
677 /**/
678 break;
685 void
686 wDrawBevel(Drawable d, unsigned width, unsigned height,
687 WTexSolid *texture, int relief)
689 GC light, dim, dark;
690 XSegment segs[4];
692 if (relief==WREL_FLAT) return;
694 light = texture->light_gc;
695 dim = texture->dim_gc;
696 dark = texture->dark_gc;
697 switch (relief) {
698 case WREL_FLAT:
699 return;
700 case WREL_MENUENTRY:
701 case WREL_RAISED:
702 case WREL_ICON:
703 segs[0].x1 = 1;
704 segs[0].x2 = width - 2;
705 segs[0].y2 = segs[0].y1 = height - 2;
706 segs[1].x1 = width - 2;
707 segs[1].y1 = 1;
708 segs[1].x2 = width - 2;
709 segs[1].y2 = height - 2;
710 XDrawSegments(dpy, d, dim, segs, 2);
711 segs[0].x1 = 0;
712 segs[0].x2 = width - 1;
713 segs[0].y2 = segs[0].y1 = height - 1;
714 segs[1].x1 = segs[1].x2 = width - 1;
715 segs[1].y1 = 0;
716 segs[1].y2 = height - 1;
717 XDrawSegments(dpy, d, dark, segs, 2);
718 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
719 segs[0].x2 = width - 2;
720 segs[1].x1 = segs[1].y1 = 0;
721 segs[1].x2 = 0;
722 segs[1].y2 = height - 2;
723 XDrawSegments(dpy, d, light, segs, 2);
724 if (relief==WREL_ICON) {
725 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
726 segs[0].x2 = width - 2;
727 segs[1].x1 = segs[1].y1 = 1;
728 segs[1].x2 = 1;
729 segs[1].y2 = height - 2;
730 XDrawSegments(dpy, d, light, segs, 2);
732 break;
733 #ifdef unused
734 case WREL_SUNKEN:
735 segs[0].x1 = 0;
736 segs[0].x2 = width - 1;
737 segs[0].y2 = segs[0].y1 = 0;
738 segs[1].x1 = segs[1].x2 = 0;
739 segs[1].y1 = 0;
740 segs[1].y2 = height - 1;
741 XDrawSegments(dpy, d, dark, segs, 2);
743 segs[0].x1 = 0;
744 segs[0].y1 = segs[0].y2 = height - 1;
745 segs[0].x2 = width - 1;
746 segs[1].x2 = segs[1].x1 = width - 1;
747 segs[1].y1 = 1;
748 segs[1].y2 = height - 1;
749 XDrawSegments(dpy, d, light, segs, 2);
750 break;
751 #endif