MenuStyle option
[wmaker-crm.git] / src / texture.c
blob2b1da55cc9efc6d296f774176369c5e3fd92d9fe
1 /*
2 * Window Maker window manager
3 *
4 * Copyright (c) 1997, 1998 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 Pixmap renderTexture(WScreen *scr, int width, int height,
48 WTexture *texture, int rel);
51 static void bevelImage(RImage *image, int relief);
55 WTexSolid*
56 wTextureMakeSolid(WScreen *scr, XColor *color)
58 WTexSolid *texture;
59 int gcm;
60 XGCValues gcv;
62 texture = wmalloc(sizeof(WTexture));
64 texture->type = WTEX_SOLID;
65 texture->subtype = 0;
67 XAllocColor(dpy, scr->w_colormap, color);
68 texture->normal = *color;
69 if (color->red==0 && color->blue==0 && color->green == 0) {
70 texture->light.red = 0xb6da;
71 texture->light.green = 0xb6da;
72 texture->light.blue = 0xb6da;
73 texture->dim.red = 0x6185;
74 texture->dim.green = 0x6185;
75 texture->dim.blue = 0x6185;
76 } else {
77 RColor rgb;
78 RHSVColor hsv, hsv2;
79 int v;
81 rgb.red = color->red >> 8;
82 rgb.green = color->green >> 8;
83 rgb.blue = color->blue >> 8;
84 RRGBtoHSV(&rgb, &hsv);
85 RHSVtoRGB(&hsv, &rgb);
86 hsv2 = hsv;
88 v = hsv.value*16/10;
89 hsv.value = (v > 255 ? 255 : v);
90 RHSVtoRGB(&hsv, &rgb);
91 texture->light.red = rgb.red << 8;
92 texture->light.green = rgb.green << 8;
93 texture->light.blue = rgb.blue << 8;
95 hsv2.value = hsv2.value/2;
96 RHSVtoRGB(&hsv2, &rgb);
97 texture->dim.red = rgb.red << 8;
98 texture->dim.green = rgb.green << 8;
99 texture->dim.blue = rgb.blue << 8;
101 texture->dark.red = 0;
102 texture->dark.green = 0;
103 texture->dark.blue = 0;
104 XAllocColor(dpy, scr->w_colormap, &texture->light);
105 XAllocColor(dpy, scr->w_colormap, &texture->dim);
106 XAllocColor(dpy, scr->w_colormap, &texture->dark);
108 gcm = GCForeground|GCBackground|GCGraphicsExposures;
109 gcv.graphics_exposures = False;
111 gcv.background = gcv.foreground = texture->light.pixel;
112 texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
114 gcv.background = gcv.foreground = texture->dim.pixel;
115 texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
117 gcv.background = gcv.foreground = texture->dark.pixel;
118 texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
120 gcv.background = gcv.foreground = color->pixel;
121 texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
123 return texture;
127 static int
128 dummyErrorHandler(Display *foo, XErrorEvent *bar)
130 #ifdef DEBUG
131 wwarning("your server is buggy. Tell the author if some error related to color occurs");
132 #endif
133 return 0;
137 void
138 wTextureDestroy(WScreen *scr, WTexture *texture)
140 int i;
141 int count=0;
142 unsigned long colors[8];
144 #ifdef DEBUG
145 if (texture==NULL) {
146 printf("BUG: trying to free NULL texture\n");
147 return;
149 #endif
152 * some stupid servers don't like white or black being freed...
154 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
155 switch (texture->any.type) {
156 case WTEX_SOLID:
157 XFreeGC(dpy, texture->solid.light_gc);
158 XFreeGC(dpy, texture->solid.dark_gc);
159 XFreeGC(dpy, texture->solid.dim_gc);
160 if (CANFREE(texture->solid.light.pixel))
161 colors[count++] = texture->solid.light.pixel;
162 if (CANFREE(texture->solid.dim.pixel))
163 colors[count++] = texture->solid.dim.pixel;
164 if (CANFREE(texture->solid.dark.pixel))
165 colors[count++] = texture->solid.dark.pixel;
166 break;
168 case WTEX_PIXMAP:
169 RDestroyImage(texture->pixmap.pixmap);
170 break;
172 case WTEX_MHGRADIENT:
173 case WTEX_MVGRADIENT:
174 case WTEX_MDGRADIENT:
175 for (i=0; texture->mgradient.colors[i]!=NULL; i++) {
176 free(texture->mgradient.colors[i]);
178 free(texture->mgradient.colors);
179 break;
181 case WTEX_THGRADIENT:
182 case WTEX_TVGRADIENT:
183 case WTEX_TDGRADIENT:
184 RDestroyImage(texture->tgradient.pixmap);
185 break;
187 #ifdef TEXTURE_PLUGIN
188 case WTEX_FUNCTION:
189 #ifdef HAVE_DLFCN_H
190 if (texture->function.handle) {
191 dlclose(texture->function.handle);
193 #endif
194 for (i = 0; i < texture->function.argc; i++) {
195 free(texture->function.argv[i]);
197 free(texture->function.argv);
198 break;
199 #endif /* TEXTURE_PLUGIN */
201 if (CANFREE(texture->any.color.pixel))
202 colors[count++] = texture->any.color.pixel;
203 if (count > 0) {
204 XErrorHandler oldhandler;
206 /* ignore error from buggy servers that don't know how
207 * to do reference counting for colors. */
208 XSync(dpy,0);
209 oldhandler = XSetErrorHandler(dummyErrorHandler);
210 XFreeColors(dpy, scr->w_colormap, colors, count, 0);
211 XSync(dpy,0);
212 XSetErrorHandler(oldhandler);
214 XFreeGC(dpy, texture->any.gc);
215 free(texture);
216 #undef CANFREE
221 WTexGradient*
222 wTextureMakeGradient(WScreen *scr, int style, RColor *from, RColor *to)
224 WTexGradient *texture;
225 XGCValues gcv;
228 texture = wmalloc(sizeof(WTexture));
229 memset(texture, 0, sizeof(WTexture));
230 texture->type = style;
231 texture->subtype = 0;
233 texture->color1 = *from;
234 texture->color2 = *to;
236 texture->normal.red = (from->red + to->red)<<7;
237 texture->normal.green = (from->green + to->green)<<7;
238 texture->normal.blue = (from->blue + to->blue)<<7;
240 XAllocColor(dpy, scr->w_colormap, &texture->normal);
241 gcv.background = gcv.foreground = texture->normal.pixel;
242 gcv.graphics_exposures = False;
243 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
244 |GCGraphicsExposures, &gcv);
246 return texture;
251 WTexMGradient*
252 wTextureMakeMGradient(WScreen *scr, int style, RColor **colors)
254 WTexMGradient *texture;
255 XGCValues gcv;
256 int i;
259 texture = wmalloc(sizeof(WTexture));
260 memset(texture, 0, sizeof(WTexture));
261 texture->type = style;
262 texture->subtype = 0;
264 i=0;
265 while (colors[i]!=NULL) i++;
266 i--;
267 texture->normal.red = (colors[0]->red<<8);
268 texture->normal.green = (colors[0]->green<<8);
269 texture->normal.blue = (colors[0]->blue<<8);
271 texture->colors = colors;
273 XAllocColor(dpy, scr->w_colormap, &texture->normal);
274 gcv.background = gcv.foreground = texture->normal.pixel;
275 gcv.graphics_exposures = False;
276 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
277 |GCGraphicsExposures, &gcv);
279 return texture;
284 WTexPixmap*
285 wTextureMakePixmap(WScreen *scr, int style, char *pixmap_file, XColor *color)
287 WTexPixmap *texture;
288 XGCValues gcv;
289 RImage *image;
290 char *file;
292 file = FindImage(wPreferences.pixmap_path, pixmap_file);
293 if (!file) {
294 wwarning(_("image file \"%s\" used as texture could not be found."),
295 pixmap_file);
296 return NULL;
298 image = RLoadImage(scr->rcontext, file, 0);
299 if (!image) {
300 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
301 RMessageForError(RErrorCode));
302 free(file);
303 return NULL;
305 free(file);
307 texture = wmalloc(sizeof(WTexture));
308 memset(texture, 0, sizeof(WTexture));
309 texture->type = WTEX_PIXMAP;
310 texture->subtype = style;
312 texture->normal = *color;
314 XAllocColor(dpy, scr->w_colormap, &texture->normal);
315 gcv.background = gcv.foreground = texture->normal.pixel;
316 gcv.graphics_exposures = False;
317 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
318 |GCGraphicsExposures, &gcv);
320 texture->pixmap = image;
322 return texture;
327 WTexTGradient*
328 wTextureMakeTGradient(WScreen *scr, int style, RColor *from, RColor *to,
329 char *pixmap_file, int opacity)
331 WTexTGradient *texture;
332 XGCValues gcv;
333 RImage *image;
334 char *file;
336 file = FindImage(wPreferences.pixmap_path, pixmap_file);
337 if (!file) {
338 wwarning(_("image file \"%s\" used as texture could not be found."),
339 pixmap_file);
340 return NULL;
342 image = RLoadImage(scr->rcontext, file, 0);
343 if (!image) {
344 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
345 RMessageForError(RErrorCode));
346 free(file);
347 return NULL;
349 free(file);
351 texture = wmalloc(sizeof(WTexture));
352 memset(texture, 0, sizeof(WTexture));
353 texture->type = style;
355 texture->opacity = opacity;
357 texture->color1 = *from;
358 texture->color2 = *to;
360 texture->normal.red = (from->red + to->red)<<7;
361 texture->normal.green = (from->green + to->green)<<7;
362 texture->normal.blue = (from->blue + to->blue)<<7;
364 XAllocColor(dpy, scr->w_colormap, &texture->normal);
365 gcv.background = gcv.foreground = texture->normal.pixel;
366 gcv.graphics_exposures = False;
367 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
368 |GCGraphicsExposures, &gcv);
370 texture->pixmap = image;
372 return texture;
376 #ifdef TEXTURE_PLUGIN
377 WTexFunction*
378 wTextureMakeFunction(WScreen *scr, char *lib, char *func, int argc, char **argv)
380 XColor fallbackColor;
381 XGCValues gcv;
382 WTexFunction *texture;
384 texture = wmalloc(sizeof(WTexture));
385 texture->type = WTEX_FUNCTION;
386 texture->handle = NULL;
387 texture->render = 0;
388 texture->argc = argc;
389 texture->argv = argv;
391 fallbackColor.red = 0x8000;
392 fallbackColor.green = 0x8000;
393 fallbackColor.blue = 0x8000;
395 gcv.background = gcv.foreground = fallbackColor.pixel;
396 gcv.graphics_exposures = False;
397 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
398 |GCGraphicsExposures, &gcv);
400 # ifdef HAVE_DLFCN_H
401 /* open the library */
402 texture->handle = dlopen(lib, RTLD_LAZY);
403 if (!texture->handle) {
404 wwarning(_("library \"%s\" cound not be opened."), lib);
405 free(argv);
406 free(texture);
407 return NULL;
410 /* find the function */
411 texture->render = dlsym(texture->handle, func);
412 if (!texture->render) {
413 wwarning(_("function \"%s\" not found in library \"%s\""), func, lib);
414 free(argv);
415 dlclose(texture->handle);
416 free(texture);
417 return NULL;
419 # else
420 wwarning(_("function textures not supported on this system, sorry."));
421 # endif
423 /* success! */
424 return texture;
426 #endif /* TEXTURE_PLUGIN */
429 RImage*
430 wTextureRenderImage(WTexture *texture, int width, int height,
431 int relief)
433 RImage *image;
434 RColor color1;
435 int d;
436 int subtype;
438 switch (texture->any.type) {
439 case WTEX_SOLID:
440 image = RCreateImage(width, height, False);
442 color1.red = texture->solid.normal.red >> 8;
443 color1.green = texture->solid.normal.green >> 8;
444 color1.blue = texture->solid.normal.blue >> 8;
445 color1.alpha = 255;
447 RClearImage(image, &color1);
448 break;
450 case WTEX_PIXMAP:
451 if (texture->pixmap.subtype == WTP_TILE) {
452 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
453 } else if (texture->pixmap.subtype == WTP_CENTER) {
454 color1.red = texture->pixmap.normal.red>>8;
455 color1.green = texture->pixmap.normal.green>>8;
456 color1.blue = texture->pixmap.normal.blue>>8;
457 color1.alpha = 255;
458 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height,
459 &color1);
460 } else {
461 image = RScaleImage(texture->pixmap.pixmap, width, height);
463 break;
465 case WTEX_HGRADIENT:
466 subtype = RGRD_HORIZONTAL;
467 goto render_gradient;
469 case WTEX_VGRADIENT:
470 subtype = RGRD_VERTICAL;
471 goto render_gradient;
473 case WTEX_DGRADIENT:
474 subtype = RGRD_DIAGONAL;
475 render_gradient:
477 image = RRenderGradient(width, height, &texture->gradient.color1,
478 &texture->gradient.color2, subtype);
479 break;
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;
491 render_mgradient:
492 image = RRenderMultiGradient(width, height,
493 &(texture->mgradient.colors[1]),
494 subtype);
495 break;
497 case WTEX_THGRADIENT:
498 subtype = RGRD_HORIZONTAL;
499 goto render_tgradient;
501 case WTEX_TVGRADIENT:
502 subtype = RGRD_VERTICAL;
503 goto render_tgradient;
505 case WTEX_TDGRADIENT:
506 subtype = RGRD_DIAGONAL;
507 render_tgradient:
509 RImage *grad;
511 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
512 if (!image)
513 break;
515 grad = RRenderGradient(width, height, &texture->tgradient.color1,
516 &texture->tgradient.color2, subtype);
517 if (!grad) {
518 RDestroyImage(image);
519 image = NULL;
520 break;
523 RCombineImagesWithOpaqueness(image, grad,
524 texture->tgradient.opacity);
525 RDestroyImage(grad);
527 break;
529 #ifdef TEXTURE_PLUGIN
530 case WTEX_FUNCTION:
531 #ifdef HAVE_DLFCN_H
532 if (texture->function.render) {
533 image = texture->function.render (
534 texture->function.argc, texture->function.argv,
535 width, height, relief);
537 #endif
538 if (!image) {
539 RErrorCode = RERR_INTERNAL;
541 break;
542 #endif /* TEXTURE_PLUGIN */
544 default:
545 puts("ERROR in wTextureRenderImage()");
546 image = NULL;
547 break;
550 if (!image) {
551 RColor gray;
553 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
555 image = RCreateImage(width, height, False);
557 gray.red = 190;
558 gray.green = 190;
559 gray.blue = 190;
560 gray.alpha = 255;
561 RClearImage(image, &gray);
565 /* render bevel */
567 switch (relief) {
568 case WREL_ICON:
569 d = RBEV_RAISED3;
570 break;
572 case WREL_RAISED:
573 d = RBEV_RAISED2;
574 break;
576 case WREL_SUNKEN:
577 d = RBEV_SUNKEN;
578 break;
580 case WREL_FLAT:
581 d = 0;
582 break;
584 case WREL_MENUENTRY:
585 d = -WREL_MENUENTRY;
586 break;
588 default:
589 d = 0;
592 if (d > 0) {
593 RBevelImage(image, d);
594 } else if (d < 0) {
595 bevelImage(image, -d);
598 return image;
603 static void
604 bevelImage(RImage *image, int relief)
606 int width = image->width;
607 int height = image->height;
608 RColor color;
610 switch (relief) {
611 case WREL_MENUENTRY:
612 color.red = color.green = color.blue = 80;
613 color.alpha = 0;
614 /**/
615 ROperateLine(image, RAddOperation, 1, 0, width-2, 0, &color);
616 /**/
618 ROperateLine(image, RAddOperation, 0, 0, 0, height-1, &color);
620 color.red = color.green = color.blue = 40;
621 color.alpha = 0;
622 ROperateLine(image, RSubtractOperation, width-1, 0, width-1,
623 height-1, &color);
625 /**/
626 ROperateLine(image, RSubtractOperation, 1, height-2, width-2,
627 height-2, &color);
629 color.red = color.green = color.blue = 0;
630 color.alpha = 255;
631 RDrawLine(image, 0, height-1, width-1, height-1, &color);
632 /**/
633 break;
640 void
641 wDrawBevel(Drawable d, unsigned width, unsigned height,
642 WTexSolid *texture, int relief)
644 GC light, dim, dark;
645 XSegment segs[4];
647 if (relief==WREL_FLAT) return;
649 light = texture->light_gc;
650 dim = texture->dim_gc;
651 dark = texture->dark_gc;
652 switch (relief) {
653 case WREL_FLAT:
654 return;
655 case WREL_MENUENTRY:
656 case WREL_RAISED:
657 case WREL_ICON:
658 segs[0].x1 = 1;
659 segs[0].x2 = width - 2;
660 segs[0].y2 = segs[0].y1 = height - 2;
661 segs[1].x1 = width - 2;
662 segs[1].y1 = 1;
663 segs[1].x2 = width - 2;
664 segs[1].y2 = height - 2;
665 XDrawSegments(dpy, d, dim, segs, 2);
666 segs[0].x1 = 0;
667 segs[0].x2 = width - 1;
668 segs[0].y2 = segs[0].y1 = height - 1;
669 segs[1].x1 = segs[1].x2 = width - 1;
670 segs[1].y1 = 0;
671 segs[1].y2 = height - 1;
672 XDrawSegments(dpy, d, dark, segs, 2);
673 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
674 segs[0].x2 = width - 2;
675 segs[1].x1 = segs[1].y1 = 0;
676 segs[1].x2 = 0;
677 segs[1].y2 = height - 2;
678 XDrawSegments(dpy, d, light, segs, 2);
679 if (relief==WREL_ICON) {
680 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
681 segs[0].x2 = width - 2;
682 segs[1].x1 = segs[1].y1 = 1;
683 segs[1].x2 = 1;
684 segs[1].y2 = height - 2;
685 XDrawSegments(dpy, d, light, segs, 2);
687 break;
688 #ifdef unused
689 case WREL_SUNKEN:
690 segs[0].x1 = 0;
691 segs[0].x2 = width - 1;
692 segs[0].y2 = segs[0].y1 = 0;
693 segs[1].x1 = segs[1].x2 = 0;
694 segs[1].y1 = 0;
695 segs[1].y2 = height - 1;
696 XDrawSegments(dpy, d, dark, segs, 2);
698 segs[0].x1 = 0;
699 segs[0].y1 = segs[0].y2 = height - 1;
700 segs[0].x2 = width - 1;
701 segs[1].x2 = segs[1].x1 = width - 1;
702 segs[1].y1 = 1;
703 segs[1].y2 = height - 1;
704 XDrawSegments(dpy, d, light, segs, 2);
705 break;
706 #endif