1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-20 04:48:06 +01:00
Files
wmaker/src/texture.c
1999-03-18 05:41:00 +00:00

751 lines
18 KiB
C

/*
* Window Maker window manager
*
* Copyright (c) 1997, 1998 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 Pixmap renderTexture(WScreen *scr, int width, int height,
WTexture *texture, int rel);
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:
RDestroyImage(texture->pixmap.pixmap);
break;
case WTEX_MHGRADIENT:
case WTEX_MVGRADIENT:
case WTEX_MDGRADIENT:
for (i=0; texture->mgradient.colors[i]!=NULL; i++) {
free(texture->mgradient.colors[i]);
}
free(texture->mgradient.colors);
break;
case WTEX_THGRADIENT:
case WTEX_TVGRADIENT:
case WTEX_TDGRADIENT:
RDestroyImage(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++) {
free(texture->function.argv[i]);
}
free(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);
free(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;
}
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));
free(file);
return NULL;
}
free(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));
free(file);
return NULL;
}
free(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);
free(argv);
free(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);
free(argv);
dlclose(texture->handle);
free(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;
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_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) {
RDestroyImage(image);
image = NULL;
break;
}
RCombineImagesWithOpaqueness(image, grad,
texture->tgradient.opacity);
RDestroyImage(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);
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;
}
/* used only for menu entries */
void
wTextureRender(WScreen *scr, WTexture *texture, Pixmap *data,
int width, int height, int relief)
{
if (!texture)
return;
/*
switch (texture->any.type) {
case WTEX_DGRADIENT:
case WTEX_VGRADIENT:
case WTEX_HGRADIENT:
case WTEX_MHGRADIENT:
case WTEX_MVGRADIENT:
case WTEX_MDGRADIENT:
case WTEX_PIXMAP:
*/
if (!*data) {
*data = renderTexture(scr, width, height, texture, relief);
}/*
break;
}*/
}
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;
}
}
static Pixmap
renderTexture(WScreen *scr, int width, int height, WTexture *texture,
int rel)
{
RImage *img;
Pixmap pix;
img = wTextureRenderImage(texture, width, height, rel);
if (!img) {
wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
return None;
}
if (!RConvertImage(scr->rcontext, img, &pix)) {
wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
}
RDestroyImage(img);
return pix;
}
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
}
}