Files
wmaker/src/texture.c
T
Carlos R. Mafra e1d5ce7a51 Cleanup includes of wcore.h, defaults.h and pixmap.h
Several files were including others for no reason, and this slows
down the build time (but probably not measurable on a fast machine).
2010-03-17 11:12:53 +01:00

696 lines
17 KiB
C

/*
* 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 "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));
memset(&fallbackColor, 0, sizeof(fallbackColor));
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
}
}