Fix for stupid Solaris (maybe other Sysv systems too).
[wmaker-crm.git] / src / texture.c
bloba4545cfc4215389c97478da34f6561b079c7e4a2
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 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 RDestroyImage(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 free(texture->mgradient.colors[i]);
174 free(texture->mgradient.colors);
175 break;
177 case WTEX_THGRADIENT:
178 case WTEX_TVGRADIENT:
179 case WTEX_TDGRADIENT:
180 RDestroyImage(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 free(texture->function.argv[i]);
193 free(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 free(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;
247 WTexMGradient*
248 wTextureMakeMGradient(WScreen *scr, int style, RColor **colors)
250 WTexMGradient *texture;
251 XGCValues gcv;
252 int i;
255 texture = wmalloc(sizeof(WTexture));
256 memset(texture, 0, sizeof(WTexture));
257 texture->type = style;
258 texture->subtype = 0;
260 i=0;
261 while (colors[i]!=NULL) i++;
262 i--;
263 texture->normal.red = (colors[0]->red<<8);
264 texture->normal.green = (colors[0]->green<<8);
265 texture->normal.blue = (colors[0]->blue<<8);
267 texture->colors = colors;
269 XAllocColor(dpy, scr->w_colormap, &texture->normal);
270 gcv.background = gcv.foreground = texture->normal.pixel;
271 gcv.graphics_exposures = False;
272 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
273 |GCGraphicsExposures, &gcv);
275 return texture;
280 WTexPixmap*
281 wTextureMakePixmap(WScreen *scr, int style, char *pixmap_file, XColor *color)
283 WTexPixmap *texture;
284 XGCValues gcv;
285 RImage *image;
286 char *file;
288 file = FindImage(wPreferences.pixmap_path, pixmap_file);
289 if (!file) {
290 wwarning(_("image file \"%s\" used as texture could not be found."),
291 pixmap_file);
292 return NULL;
294 image = RLoadImage(scr->rcontext, file, 0);
295 if (!image) {
296 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
297 RMessageForError(RErrorCode));
298 free(file);
299 return NULL;
301 free(file);
303 texture = wmalloc(sizeof(WTexture));
304 memset(texture, 0, sizeof(WTexture));
305 texture->type = WTEX_PIXMAP;
306 texture->subtype = style;
308 texture->normal = *color;
310 XAllocColor(dpy, scr->w_colormap, &texture->normal);
311 gcv.background = gcv.foreground = texture->normal.pixel;
312 gcv.graphics_exposures = False;
313 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
314 |GCGraphicsExposures, &gcv);
316 texture->pixmap = image;
318 return texture;
323 WTexTGradient*
324 wTextureMakeTGradient(WScreen *scr, int style, RColor *from, RColor *to,
325 char *pixmap_file, int opacity)
327 WTexTGradient *texture;
328 XGCValues gcv;
329 RImage *image;
330 char *file;
332 file = FindImage(wPreferences.pixmap_path, pixmap_file);
333 if (!file) {
334 wwarning(_("image file \"%s\" used as texture could not be found."),
335 pixmap_file);
336 return NULL;
338 image = RLoadImage(scr->rcontext, file, 0);
339 if (!image) {
340 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
341 RMessageForError(RErrorCode));
342 free(file);
343 return NULL;
345 free(file);
347 texture = wmalloc(sizeof(WTexture));
348 memset(texture, 0, sizeof(WTexture));
349 texture->type = style;
351 texture->opacity = opacity;
353 texture->color1 = *from;
354 texture->color2 = *to;
356 texture->normal.red = (from->red + to->red)<<7;
357 texture->normal.green = (from->green + to->green)<<7;
358 texture->normal.blue = (from->blue + to->blue)<<7;
360 XAllocColor(dpy, scr->w_colormap, &texture->normal);
361 gcv.background = gcv.foreground = texture->normal.pixel;
362 gcv.graphics_exposures = False;
363 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
364 |GCGraphicsExposures, &gcv);
366 texture->pixmap = image;
368 return texture;
372 #ifdef TEXTURE_PLUGIN
373 WTexFunction*
374 wTextureMakeFunction(WScreen *scr, char *lib, char *func, int argc, char **argv)
376 XColor fallbackColor;
377 XGCValues gcv;
378 WTexFunction *texture;
380 texture = wmalloc(sizeof(WTexture));
381 texture->type = WTEX_FUNCTION;
382 texture->handle = NULL;
383 texture->render = 0;
384 texture->argc = argc;
385 texture->argv = argv;
387 fallbackColor.red = 0x8000;
388 fallbackColor.green = 0x8000;
389 fallbackColor.blue = 0x8000;
391 gcv.background = gcv.foreground = fallbackColor.pixel;
392 gcv.graphics_exposures = False;
393 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
394 |GCGraphicsExposures, &gcv);
396 # ifdef HAVE_DLFCN_H
397 /* open the library */
398 texture->handle = dlopen(lib, RTLD_LAZY);
399 if (!texture->handle) {
400 wwarning(_("library \"%s\" cound not be opened."), lib);
401 free(argv);
402 free(texture);
403 return NULL;
406 /* find the function */
407 texture->render = dlsym(texture->handle, func);
408 if (!texture->render) {
409 wwarning(_("function \"%s\" not found in library \"%s\""), func, lib);
410 free(argv);
411 dlclose(texture->handle);
412 free(texture);
413 return NULL;
415 # else
416 wwarning(_("function textures not supported on this system, sorry."));
417 # endif
419 /* success! */
420 return texture;
422 #endif /* TEXTURE_PLUGIN */
425 RImage*
426 wTextureRenderImage(WTexture *texture, int width, int height,
427 int relief)
429 RImage *image = NULL;
430 RColor color1;
431 int d;
432 int subtype;
434 switch (texture->any.type) {
435 case WTEX_SOLID:
436 image = RCreateImage(width, height, False);
438 color1.red = texture->solid.normal.red >> 8;
439 color1.green = texture->solid.normal.green >> 8;
440 color1.blue = texture->solid.normal.blue >> 8;
441 color1.alpha = 255;
443 RClearImage(image, &color1);
444 break;
446 case WTEX_PIXMAP:
447 if (texture->pixmap.subtype == WTP_TILE) {
448 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
449 } else if (texture->pixmap.subtype == WTP_CENTER) {
450 color1.red = texture->pixmap.normal.red>>8;
451 color1.green = texture->pixmap.normal.green>>8;
452 color1.blue = texture->pixmap.normal.blue>>8;
453 color1.alpha = 255;
454 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height,
455 &color1);
456 } else {
457 image = RScaleImage(texture->pixmap.pixmap, width, height);
459 break;
461 case WTEX_HGRADIENT:
462 subtype = RGRD_HORIZONTAL;
463 goto render_gradient;
465 case WTEX_VGRADIENT:
466 subtype = RGRD_VERTICAL;
467 goto render_gradient;
469 case WTEX_DGRADIENT:
470 subtype = RGRD_DIAGONAL;
471 render_gradient:
473 image = RRenderGradient(width, height, &texture->gradient.color1,
474 &texture->gradient.color2, subtype);
475 break;
477 case WTEX_MHGRADIENT:
478 subtype = RGRD_HORIZONTAL;
479 goto render_mgradient;
481 case WTEX_MVGRADIENT:
482 subtype = RGRD_VERTICAL;
483 goto render_mgradient;
485 case WTEX_MDGRADIENT:
486 subtype = RGRD_DIAGONAL;
487 render_mgradient:
488 image = RRenderMultiGradient(width, height,
489 &(texture->mgradient.colors[1]),
490 subtype);
491 break;
493 case WTEX_THGRADIENT:
494 subtype = RGRD_HORIZONTAL;
495 goto render_tgradient;
497 case WTEX_TVGRADIENT:
498 subtype = RGRD_VERTICAL;
499 goto render_tgradient;
501 case WTEX_TDGRADIENT:
502 subtype = RGRD_DIAGONAL;
503 render_tgradient:
505 RImage *grad;
507 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
508 if (!image)
509 break;
511 grad = RRenderGradient(width, height, &texture->tgradient.color1,
512 &texture->tgradient.color2, subtype);
513 if (!grad) {
514 RDestroyImage(image);
515 image = NULL;
516 break;
519 RCombineImagesWithOpaqueness(image, grad,
520 texture->tgradient.opacity);
521 RDestroyImage(grad);
523 break;
525 #ifdef TEXTURE_PLUGIN
526 case WTEX_FUNCTION:
527 #ifdef HAVE_DLFCN_H
528 if (texture->function.render) {
529 image = texture->function.render (
530 texture->function.argc, texture->function.argv,
531 width, height, relief);
533 #endif
534 if (!image) {
535 RErrorCode = RERR_INTERNAL;
537 break;
538 #endif /* TEXTURE_PLUGIN */
540 default:
541 puts("ERROR in wTextureRenderImage()");
542 image = NULL;
543 break;
546 if (!image) {
547 RColor gray;
549 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
551 image = RCreateImage(width, height, False);
553 gray.red = 190;
554 gray.green = 190;
555 gray.blue = 190;
556 gray.alpha = 255;
557 RClearImage(image, &gray);
561 /* render bevel */
563 switch (relief) {
564 case WREL_ICON:
565 d = RBEV_RAISED3;
566 break;
568 case WREL_RAISED:
569 d = RBEV_RAISED2;
570 break;
572 case WREL_SUNKEN:
573 d = RBEV_SUNKEN;
574 break;
576 case WREL_FLAT:
577 d = 0;
578 break;
580 case WREL_MENUENTRY:
581 d = -WREL_MENUENTRY;
582 break;
584 default:
585 d = 0;
588 if (d > 0) {
589 RBevelImage(image, d);
590 } else if (d < 0) {
591 bevelImage(image, -d);
594 return image;
599 static void
600 bevelImage(RImage *image, int relief)
602 int width = image->width;
603 int height = image->height;
604 RColor color;
606 switch (relief) {
607 case WREL_MENUENTRY:
608 color.red = color.green = color.blue = 80;
609 color.alpha = 0;
610 /**/
611 ROperateLine(image, RAddOperation, 1, 0, width-2, 0, &color);
612 /**/
614 ROperateLine(image, RAddOperation, 0, 0, 0, height-1, &color);
616 color.red = color.green = color.blue = 40;
617 color.alpha = 0;
618 ROperateLine(image, RSubtractOperation, width-1, 0, width-1,
619 height-1, &color);
621 /**/
622 ROperateLine(image, RSubtractOperation, 1, height-2, width-2,
623 height-2, &color);
625 color.red = color.green = color.blue = 0;
626 color.alpha = 255;
627 RDrawLine(image, 0, height-1, width-1, height-1, &color);
628 /**/
629 break;
636 void
637 wDrawBevel(Drawable d, unsigned width, unsigned height,
638 WTexSolid *texture, int relief)
640 GC light, dim, dark;
641 XSegment segs[4];
643 if (relief==WREL_FLAT) return;
645 light = texture->light_gc;
646 dim = texture->dim_gc;
647 dark = texture->dark_gc;
648 switch (relief) {
649 case WREL_FLAT:
650 return;
651 case WREL_MENUENTRY:
652 case WREL_RAISED:
653 case WREL_ICON:
654 segs[0].x1 = 1;
655 segs[0].x2 = width - 2;
656 segs[0].y2 = segs[0].y1 = height - 2;
657 segs[1].x1 = width - 2;
658 segs[1].y1 = 1;
659 segs[1].x2 = width - 2;
660 segs[1].y2 = height - 2;
661 XDrawSegments(dpy, d, dim, segs, 2);
662 segs[0].x1 = 0;
663 segs[0].x2 = width - 1;
664 segs[0].y2 = segs[0].y1 = height - 1;
665 segs[1].x1 = segs[1].x2 = width - 1;
666 segs[1].y1 = 0;
667 segs[1].y2 = height - 1;
668 XDrawSegments(dpy, d, dark, segs, 2);
669 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
670 segs[0].x2 = width - 2;
671 segs[1].x1 = segs[1].y1 = 0;
672 segs[1].x2 = 0;
673 segs[1].y2 = height - 2;
674 XDrawSegments(dpy, d, light, segs, 2);
675 if (relief==WREL_ICON) {
676 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
677 segs[0].x2 = width - 2;
678 segs[1].x1 = segs[1].y1 = 1;
679 segs[1].x2 = 1;
680 segs[1].y2 = height - 2;
681 XDrawSegments(dpy, d, light, segs, 2);
683 break;
684 #ifdef unused
685 case WREL_SUNKEN:
686 segs[0].x1 = 0;
687 segs[0].x2 = width - 1;
688 segs[0].y2 = segs[0].y1 = 0;
689 segs[1].x1 = segs[1].x2 = 0;
690 segs[1].y1 = 0;
691 segs[1].y2 = height - 1;
692 XDrawSegments(dpy, d, dark, segs, 2);
694 segs[0].x1 = 0;
695 segs[0].y1 = segs[0].y2 = height - 1;
696 segs[0].x2 = width - 1;
697 segs[1].x2 = segs[1].x1 = width - 1;
698 segs[1].y1 = 1;
699 segs[1].y2 = height - 1;
700 XDrawSegments(dpy, d, light, segs, 2);
701 break;
702 #endif