Change to the linux kernel coding style
[wmaker-crm.git] / src / texture.c
dissimilarity index 91%
index 0fd2ad3..c0f6c2a 100644 (file)
-/*
- *  Window Maker window manager
- *
- *  Copyright (c) 1997-2003 Alfredo K. Kojima
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- *  USA.
- */
-
-#include "wconfig.h"
-
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-#ifdef TEXTURE_PLUGIN
-# ifdef HAVE_DLFCN_H
-#  include <dlfcn.h>
-# endif
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <wraster.h>
-
-#include "WindowMaker.h"
-#include "wcore.h"
-#include "texture.h"
-#include "funcs.h"
-
-extern WPreferences wPreferences;
-
-
-static void bevelImage(RImage *image, int relief);
-
-
-
-WTexSolid*
-wTextureMakeSolid(WScreen *scr, XColor *color)
-{
-    WTexSolid *texture;
-    int gcm;
-    XGCValues gcv;
-
-    texture = wmalloc(sizeof(WTexture));
-
-    texture->type = WTEX_SOLID;
-    texture->subtype = 0;
-
-    XAllocColor(dpy, scr->w_colormap, color);
-    texture->normal = *color;
-    if (color->red==0 && color->blue==0 && color->green == 0) {
-        texture->light.red = 0xb6da;
-        texture->light.green = 0xb6da;
-        texture->light.blue = 0xb6da;
-        texture->dim.red = 0x6185;
-        texture->dim.green = 0x6185;
-        texture->dim.blue = 0x6185;
-    } else {
-        RColor rgb;
-        RHSVColor hsv, hsv2;
-        int v;
-
-        rgb.red = color->red >> 8;
-        rgb.green = color->green >> 8;
-        rgb.blue = color->blue >> 8;
-        RRGBtoHSV(&rgb, &hsv);
-        RHSVtoRGB(&hsv, &rgb);
-        hsv2 = hsv;
-
-        v = hsv.value*16/10;
-        hsv.value = (v > 255 ? 255 : v);
-        RHSVtoRGB(&hsv, &rgb);
-        texture->light.red = rgb.red << 8;
-        texture->light.green = rgb.green << 8;
-        texture->light.blue = rgb.blue << 8;
-
-        hsv2.value = hsv2.value/2;
-        RHSVtoRGB(&hsv2, &rgb);
-        texture->dim.red = rgb.red << 8;
-        texture->dim.green = rgb.green << 8;
-        texture->dim.blue = rgb.blue << 8;
-    }
-    texture->dark.red = 0;
-    texture->dark.green = 0;
-    texture->dark.blue = 0;
-    XAllocColor(dpy, scr->w_colormap, &texture->light);
-    XAllocColor(dpy, scr->w_colormap, &texture->dim);
-    XAllocColor(dpy, scr->w_colormap, &texture->dark);
-
-    gcm = GCForeground|GCBackground|GCGraphicsExposures;
-    gcv.graphics_exposures = False;
-
-    gcv.background = gcv.foreground = texture->light.pixel;
-    texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
-
-    gcv.background = gcv.foreground = texture->dim.pixel;
-    texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
-
-    gcv.background = gcv.foreground = texture->dark.pixel;
-    texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
-
-    gcv.background = gcv.foreground = color->pixel;
-    texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
-
-    return texture;
-}
-
-
-static int
-dummyErrorHandler(Display *foo, XErrorEvent *bar)
-{
-#ifdef DEBUG
-    wwarning("your server is buggy. Tell the author if some error related to color occurs");
-#endif
-    return 0;
-}
-
-
-void
-wTextureDestroy(WScreen *scr, WTexture *texture)
-{
-    int i;
-    int count=0;
-    unsigned long colors[8];
-
-#ifdef DEBUG
-    if (texture==NULL) {
-        printf("BUG: trying to free NULL texture\n");
-        return;
-    }
-#endif
-
-    /*
-     * some stupid servers don't like white or black being freed...
-     */
-#define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
-    switch (texture->any.type) {
-    case WTEX_SOLID:
-        XFreeGC(dpy, texture->solid.light_gc);
-        XFreeGC(dpy, texture->solid.dark_gc);
-        XFreeGC(dpy, texture->solid.dim_gc);
-        if (CANFREE(texture->solid.light.pixel))
-            colors[count++] = texture->solid.light.pixel;
-        if (CANFREE(texture->solid.dim.pixel))
-            colors[count++] = texture->solid.dim.pixel;
-        if (CANFREE(texture->solid.dark.pixel))
-            colors[count++] = texture->solid.dark.pixel;
-        break;
-
-    case WTEX_PIXMAP:
-        RReleaseImage(texture->pixmap.pixmap);
-        break;
-
-    case WTEX_MHGRADIENT:
-    case WTEX_MVGRADIENT:
-    case WTEX_MDGRADIENT:
-        for (i=0; texture->mgradient.colors[i]!=NULL; i++) {
-            wfree(texture->mgradient.colors[i]);
-        }
-        wfree(texture->mgradient.colors);
-        break;
-
-    case WTEX_THGRADIENT:
-    case WTEX_TVGRADIENT:
-    case WTEX_TDGRADIENT:
-        RReleaseImage(texture->tgradient.pixmap);
-        break;
-
-#ifdef TEXTURE_PLUGIN
-    case WTEX_FUNCTION:
-#ifdef HAVE_DLFCN_H
-        if (texture->function.handle) {
-            dlclose(texture->function.handle);
-        }
-#endif
-        for (i = 0; i < texture->function.argc; i++) {
-            wfree(texture->function.argv[i]);
-        }
-        wfree(texture->function.argv);
-        break;
-#endif /* TEXTURE_PLUGIN */
-    }
-    if (CANFREE(texture->any.color.pixel))
-        colors[count++] = texture->any.color.pixel;
-    if (count > 0) {
-        XErrorHandler oldhandler;
-
-        /* ignore error from buggy servers that don't know how
-         * to do reference counting for colors. */
-        XSync(dpy,0);
-        oldhandler = XSetErrorHandler(dummyErrorHandler);
-        XFreeColors(dpy, scr->w_colormap, colors, count, 0);
-        XSync(dpy,0);
-        XSetErrorHandler(oldhandler);
-    }
-    XFreeGC(dpy, texture->any.gc);
-    wfree(texture);
-#undef CANFREE
-}
-
-
-
-WTexGradient*
-wTextureMakeGradient(WScreen *scr, int style, RColor *from, RColor *to)
-{
-    WTexGradient *texture;
-    XGCValues gcv;
-
-
-    texture = wmalloc(sizeof(WTexture));
-    memset(texture, 0, sizeof(WTexture));
-    texture->type = style;
-    texture->subtype = 0;
-
-    texture->color1 = *from;
-    texture->color2 = *to;
-
-    texture->normal.red = (from->red + to->red)<<7;
-    texture->normal.green = (from->green + to->green)<<7;
-    texture->normal.blue = (from->blue + to->blue)<<7;
-
-    XAllocColor(dpy, scr->w_colormap, &texture->normal);
-    gcv.background = gcv.foreground = texture->normal.pixel;
-    gcv.graphics_exposures = False;
-    texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
-                                   |GCGraphicsExposures, &gcv);
-
-    return texture;
-}
-
-
-
-
-WTexIGradient*
-wTextureMakeIGradient(WScreen *scr, int thickness1, RColor colors1[2],
-                      int thickness2, RColor colors2[2])
-{
-    WTexIGradient *texture;
-    XGCValues gcv;
-    int i;
-
-
-    texture = wmalloc(sizeof(WTexture));
-    memset(texture, 0, sizeof(WTexture));
-    texture->type = WTEX_IGRADIENT;
-    for (i = 0; i < 2; i++) {
-        texture->colors1[i] = colors1[i];
-        texture->colors2[i] = colors2[i];
-    }
-    texture->thickness1 = thickness1;
-    texture->thickness2 = thickness2;
-    if (thickness1 >= thickness2) {
-        texture->normal.red = (colors1[0].red + colors1[1].red)<<7;
-        texture->normal.green = (colors1[0].green + colors1[1].green)<<7;
-        texture->normal.blue = (colors1[0].blue + colors1[1].blue)<<7;
-    } else {
-        texture->normal.red = (colors2[0].red + colors2[1].red)<<7;
-        texture->normal.green = (colors2[0].green + colors2[1].green)<<7;
-        texture->normal.blue = (colors2[0].blue + colors2[1].blue)<<7;
-    }
-    XAllocColor(dpy, scr->w_colormap, &texture->normal);
-    gcv.background = gcv.foreground = texture->normal.pixel;
-    gcv.graphics_exposures = False;
-    texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
-                                   |GCGraphicsExposures, &gcv);
-
-    return texture;
-}
-
-
-
-WTexMGradient*
-wTextureMakeMGradient(WScreen *scr, int style, RColor **colors)
-{
-    WTexMGradient *texture;
-    XGCValues gcv;
-    int i;
-
-
-    texture = wmalloc(sizeof(WTexture));
-    memset(texture, 0, sizeof(WTexture));
-    texture->type = style;
-    texture->subtype = 0;
-
-    i=0;
-    while (colors[i]!=NULL) i++;
-    i--;
-    texture->normal.red = (colors[0]->red<<8);
-    texture->normal.green = (colors[0]->green<<8);
-    texture->normal.blue =  (colors[0]->blue<<8);
-
-    texture->colors = colors;
-
-    XAllocColor(dpy, scr->w_colormap, &texture->normal);
-    gcv.background = gcv.foreground = texture->normal.pixel;
-    gcv.graphics_exposures = False;
-    texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
-                                   |GCGraphicsExposures, &gcv);
-
-    return texture;
-}
-
-
-
-WTexPixmap*
-wTextureMakePixmap(WScreen *scr, int style, char *pixmap_file, XColor *color)
-{
-    WTexPixmap *texture;
-    XGCValues gcv;
-    RImage *image;
-    char *file;
-
-    file = FindImage(wPreferences.pixmap_path, pixmap_file);
-    if (!file) {
-        wwarning(_("image file \"%s\" used as texture could not be found."),
-                 pixmap_file);
-        return NULL;
-    }
-    image = RLoadImage(scr->rcontext, file, 0);
-    if (!image) {
-        wwarning(_("could not load texture pixmap \"%s\":%s"), file,
-                 RMessageForError(RErrorCode));
-        wfree(file);
-        return NULL;
-    }
-    wfree(file);
-
-    texture = wmalloc(sizeof(WTexture));
-    memset(texture, 0, sizeof(WTexture));
-    texture->type = WTEX_PIXMAP;
-    texture->subtype = style;
-
-    texture->normal = *color;
-
-    XAllocColor(dpy, scr->w_colormap, &texture->normal);
-    gcv.background = gcv.foreground = texture->normal.pixel;
-    gcv.graphics_exposures = False;
-    texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
-                                   |GCGraphicsExposures, &gcv);
-
-    texture->pixmap = image;
-
-    return texture;
-}
-
-WTexTGradient*
-wTextureMakeTGradient(WScreen *scr, int style, RColor *from, RColor *to,
-                      char *pixmap_file, int opacity)
-{
-    WTexTGradient *texture;
-    XGCValues gcv;
-    RImage *image;
-    char *file;
-
-    file = FindImage(wPreferences.pixmap_path, pixmap_file);
-    if (!file) {
-        wwarning(_("image file \"%s\" used as texture could not be found."),
-                 pixmap_file);
-        return NULL;
-    }
-    image = RLoadImage(scr->rcontext, file, 0);
-    if (!image) {
-        wwarning(_("could not load texture pixmap \"%s\":%s"), file,
-                 RMessageForError(RErrorCode));
-        wfree(file);
-        return NULL;
-    }
-    wfree(file);
-
-    texture = wmalloc(sizeof(WTexture));
-    memset(texture, 0, sizeof(WTexture));
-    texture->type = style;
-
-    texture->opacity = opacity;
-
-    texture->color1 = *from;
-    texture->color2 = *to;
-
-    texture->normal.red = (from->red + to->red)<<7;
-    texture->normal.green = (from->green + to->green)<<7;
-    texture->normal.blue = (from->blue + to->blue)<<7;
-
-    XAllocColor(dpy, scr->w_colormap, &texture->normal);
-    gcv.background = gcv.foreground = texture->normal.pixel;
-    gcv.graphics_exposures = False;
-    texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
-                                   |GCGraphicsExposures, &gcv);
-
-    texture->pixmap = image;
-
-    return texture;
-}
-
-
-#ifdef TEXTURE_PLUGIN
-WTexFunction*
-wTextureMakeFunction(WScreen *scr, char *lib, char *func, int argc, char **argv)
-{
-    XColor fallbackColor;
-    XGCValues gcv;
-    WTexFunction *texture;
-
-    texture = wmalloc(sizeof(WTexture));
-    texture->type = WTEX_FUNCTION;
-    texture->handle = NULL;
-    texture->render = 0;
-    texture->argc = argc;
-    texture->argv = argv;
-
-    fallbackColor.red = 0x8000;
-    fallbackColor.green = 0x8000;
-    fallbackColor.blue = 0x8000;
-
-    gcv.background = gcv.foreground = fallbackColor.pixel;
-    gcv.graphics_exposures = False;
-    texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
-                                   |GCGraphicsExposures, &gcv);
-
-# ifdef HAVE_DLFCN_H
-    /* open the library */
-    texture->handle = dlopen(lib, RTLD_LAZY);
-    if (!texture->handle) {
-        wwarning(_("library \"%s\" cound not be opened."), lib);
-        wfree(argv);
-        wfree(texture);
-        return NULL;
-    }
-
-    /* find the function */
-    texture->render = dlsym(texture->handle, func);
-    if (!texture->render) {
-        wwarning(_("function \"%s\" not found in library \"%s\""), func, lib);
-        wfree(argv);
-        dlclose(texture->handle);
-        wfree(texture);
-        return NULL;
-    }
-# else
-    wwarning(_("function textures not supported on this system, sorry."));
-# endif
-
-    /* success! */
-    return texture;
-}
-#endif /* TEXTURE_PLUGIN */
-
-
-RImage*
-wTextureRenderImage(WTexture *texture, int width, int height,
-                    int relief)
-{
-    RImage *image = NULL;
-    RColor color1;
-    int d;
-    int subtype;
-
-    switch (texture->any.type) {
-    case WTEX_SOLID:
-        image = RCreateImage(width, height, False);
-
-        color1.red = texture->solid.normal.red >> 8;
-        color1.green = texture->solid.normal.green >> 8;
-        color1.blue = texture->solid.normal.blue >> 8;
-        color1.alpha = 255;
-
-        RClearImage(image, &color1);
-        break;
-
-    case WTEX_PIXMAP:
-        if (texture->pixmap.subtype == WTP_TILE) {
-            image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
-        } else if (texture->pixmap.subtype == WTP_CENTER) {
-            color1.red = texture->pixmap.normal.red>>8;
-            color1.green = texture->pixmap.normal.green>>8;
-            color1.blue = texture->pixmap.normal.blue>>8;
-            color1.alpha = 255;
-            image = RMakeCenteredImage(texture->pixmap.pixmap, width, height,
-                                       &color1);
-        } else {
-            image = RScaleImage(texture->pixmap.pixmap, width, height);
-        }
-        break;
-
-    case WTEX_IGRADIENT:
-        image = RRenderInterwovenGradient(width, height,
-                                          texture->igradient.colors1,
-                                          texture->igradient.thickness1,
-                                          texture->igradient.colors2,
-                                          texture->igradient.thickness2);
-        break;
-
-    case WTEX_HGRADIENT:
-        subtype = RGRD_HORIZONTAL;
-        goto render_gradient;
-
-    case WTEX_VGRADIENT:
-        subtype = RGRD_VERTICAL;
-        goto render_gradient;
-
-    case WTEX_DGRADIENT:
-        subtype = RGRD_DIAGONAL;
-    render_gradient:
-
-        image = RRenderGradient(width, height, &texture->gradient.color1,
-                                &texture->gradient.color2, subtype);
-        break;
-
-    case WTEX_MHGRADIENT:
-        subtype = RGRD_HORIZONTAL;
-        goto render_mgradient;
-
-    case WTEX_MVGRADIENT:
-        subtype = RGRD_VERTICAL;
-        goto render_mgradient;
-
-    case WTEX_MDGRADIENT:
-        subtype = RGRD_DIAGONAL;
-    render_mgradient:
-        image = RRenderMultiGradient(width, height,
-                                     &(texture->mgradient.colors[1]),
-                                     subtype);
-        break;
-
-    case WTEX_THGRADIENT:
-        subtype = RGRD_HORIZONTAL;
-        goto render_tgradient;
-
-    case WTEX_TVGRADIENT:
-        subtype = RGRD_VERTICAL;
-        goto render_tgradient;
-
-    case WTEX_TDGRADIENT:
-        subtype = RGRD_DIAGONAL;
-    render_tgradient:
-        {
-            RImage *grad;
-
-            image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
-            if (!image)
-                break;
-
-            grad = RRenderGradient(width, height, &texture->tgradient.color1,
-                                   &texture->tgradient.color2, subtype);
-            if (!grad) {
-                RReleaseImage(image);
-                image = NULL;
-                break;
-            }
-
-            RCombineImagesWithOpaqueness(image, grad,
-                                         texture->tgradient.opacity);
-            RReleaseImage(grad);
-        }
-        break;
-
-#ifdef TEXTURE_PLUGIN
-    case WTEX_FUNCTION:
-#ifdef HAVE_DLFCN_H
-        if (texture->function.render) {
-            image = texture->function.render (
-                                              texture->function.argc, texture->function.argv,
-                                              width, height, relief);
-        }
-#endif
-        if (!image) {
-            RErrorCode = RERR_INTERNAL;
-        }
-        break;
-#endif /* TEXTURE_PLUGIN */
-
-    default:
-        puts("ERROR in wTextureRenderImage()");
-        image = NULL;
-        break;
-    }
-
-    if (!image) {
-        RColor gray;
-
-        wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
-
-        image = RCreateImage(width, height, False);
-        if (image == NULL) {
-            wwarning(_("could not allocate image buffer"));
-            return NULL;
-        }
-
-        gray.red = 190;
-        gray.green = 190;
-        gray.blue = 190;
-        gray.alpha = 255;
-        RClearImage(image, &gray);
-    }
-
-
-    /* render bevel */
-
-    switch (relief) {
-    case WREL_ICON:
-        d = RBEV_RAISED3;
-        break;
-
-    case WREL_RAISED:
-        d = RBEV_RAISED2;
-        break;
-
-    case WREL_SUNKEN:
-        d = RBEV_SUNKEN;
-        break;
-
-    case WREL_FLAT:
-        d = 0;
-        break;
-
-    case WREL_MENUENTRY:
-        d = -WREL_MENUENTRY;
-        break;
-
-    default:
-        d = 0;
-    }
-
-    if (d > 0) {
-        RBevelImage(image, d);
-    } else if (d < 0) {
-        bevelImage(image, -d);
-    }
-
-    return image;
-}
-
-
-
-static void
-bevelImage(RImage *image, int relief)
-{
-    int width = image->width;
-    int height = image->height;
-    RColor color;
-
-    switch (relief) {
-    case WREL_MENUENTRY:
-        color.red = color.green = color.blue = 80;
-        color.alpha = 0;
-        /**/
-        ROperateLine(image, RAddOperation, 1, 0, width-2, 0, &color);
-        /**/
-
-        ROperateLine(image, RAddOperation, 0, 0, 0, height-1, &color);
-
-        color.red = color.green = color.blue = 40;
-        color.alpha = 0;
-        ROperateLine(image, RSubtractOperation, width-1, 0, width-1,
-                     height-1, &color);
-
-        /**/
-        ROperateLine(image, RSubtractOperation, 1, height-2, width-2,
-                     height-2, &color);
-
-        color.red = color.green = color.blue = 0;
-        color.alpha = 255;
-        RDrawLine(image, 0, height-1, width-1, height-1, &color);
-        /**/
-        break;
-
-    }
-}
-
-
-
-void
-wDrawBevel(Drawable d, unsigned width, unsigned height,
-           WTexSolid *texture, int relief)
-{
-    GC light, dim, dark;
-    XSegment segs[4];
-
-    if (relief==WREL_FLAT) return;
-
-    light = texture->light_gc;
-    dim = texture->dim_gc;
-    dark = texture->dark_gc;
-    switch (relief) {
-    case WREL_FLAT:
-        return;
-    case WREL_MENUENTRY:
-    case WREL_RAISED:
-    case WREL_ICON:
-        segs[0].x1 = 1;
-        segs[0].x2 = width - 2;
-        segs[0].y2 = segs[0].y1 = height - 2;
-        segs[1].x1 = width - 2;
-        segs[1].y1 = 1;
-        segs[1].x2 = width - 2;
-        segs[1].y2 = height - 2;
-        XDrawSegments(dpy, d, dim, segs, 2);
-        segs[0].x1 = 0;
-        segs[0].x2 = width - 1;
-        segs[0].y2 = segs[0].y1 = height - 1;
-        segs[1].x1 = segs[1].x2 = width - 1;
-        segs[1].y1 = 0;
-        segs[1].y2 = height - 1;
-        XDrawSegments(dpy, d, dark, segs, 2);
-        segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
-        segs[0].x2 = width - 2;
-        segs[1].x1 = segs[1].y1 = 0;
-        segs[1].x2 = 0;
-        segs[1].y2 = height - 2;
-        XDrawSegments(dpy, d, light, segs, 2);
-        if (relief==WREL_ICON) {
-            segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
-            segs[0].x2 = width - 2;
-            segs[1].x1 = segs[1].y1 = 1;
-            segs[1].x2 = 1;
-            segs[1].y2 = height - 2;
-            XDrawSegments(dpy, d, light, segs, 2);
-        }
-        break;
-#ifdef unused
-    case WREL_SUNKEN:
-        segs[0].x1 = 0;
-        segs[0].x2 = width - 1;
-        segs[0].y2 = segs[0].y1 = 0;
-        segs[1].x1 = segs[1].x2 = 0;
-        segs[1].y1 = 0;
-        segs[1].y2 = height - 1;
-        XDrawSegments(dpy, d, dark, segs, 2);
-
-        segs[0].x1 = 0;
-        segs[0].y1 = segs[0].y2 = height - 1;
-        segs[0].x2 = width - 1;
-        segs[1].x2 = segs[1].x1 = width - 1;
-        segs[1].y1 = 1;
-        segs[1].y2 = height - 1;
-        XDrawSegments(dpy, d, light, segs, 2);
-        break;
-#endif
-    }
-}
-
+/*
+ *  Window Maker window manager
+ *
+ *  Copyright (c) 1997-2003 Alfredo K. Kojima
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ *  USA.
+ */
+
+#include "wconfig.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef TEXTURE_PLUGIN
+# ifdef HAVE_DLFCN_H
+#  include <dlfcn.h>
+# endif
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <wraster.h>
+
+#include "WindowMaker.h"
+#include "wcore.h"
+#include "texture.h"
+#include "funcs.h"
+
+extern WPreferences wPreferences;
+
+static void bevelImage(RImage * image, int relief);
+
+WTexSolid *wTextureMakeSolid(WScreen * scr, XColor * color)
+{
+       WTexSolid *texture;
+       int gcm;
+       XGCValues gcv;
+
+       texture = wmalloc(sizeof(WTexture));
+
+       texture->type = WTEX_SOLID;
+       texture->subtype = 0;
+
+       XAllocColor(dpy, scr->w_colormap, color);
+       texture->normal = *color;
+       if (color->red == 0 && color->blue == 0 && color->green == 0) {
+               texture->light.red = 0xb6da;
+               texture->light.green = 0xb6da;
+               texture->light.blue = 0xb6da;
+               texture->dim.red = 0x6185;
+               texture->dim.green = 0x6185;
+               texture->dim.blue = 0x6185;
+       } else {
+               RColor rgb;
+               RHSVColor hsv, hsv2;
+               int v;
+
+               rgb.red = color->red >> 8;
+               rgb.green = color->green >> 8;
+               rgb.blue = color->blue >> 8;
+               RRGBtoHSV(&rgb, &hsv);
+               RHSVtoRGB(&hsv, &rgb);
+               hsv2 = hsv;
+
+               v = hsv.value * 16 / 10;
+               hsv.value = (v > 255 ? 255 : v);
+               RHSVtoRGB(&hsv, &rgb);
+               texture->light.red = rgb.red << 8;
+               texture->light.green = rgb.green << 8;
+               texture->light.blue = rgb.blue << 8;
+
+               hsv2.value = hsv2.value / 2;
+               RHSVtoRGB(&hsv2, &rgb);
+               texture->dim.red = rgb.red << 8;
+               texture->dim.green = rgb.green << 8;
+               texture->dim.blue = rgb.blue << 8;
+       }
+       texture->dark.red = 0;
+       texture->dark.green = 0;
+       texture->dark.blue = 0;
+       XAllocColor(dpy, scr->w_colormap, &texture->light);
+       XAllocColor(dpy, scr->w_colormap, &texture->dim);
+       XAllocColor(dpy, scr->w_colormap, &texture->dark);
+
+       gcm = GCForeground | GCBackground | GCGraphicsExposures;
+       gcv.graphics_exposures = False;
+
+       gcv.background = gcv.foreground = texture->light.pixel;
+       texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
+
+       gcv.background = gcv.foreground = texture->dim.pixel;
+       texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
+
+       gcv.background = gcv.foreground = texture->dark.pixel;
+       texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
+
+       gcv.background = gcv.foreground = color->pixel;
+       texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
+
+       return texture;
+}
+
+static int dummyErrorHandler(Display * foo, XErrorEvent * bar)
+{
+#ifdef DEBUG
+       wwarning("your server is buggy. Tell the author if some error related to color occurs");
+#endif
+       return 0;
+}
+
+void wTextureDestroy(WScreen * scr, WTexture * texture)
+{
+       int i;
+       int count = 0;
+       unsigned long colors[8];
+
+#ifdef DEBUG
+       if (texture == NULL) {
+               printf("BUG: trying to free NULL texture\n");
+               return;
+       }
+#endif
+
+       /*
+        * some stupid servers don't like white or black being freed...
+        */
+#define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
+       switch (texture->any.type) {
+       case WTEX_SOLID:
+               XFreeGC(dpy, texture->solid.light_gc);
+               XFreeGC(dpy, texture->solid.dark_gc);
+               XFreeGC(dpy, texture->solid.dim_gc);
+               if (CANFREE(texture->solid.light.pixel))
+                       colors[count++] = texture->solid.light.pixel;
+               if (CANFREE(texture->solid.dim.pixel))
+                       colors[count++] = texture->solid.dim.pixel;
+               if (CANFREE(texture->solid.dark.pixel))
+                       colors[count++] = texture->solid.dark.pixel;
+               break;
+
+       case WTEX_PIXMAP:
+               RReleaseImage(texture->pixmap.pixmap);
+               break;
+
+       case WTEX_MHGRADIENT:
+       case WTEX_MVGRADIENT:
+       case WTEX_MDGRADIENT:
+               for (i = 0; texture->mgradient.colors[i] != NULL; i++) {
+                       wfree(texture->mgradient.colors[i]);
+               }
+               wfree(texture->mgradient.colors);
+               break;
+
+       case WTEX_THGRADIENT:
+       case WTEX_TVGRADIENT:
+       case WTEX_TDGRADIENT:
+               RReleaseImage(texture->tgradient.pixmap);
+               break;
+
+#ifdef TEXTURE_PLUGIN
+       case WTEX_FUNCTION:
+#ifdef HAVE_DLFCN_H
+               if (texture->function.handle) {
+                       dlclose(texture->function.handle);
+               }
+#endif
+               for (i = 0; i < texture->function.argc; i++) {
+                       wfree(texture->function.argv[i]);
+               }
+               wfree(texture->function.argv);
+               break;
+#endif                         /* TEXTURE_PLUGIN */
+       }
+       if (CANFREE(texture->any.color.pixel))
+               colors[count++] = texture->any.color.pixel;
+       if (count > 0) {
+               XErrorHandler oldhandler;
+
+               /* ignore error from buggy servers that don't know how
+                * to do reference counting for colors. */
+               XSync(dpy, 0);
+               oldhandler = XSetErrorHandler(dummyErrorHandler);
+               XFreeColors(dpy, scr->w_colormap, colors, count, 0);
+               XSync(dpy, 0);
+               XSetErrorHandler(oldhandler);
+       }
+       XFreeGC(dpy, texture->any.gc);
+       wfree(texture);
+#undef CANFREE
+}
+
+WTexGradient *wTextureMakeGradient(WScreen * scr, int style, RColor * from, RColor * to)
+{
+       WTexGradient *texture;
+       XGCValues gcv;
+
+       texture = wmalloc(sizeof(WTexture));
+       memset(texture, 0, sizeof(WTexture));
+       texture->type = style;
+       texture->subtype = 0;
+
+       texture->color1 = *from;
+       texture->color2 = *to;
+
+       texture->normal.red = (from->red + to->red) << 7;
+       texture->normal.green = (from->green + to->green) << 7;
+       texture->normal.blue = (from->blue + to->blue) << 7;
+
+       XAllocColor(dpy, scr->w_colormap, &texture->normal);
+       gcv.background = gcv.foreground = texture->normal.pixel;
+       gcv.graphics_exposures = False;
+       texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+
+       return texture;
+}
+
+WTexIGradient *wTextureMakeIGradient(WScreen * scr, int thickness1, RColor colors1[2],
+                                    int thickness2, RColor colors2[2])
+{
+       WTexIGradient *texture;
+       XGCValues gcv;
+       int i;
+
+       texture = wmalloc(sizeof(WTexture));
+       memset(texture, 0, sizeof(WTexture));
+       texture->type = WTEX_IGRADIENT;
+       for (i = 0; i < 2; i++) {
+               texture->colors1[i] = colors1[i];
+               texture->colors2[i] = colors2[i];
+       }
+       texture->thickness1 = thickness1;
+       texture->thickness2 = thickness2;
+       if (thickness1 >= thickness2) {
+               texture->normal.red = (colors1[0].red + colors1[1].red) << 7;
+               texture->normal.green = (colors1[0].green + colors1[1].green) << 7;
+               texture->normal.blue = (colors1[0].blue + colors1[1].blue) << 7;
+       } else {
+               texture->normal.red = (colors2[0].red + colors2[1].red) << 7;
+               texture->normal.green = (colors2[0].green + colors2[1].green) << 7;
+               texture->normal.blue = (colors2[0].blue + colors2[1].blue) << 7;
+       }
+       XAllocColor(dpy, scr->w_colormap, &texture->normal);
+       gcv.background = gcv.foreground = texture->normal.pixel;
+       gcv.graphics_exposures = False;
+       texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+
+       return texture;
+}
+
+WTexMGradient *wTextureMakeMGradient(WScreen * scr, int style, RColor ** colors)
+{
+       WTexMGradient *texture;
+       XGCValues gcv;
+       int i;
+
+       texture = wmalloc(sizeof(WTexture));
+       memset(texture, 0, sizeof(WTexture));
+       texture->type = style;
+       texture->subtype = 0;
+
+       i = 0;
+       while (colors[i] != NULL)
+               i++;
+       i--;
+       texture->normal.red = (colors[0]->red << 8);
+       texture->normal.green = (colors[0]->green << 8);
+       texture->normal.blue = (colors[0]->blue << 8);
+
+       texture->colors = colors;
+
+       XAllocColor(dpy, scr->w_colormap, &texture->normal);
+       gcv.background = gcv.foreground = texture->normal.pixel;
+       gcv.graphics_exposures = False;
+       texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+
+       return texture;
+}
+
+WTexPixmap *wTextureMakePixmap(WScreen * scr, int style, char *pixmap_file, XColor * color)
+{
+       WTexPixmap *texture;
+       XGCValues gcv;
+       RImage *image;
+       char *file;
+
+       file = FindImage(wPreferences.pixmap_path, pixmap_file);
+       if (!file) {
+               wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
+               return NULL;
+       }
+       image = RLoadImage(scr->rcontext, file, 0);
+       if (!image) {
+               wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
+               wfree(file);
+               return NULL;
+       }
+       wfree(file);
+
+       texture = wmalloc(sizeof(WTexture));
+       memset(texture, 0, sizeof(WTexture));
+       texture->type = WTEX_PIXMAP;
+       texture->subtype = style;
+
+       texture->normal = *color;
+
+       XAllocColor(dpy, scr->w_colormap, &texture->normal);
+       gcv.background = gcv.foreground = texture->normal.pixel;
+       gcv.graphics_exposures = False;
+       texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+
+       texture->pixmap = image;
+
+       return texture;
+}
+
+WTexTGradient *wTextureMakeTGradient(WScreen * scr, int style, RColor * from, RColor * to,
+                                    char *pixmap_file, int opacity)
+{
+       WTexTGradient *texture;
+       XGCValues gcv;
+       RImage *image;
+       char *file;
+
+       file = FindImage(wPreferences.pixmap_path, pixmap_file);
+       if (!file) {
+               wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
+               return NULL;
+       }
+       image = RLoadImage(scr->rcontext, file, 0);
+       if (!image) {
+               wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
+               wfree(file);
+               return NULL;
+       }
+       wfree(file);
+
+       texture = wmalloc(sizeof(WTexture));
+       memset(texture, 0, sizeof(WTexture));
+       texture->type = style;
+
+       texture->opacity = opacity;
+
+       texture->color1 = *from;
+       texture->color2 = *to;
+
+       texture->normal.red = (from->red + to->red) << 7;
+       texture->normal.green = (from->green + to->green) << 7;
+       texture->normal.blue = (from->blue + to->blue) << 7;
+
+       XAllocColor(dpy, scr->w_colormap, &texture->normal);
+       gcv.background = gcv.foreground = texture->normal.pixel;
+       gcv.graphics_exposures = False;
+       texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+
+       texture->pixmap = image;
+
+       return texture;
+}
+
+#ifdef TEXTURE_PLUGIN
+WTexFunction *wTextureMakeFunction(WScreen * scr, char *lib, char *func, int argc, char **argv)
+{
+       XColor fallbackColor;
+       XGCValues gcv;
+       WTexFunction *texture;
+
+       texture = wmalloc(sizeof(WTexture));
+       texture->type = WTEX_FUNCTION;
+       texture->handle = NULL;
+       texture->render = 0;
+       texture->argc = argc;
+       texture->argv = argv;
+
+       fallbackColor.red = 0x8000;
+       fallbackColor.green = 0x8000;
+       fallbackColor.blue = 0x8000;
+
+       gcv.background = gcv.foreground = fallbackColor.pixel;
+       gcv.graphics_exposures = False;
+       texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
+
+# ifdef HAVE_DLFCN_H
+       /* open the library */
+       texture->handle = dlopen(lib, RTLD_LAZY);
+       if (!texture->handle) {
+               wwarning(_("library \"%s\" cound not be opened."), lib);
+               wfree(argv);
+               wfree(texture);
+               return NULL;
+       }
+
+       /* find the function */
+       texture->render = dlsym(texture->handle, func);
+       if (!texture->render) {
+               wwarning(_("function \"%s\" not found in library \"%s\""), func, lib);
+               wfree(argv);
+               dlclose(texture->handle);
+               wfree(texture);
+               return NULL;
+       }
+# else
+       wwarning(_("function textures not supported on this system, sorry."));
+# endif
+
+       /* success! */
+       return texture;
+}
+#endif                         /* TEXTURE_PLUGIN */
+
+RImage *wTextureRenderImage(WTexture * texture, int width, int height, int relief)
+{
+       RImage *image = NULL;
+       RColor color1;
+       int d;
+       int subtype;
+
+       switch (texture->any.type) {
+       case WTEX_SOLID:
+               image = RCreateImage(width, height, False);
+
+               color1.red = texture->solid.normal.red >> 8;
+               color1.green = texture->solid.normal.green >> 8;
+               color1.blue = texture->solid.normal.blue >> 8;
+               color1.alpha = 255;
+
+               RClearImage(image, &color1);
+               break;
+
+       case WTEX_PIXMAP:
+               if (texture->pixmap.subtype == WTP_TILE) {
+                       image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
+               } else if (texture->pixmap.subtype == WTP_CENTER) {
+                       color1.red = texture->pixmap.normal.red >> 8;
+                       color1.green = texture->pixmap.normal.green >> 8;
+                       color1.blue = texture->pixmap.normal.blue >> 8;
+                       color1.alpha = 255;
+                       image = RMakeCenteredImage(texture->pixmap.pixmap, width, height, &color1);
+               } else {
+                       image = RScaleImage(texture->pixmap.pixmap, width, height);
+               }
+               break;
+
+       case WTEX_IGRADIENT:
+               image = RRenderInterwovenGradient(width, height,
+                                                 texture->igradient.colors1,
+                                                 texture->igradient.thickness1,
+                                                 texture->igradient.colors2, texture->igradient.thickness2);
+               break;
+
+       case WTEX_HGRADIENT:
+               subtype = RGRD_HORIZONTAL;
+               goto render_gradient;
+
+       case WTEX_VGRADIENT:
+               subtype = RGRD_VERTICAL;
+               goto render_gradient;
+
+       case WTEX_DGRADIENT:
+               subtype = RGRD_DIAGONAL;
+ render_gradient:
+
+               image = RRenderGradient(width, height, &texture->gradient.color1,
+                                       &texture->gradient.color2, subtype);
+               break;
+
+       case WTEX_MHGRADIENT:
+               subtype = RGRD_HORIZONTAL;
+               goto render_mgradient;
+
+       case WTEX_MVGRADIENT:
+               subtype = RGRD_VERTICAL;
+               goto render_mgradient;
+
+       case WTEX_MDGRADIENT:
+               subtype = RGRD_DIAGONAL;
+ render_mgradient:
+               image = RRenderMultiGradient(width, height, &(texture->mgradient.colors[1]), subtype);
+               break;
+
+       case WTEX_THGRADIENT:
+               subtype = RGRD_HORIZONTAL;
+               goto render_tgradient;
+
+       case WTEX_TVGRADIENT:
+               subtype = RGRD_VERTICAL;
+               goto render_tgradient;
+
+       case WTEX_TDGRADIENT:
+               subtype = RGRD_DIAGONAL;
+ render_tgradient:
+               {
+                       RImage *grad;
+
+                       image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
+                       if (!image)
+                               break;
+
+                       grad = RRenderGradient(width, height, &texture->tgradient.color1,
+                                              &texture->tgradient.color2, subtype);
+                       if (!grad) {
+                               RReleaseImage(image);
+                               image = NULL;
+                               break;
+                       }
+
+                       RCombineImagesWithOpaqueness(image, grad, texture->tgradient.opacity);
+                       RReleaseImage(grad);
+               }
+               break;
+
+#ifdef TEXTURE_PLUGIN
+       case WTEX_FUNCTION:
+#ifdef HAVE_DLFCN_H
+               if (texture->function.render) {
+                       image = texture->function.render(texture->function.argc, texture->function.argv,
+                                                        width, height, relief);
+               }
+#endif
+               if (!image) {
+                       RErrorCode = RERR_INTERNAL;
+               }
+               break;
+#endif                         /* TEXTURE_PLUGIN */
+
+       default:
+               puts("ERROR in wTextureRenderImage()");
+               image = NULL;
+               break;
+       }
+
+       if (!image) {
+               RColor gray;
+
+               wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
+
+               image = RCreateImage(width, height, False);
+               if (image == NULL) {
+                       wwarning(_("could not allocate image buffer"));
+                       return NULL;
+               }
+
+               gray.red = 190;
+               gray.green = 190;
+               gray.blue = 190;
+               gray.alpha = 255;
+               RClearImage(image, &gray);
+       }
+
+       /* render bevel */
+
+       switch (relief) {
+       case WREL_ICON:
+               d = RBEV_RAISED3;
+               break;
+
+       case WREL_RAISED:
+               d = RBEV_RAISED2;
+               break;
+
+       case WREL_SUNKEN:
+               d = RBEV_SUNKEN;
+               break;
+
+       case WREL_FLAT:
+               d = 0;
+               break;
+
+       case WREL_MENUENTRY:
+               d = -WREL_MENUENTRY;
+               break;
+
+       default:
+               d = 0;
+       }
+
+       if (d > 0) {
+               RBevelImage(image, d);
+       } else if (d < 0) {
+               bevelImage(image, -d);
+       }
+
+       return image;
+}
+
+static void bevelImage(RImage * image, int relief)
+{
+       int width = image->width;
+       int height = image->height;
+       RColor color;
+
+       switch (relief) {
+       case WREL_MENUENTRY:
+               color.red = color.green = color.blue = 80;
+               color.alpha = 0;
+                /**/ ROperateLine(image, RAddOperation, 1, 0, width - 2, 0, &color);
+                /**/ ROperateLine(image, RAddOperation, 0, 0, 0, height - 1, &color);
+
+               color.red = color.green = color.blue = 40;
+               color.alpha = 0;
+               ROperateLine(image, RSubtractOperation, width - 1, 0, width - 1, height - 1, &color);
+
+                /**/ ROperateLine(image, RSubtractOperation, 1, height - 2, width - 2, height - 2, &color);
+
+               color.red = color.green = color.blue = 0;
+               color.alpha = 255;
+               RDrawLine(image, 0, height - 1, width - 1, height - 1, &color);
+                /**/ break;
+
+       }
+}
+
+void wDrawBevel(Drawable d, unsigned width, unsigned height, WTexSolid * texture, int relief)
+{
+       GC light, dim, dark;
+       XSegment segs[4];
+
+       if (relief == WREL_FLAT)
+               return;
+
+       light = texture->light_gc;
+       dim = texture->dim_gc;
+       dark = texture->dark_gc;
+       switch (relief) {
+       case WREL_FLAT:
+               return;
+       case WREL_MENUENTRY:
+       case WREL_RAISED:
+       case WREL_ICON:
+               segs[0].x1 = 1;
+               segs[0].x2 = width - 2;
+               segs[0].y2 = segs[0].y1 = height - 2;
+               segs[1].x1 = width - 2;
+               segs[1].y1 = 1;
+               segs[1].x2 = width - 2;
+               segs[1].y2 = height - 2;
+               XDrawSegments(dpy, d, dim, segs, 2);
+               segs[0].x1 = 0;
+               segs[0].x2 = width - 1;
+               segs[0].y2 = segs[0].y1 = height - 1;
+               segs[1].x1 = segs[1].x2 = width - 1;
+               segs[1].y1 = 0;
+               segs[1].y2 = height - 1;
+               XDrawSegments(dpy, d, dark, segs, 2);
+               segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
+               segs[0].x2 = width - 2;
+               segs[1].x1 = segs[1].y1 = 0;
+               segs[1].x2 = 0;
+               segs[1].y2 = height - 2;
+               XDrawSegments(dpy, d, light, segs, 2);
+               if (relief == WREL_ICON) {
+                       segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
+                       segs[0].x2 = width - 2;
+                       segs[1].x1 = segs[1].y1 = 1;
+                       segs[1].x2 = 1;
+                       segs[1].y2 = height - 2;
+                       XDrawSegments(dpy, d, light, segs, 2);
+               }
+               break;
+#ifdef unused
+       case WREL_SUNKEN:
+               segs[0].x1 = 0;
+               segs[0].x2 = width - 1;
+               segs[0].y2 = segs[0].y1 = 0;
+               segs[1].x1 = segs[1].x2 = 0;
+               segs[1].y1 = 0;
+               segs[1].y2 = height - 1;
+               XDrawSegments(dpy, d, dark, segs, 2);
+
+               segs[0].x1 = 0;
+               segs[0].y1 = segs[0].y2 = height - 1;
+               segs[0].x2 = width - 1;
+               segs[1].x2 = segs[1].x1 = width - 1;
+               segs[1].y1 = 1;
+               segs[1].y2 = height - 1;
+               XDrawSegments(dpy, d, light, segs, 2);
+               break;
+#endif
+       }
+}