Updating to version 0.20.2
[wmaker-crm.git] / src / texture.c
blob0c93ea0f295b25d34efbbf1c02c1634c1243b102
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 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
31 #include <wraster.h>
33 #include "WindowMaker.h"
34 #include "wcore.h"
35 #include "texture.h"
36 #include "funcs.h"
38 extern WPreferences wPreferences;
41 static Pixmap renderTexture(WScreen *scr, int width, int height,
42 WTexture *texture, int rel);
45 static void bevelImage(RImage *image, int relief);
49 WTexSolid*
50 wTextureMakeSolid(WScreen *scr, XColor *color)
52 WTexSolid *texture;
53 int gcm;
54 XGCValues gcv;
56 texture = wmalloc(sizeof(WTexture));
58 texture->type = WTEX_SOLID;
59 texture->subtype = 0;
61 XAllocColor(dpy, scr->w_colormap, color);
62 texture->normal = *color;
63 if (color->red==0 && color->blue==0 && color->green == 0) {
64 texture->light.red = 0xb6da;
65 texture->light.green = 0xb6da;
66 texture->light.blue = 0xb6da;
67 texture->dim.red = 0x6185;
68 texture->dim.green = 0x6185;
69 texture->dim.blue = 0x6185;
70 } else {
71 RColor rgb;
72 RHSVColor hsv, hsv2;
73 int v;
75 rgb.red = color->red >> 8;
76 rgb.green = color->green >> 8;
77 rgb.blue = color->blue >> 8;
78 RRGBtoHSV(&rgb, &hsv);
79 RHSVtoRGB(&hsv, &rgb);
80 hsv2 = hsv;
82 v = hsv.value*16/10;
83 hsv.value = (v > 255 ? 255 : v);
84 RHSVtoRGB(&hsv, &rgb);
85 texture->light.red = rgb.red << 8;
86 texture->light.green = rgb.green << 8;
87 texture->light.blue = rgb.blue << 8;
89 hsv2.value = hsv2.value/2;
90 RHSVtoRGB(&hsv2, &rgb);
91 texture->dim.red = rgb.red << 8;
92 texture->dim.green = rgb.green << 8;
93 texture->dim.blue = rgb.blue << 8;
95 texture->dark.red = 0;
96 texture->dark.green = 0;
97 texture->dark.blue = 0;
98 XAllocColor(dpy, scr->w_colormap, &texture->light);
99 XAllocColor(dpy, scr->w_colormap, &texture->dim);
100 XAllocColor(dpy, scr->w_colormap, &texture->dark);
102 gcm = GCForeground|GCBackground|GCGraphicsExposures;
103 gcv.graphics_exposures = False;
105 gcv.background = gcv.foreground = texture->light.pixel;
106 texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
108 gcv.background = gcv.foreground = texture->dim.pixel;
109 texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
111 gcv.background = gcv.foreground = texture->dark.pixel;
112 texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
114 gcv.background = gcv.foreground = color->pixel;
115 texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
117 return texture;
121 static int
122 dummyErrorHandler(Display *foo, XErrorEvent *bar)
124 #ifdef DEBUG
125 wwarning("your server is buggy. Tell the author if some error related to color occurs");
126 #endif
127 return 0;
131 void
132 wTextureDestroy(WScreen *scr, WTexture *texture)
134 int i;
135 int count=0;
136 unsigned long colors[8];
138 #ifdef DEBUG
139 if (texture==NULL) {
140 printf("BUG: trying to free NULL texture\n");
141 return;
143 #endif
146 * some stupid servers don't like white or black being freed...
148 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel)
149 switch (texture->any.type) {
150 case WTEX_SOLID:
151 XFreeGC(dpy, texture->solid.light_gc);
152 XFreeGC(dpy, texture->solid.dark_gc);
153 XFreeGC(dpy, texture->solid.dim_gc);
154 if (CANFREE(texture->solid.light.pixel))
155 colors[count++] = texture->solid.light.pixel;
156 if (CANFREE(texture->solid.dim.pixel))
157 colors[count++] = texture->solid.dim.pixel;
158 if (CANFREE(texture->solid.dark.pixel))
159 colors[count++] = texture->solid.dark.pixel;
160 break;
162 case WTEX_PIXMAP:
163 RDestroyImage(texture->pixmap.pixmap);
164 break;
166 case WTEX_MHGRADIENT:
167 case WTEX_MVGRADIENT:
168 case WTEX_MDGRADIENT:
169 for (i=0; texture->mgradient.colors[i]!=NULL; i++) {
170 free(texture->mgradient.colors[i]);
172 free(texture->mgradient.colors);
173 break;
175 if (CANFREE(texture->any.color.pixel))
176 colors[count++] = texture->any.color.pixel;
177 if (count > 0) {
178 XErrorHandler oldhandler;
180 /* ignore error from buggy servers that don't know how
181 * to do reference counting for colors. */
182 oldhandler = XSetErrorHandler(dummyErrorHandler);
183 XFreeColors(dpy, scr->colormap, colors, count, 0);
184 XSync(dpy,0);
185 XSetErrorHandler(oldhandler);
187 XFreeGC(dpy, texture->any.gc);
188 free(texture);
189 #undef CANFREE
194 WTexGradient*
195 wTextureMakeGradient(WScreen *scr, int style, XColor *from, XColor *to)
197 WTexGradient *texture;
198 XGCValues gcv;
201 texture = wmalloc(sizeof(WTexture));
202 memset(texture, 0, sizeof(WTexture));
203 texture->type = style;
204 texture->subtype = 0;
206 texture->color1 = *from;
207 texture->color2 = *to;
209 texture->normal.red = (from->red + to->red)/2;
210 texture->normal.green = (from->green + to->green)/2;
211 texture->normal.blue = (from->blue + to->blue)/2;
213 XAllocColor(dpy, scr->w_colormap, &texture->normal);
214 gcv.background = gcv.foreground = texture->normal.pixel;
215 gcv.graphics_exposures = False;
216 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
217 |GCGraphicsExposures, &gcv);
219 return texture;
224 WTexMGradient*
225 wTextureMakeMGradient(WScreen *scr, int style, RColor **colors)
227 WTexMGradient *texture;
228 XGCValues gcv;
229 int i;
232 texture = wmalloc(sizeof(WTexture));
233 memset(texture, 0, sizeof(WTexture));
234 texture->type = style;
235 texture->subtype = 0;
237 i=0;
238 while (colors[i]!=NULL) i++;
239 i--;
240 texture->normal.red = (colors[0]->red<<8);
241 texture->normal.green = (colors[0]->green<<8);
242 texture->normal.blue = (colors[0]->blue<<8);
244 texture->colors = colors;
246 XAllocColor(dpy, scr->w_colormap, &texture->normal);
247 gcv.background = gcv.foreground = texture->normal.pixel;
248 gcv.graphics_exposures = False;
249 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
250 |GCGraphicsExposures, &gcv);
252 return texture;
257 WTexPixmap*
258 wTextureMakePixmap(WScreen *scr, int style, char *pixmap_file, XColor *color)
260 WTexPixmap *texture;
261 XGCValues gcv;
262 RImage *image;
263 char *file;
265 file = FindImage(wPreferences.pixmap_path, pixmap_file);
266 if (!file) {
267 wwarning(_("image file \"%s\" used as texture could not be found."),
268 pixmap_file);
269 return NULL;
271 image = RLoadImage(scr->rcontext, file, 0);
272 if (!image) {
273 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
274 RMessageForError(RErrorCode));
275 free(file);
276 return NULL;
278 free(file);
280 texture = wmalloc(sizeof(WTexture));
281 memset(texture, 0, sizeof(WTexture));
282 texture->type = WTEX_PIXMAP;
283 texture->subtype = style;
285 texture->normal = *color;
287 XAllocColor(dpy, scr->w_colormap, &texture->normal);
288 gcv.background = gcv.foreground = texture->normal.pixel;
289 gcv.graphics_exposures = False;
290 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
291 |GCGraphicsExposures, &gcv);
293 texture->pixmap = image;
295 return texture;
299 RImage*
300 wTextureRenderImage(WTexture *texture, int width, int height, int relief)
302 RImage *image;
303 RColor color1, color2;
304 int d;
305 int subtype;
307 switch (texture->any.type) {
308 case WTEX_SOLID:
309 image = RCreateImage(width, height, False);
311 color1.red = texture->solid.normal.red >> 8;
312 color1.green = texture->solid.normal.green >> 8;
313 color1.blue = texture->solid.normal.blue >> 8;
314 color1.alpha = 255;
316 RClearImage(image, &color1);
317 break;
319 case WTEX_PIXMAP:
320 if (texture->pixmap.subtype == WTP_TILE) {
321 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
322 } else if (texture->pixmap.subtype == WTP_CENTER) {
323 color1.red = texture->pixmap.normal.red>>8;
324 color1.green = texture->pixmap.normal.green>>8;
325 color1.blue = texture->pixmap.normal.blue>>8;
326 color1.alpha = 255;
327 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height,
328 &color1);
329 } else {
330 image = RScaleImage(texture->pixmap.pixmap, width, height);
332 break;
334 case WTEX_HGRADIENT:
335 subtype = RGRD_HORIZONTAL;
336 goto render_gradient;
338 case WTEX_VGRADIENT:
339 subtype = RGRD_VERTICAL;
340 goto render_gradient;
342 case WTEX_DGRADIENT:
343 subtype = RGRD_DIAGONAL;
344 render_gradient:
345 color1.red = texture->gradient.color1.red >> 8;
346 color1.green = texture->gradient.color1.green >> 8;
347 color1.blue = texture->gradient.color1.blue >> 8;
348 color2.red = texture->gradient.color2.red >> 8;
349 color2.green = texture->gradient.color2.green >> 8;
350 color2.blue = texture->gradient.color2.blue >> 8;
352 image = RRenderGradient(width, height, &color1, &color2, subtype);
353 break;
355 case WTEX_MHGRADIENT:
356 subtype = RGRD_HORIZONTAL;
357 goto render_mgradient;
359 case WTEX_MVGRADIENT:
360 subtype = RGRD_VERTICAL;
361 goto render_mgradient;
363 case WTEX_MDGRADIENT:
364 subtype = RGRD_DIAGONAL;
365 render_mgradient:
366 image = RRenderMultiGradient(width, height,
367 &(texture->mgradient.colors[1]),
368 subtype);
369 break;
371 default:
372 puts("ERROR in wTextureRenderImage()");
373 image = NULL;
376 if (!image) {
377 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
378 return None;
382 /* render bevel */
384 switch (relief) {
385 case WREL_ICON:
386 d = RBEV_RAISED3;
387 break;
389 case WREL_RAISED:
390 d = RBEV_RAISED2;
391 break;
393 case WREL_SUNKEN:
394 d = RBEV_SUNKEN;
395 break;
397 case WREL_FLAT:
398 d = 0;
399 break;
401 case WREL_MENUENTRY:
402 d = -WREL_MENUENTRY;
403 break;
405 default:
406 d = 0;
409 if (d > 0) {
410 RBevelImage(image, d);
411 } else if (d < 0) {
412 bevelImage(image, -d);
415 return image;
419 /* used only for menu entries */
420 void
421 wTextureRender(WScreen *scr, WTexture *texture, Pixmap *data,
422 int width, int height, int relief)
424 if (!texture)
425 return;
427 switch (texture->any.type) {
428 case WTEX_DGRADIENT:
429 case WTEX_VGRADIENT:
430 case WTEX_HGRADIENT:
431 case WTEX_MHGRADIENT:
432 case WTEX_MVGRADIENT:
433 case WTEX_MDGRADIENT:
434 case WTEX_PIXMAP:
436 if (!*data) {
437 *data = renderTexture(scr, width, height, texture, relief);
439 break;
445 static void
446 bevelImage(RImage *image, int relief)
448 int width = image->width;
449 int height = image->height;
450 RColor color;
452 switch (relief) {
453 case WREL_MENUENTRY:
454 color.red = color.green = color.blue = 80;
455 color.alpha = 0;
456 ROperateLine(image, RAddOperation, 1, 0, width-2, 0, &color);
458 ROperateLine(image, RAddOperation, 0, 0, 0, height-1, &color);
460 color.red = color.green = color.blue = 40;
461 color.alpha = 0;
462 ROperateLine(image, RSubtractOperation, width-1, 0, width-1,
463 height-1, &color);
465 ROperateLine(image, RSubtractOperation, 1, height-2, width-2,
466 height-2, &color);
468 color.red = color.green = color.blue = 0;
469 color.alpha = 255;
470 RDrawLine(image, 0, height-1, width-1, height-1, &color);
471 break;
478 static Pixmap
479 renderTexture(WScreen *scr, int width, int height, WTexture *texture,
480 int rel)
482 RImage *img;
483 Pixmap pix;
485 img = wTextureRenderImage(texture, width, height, rel);
487 if (!img) {
488 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
489 return None;
491 if (!RConvertImage(scr->rcontext, img, &pix)) {
492 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
494 RDestroyImage(img);
495 return pix;
499 void
500 wDrawBevel(Drawable d, unsigned width, unsigned height,
501 WTexSolid *texture, int relief)
503 GC light, dim, dark;
504 XSegment segs[4];
506 if (relief==WREL_FLAT) return;
508 light = texture->light_gc;
509 dim = texture->dim_gc;
510 dark = texture->dark_gc;
511 switch (relief) {
512 case WREL_FLAT:
513 return;
514 case WREL_MENUENTRY:
515 case WREL_RAISED:
516 case WREL_ICON:
517 segs[0].x1 = 1;
518 segs[0].x2 = width - 2;
519 segs[0].y2 = segs[0].y1 = height - 2;
520 segs[1].x1 = width - 2;
521 segs[1].y1 = 1;
522 segs[1].x2 = width - 2;
523 segs[1].y2 = height - 2;
524 XDrawSegments(dpy, d, dim, segs, 2);
525 segs[0].x1 = 0;
526 segs[0].x2 = width - 1;
527 segs[0].y2 = segs[0].y1 = height - 1;
528 segs[1].x1 = segs[1].x2 = width - 1;
529 segs[1].y1 = 0;
530 segs[1].y2 = height - 1;
531 XDrawSegments(dpy, d, dark, segs, 2);
532 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
533 segs[0].x2 = width - 2;
534 segs[1].x1 = segs[1].y1 = 0;
535 segs[1].x2 = 0;
536 segs[1].y2 = height - 2;
537 XDrawSegments(dpy, d, light, segs, 2);
538 if (relief==WREL_ICON) {
539 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
540 segs[0].x2 = width - 2;
541 segs[1].x1 = segs[1].y1 = 1;
542 segs[1].x2 = 1;
543 segs[1].y2 = height - 2;
544 XDrawSegments(dpy, d, light, segs, 2);
546 break;
547 #ifdef unused
548 case WREL_SUNKEN:
549 segs[0].x1 = 0;
550 segs[0].x2 = width - 1;
551 segs[0].y2 = segs[0].y1 = 0;
552 segs[1].x1 = segs[1].x2 = 0;
553 segs[1].y1 = 0;
554 segs[1].y2 = height - 1;
555 XDrawSegments(dpy, d, dark, segs, 2);
557 segs[0].x1 = 0;
558 segs[0].y1 = segs[0].y2 = height - 1;
559 segs[0].x2 = width - 1;
560 segs[1].x2 = segs[1].x1 = width - 1;
561 segs[1].y1 = 1;
562 segs[1].y2 = height - 1;
563 XDrawSegments(dpy, d, light, segs, 2);
564 break;
565 #endif