Code update for Window Maker version 0.50.0
[wmaker-crm.git] / src / texture.c
blobef95bdcdddfc5a6bc3eec2197cc1afd6d1b603bb
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 && c!=0)
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 case WTEX_THGRADIENT:
176 case WTEX_TVGRADIENT:
177 case WTEX_TDGRADIENT:
178 RDestroyImage(texture->tgradient.pixmap);
179 break;
181 if (CANFREE(texture->any.color.pixel))
182 colors[count++] = texture->any.color.pixel;
183 if (count > 0) {
184 XErrorHandler oldhandler;
186 /* ignore error from buggy servers that don't know how
187 * to do reference counting for colors. */
188 XSync(dpy,0);
189 oldhandler = XSetErrorHandler(dummyErrorHandler);
190 XFreeColors(dpy, scr->colormap, colors, count, 0);
191 XSync(dpy,0);
192 XSetErrorHandler(oldhandler);
194 XFreeGC(dpy, texture->any.gc);
195 free(texture);
196 #undef CANFREE
201 WTexGradient*
202 wTextureMakeGradient(WScreen *scr, int style, RColor *from, RColor *to)
204 WTexGradient *texture;
205 XGCValues gcv;
208 texture = wmalloc(sizeof(WTexture));
209 memset(texture, 0, sizeof(WTexture));
210 texture->type = style;
211 texture->subtype = 0;
213 texture->color1 = *from;
214 texture->color2 = *to;
216 texture->normal.red = (from->red + to->red)<<7;
217 texture->normal.green = (from->green + to->green)<<7;
218 texture->normal.blue = (from->blue + to->blue)<<7;
220 XAllocColor(dpy, scr->w_colormap, &texture->normal);
221 gcv.background = gcv.foreground = texture->normal.pixel;
222 gcv.graphics_exposures = False;
223 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
224 |GCGraphicsExposures, &gcv);
226 return texture;
231 WTexMGradient*
232 wTextureMakeMGradient(WScreen *scr, int style, RColor **colors)
234 WTexMGradient *texture;
235 XGCValues gcv;
236 int i;
239 texture = wmalloc(sizeof(WTexture));
240 memset(texture, 0, sizeof(WTexture));
241 texture->type = style;
242 texture->subtype = 0;
244 i=0;
245 while (colors[i]!=NULL) i++;
246 i--;
247 texture->normal.red = (colors[0]->red<<8);
248 texture->normal.green = (colors[0]->green<<8);
249 texture->normal.blue = (colors[0]->blue<<8);
251 texture->colors = colors;
253 XAllocColor(dpy, scr->w_colormap, &texture->normal);
254 gcv.background = gcv.foreground = texture->normal.pixel;
255 gcv.graphics_exposures = False;
256 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
257 |GCGraphicsExposures, &gcv);
259 return texture;
264 WTexPixmap*
265 wTextureMakePixmap(WScreen *scr, int style, char *pixmap_file, XColor *color)
267 WTexPixmap *texture;
268 XGCValues gcv;
269 RImage *image;
270 char *file;
272 file = FindImage(wPreferences.pixmap_path, pixmap_file);
273 if (!file) {
274 wwarning(_("image file \"%s\" used as texture could not be found."),
275 pixmap_file);
276 return NULL;
278 image = RLoadImage(scr->rcontext, file, 0);
279 if (!image) {
280 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
281 RMessageForError(RErrorCode));
282 free(file);
283 return NULL;
285 free(file);
287 texture = wmalloc(sizeof(WTexture));
288 memset(texture, 0, sizeof(WTexture));
289 texture->type = WTEX_PIXMAP;
290 texture->subtype = style;
292 texture->normal = *color;
294 XAllocColor(dpy, scr->w_colormap, &texture->normal);
295 gcv.background = gcv.foreground = texture->normal.pixel;
296 gcv.graphics_exposures = False;
297 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
298 |GCGraphicsExposures, &gcv);
300 texture->pixmap = image;
302 return texture;
307 WTexTGradient*
308 wTextureMakeTGradient(WScreen *scr, int style, RColor *from, RColor *to,
309 char *pixmap_file, int opacity)
311 WTexTGradient *texture;
312 XGCValues gcv;
313 RImage *image;
314 char *file;
316 file = FindImage(wPreferences.pixmap_path, pixmap_file);
317 if (!file) {
318 wwarning(_("image file \"%s\" used as texture could not be found."),
319 pixmap_file);
320 return NULL;
322 image = RLoadImage(scr->rcontext, file, 0);
323 if (!image) {
324 wwarning(_("could not load texture pixmap \"%s\":%s"), file,
325 RMessageForError(RErrorCode));
326 free(file);
327 return NULL;
329 free(file);
331 texture = wmalloc(sizeof(WTexture));
332 memset(texture, 0, sizeof(WTexture));
333 texture->type = style;
335 texture->opacity = opacity;
337 texture->color1 = *from;
338 texture->color2 = *to;
340 texture->normal.red = (from->red + to->red)<<7;
341 texture->normal.green = (from->green + to->green)<<7;
342 texture->normal.blue = (from->blue + to->blue)<<7;
344 XAllocColor(dpy, scr->w_colormap, &texture->normal);
345 gcv.background = gcv.foreground = texture->normal.pixel;
346 gcv.graphics_exposures = False;
347 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
348 |GCGraphicsExposures, &gcv);
350 texture->pixmap = image;
352 return texture;
357 RImage*
358 wTextureRenderImage(WTexture *texture, int width, int height, int relief)
360 RImage *image;
361 RColor color1;
362 int d;
363 int subtype;
365 switch (texture->any.type) {
366 case WTEX_SOLID:
367 image = RCreateImage(width, height, False);
369 color1.red = texture->solid.normal.red >> 8;
370 color1.green = texture->solid.normal.green >> 8;
371 color1.blue = texture->solid.normal.blue >> 8;
372 color1.alpha = 255;
374 RClearImage(image, &color1);
375 break;
377 case WTEX_PIXMAP:
378 if (texture->pixmap.subtype == WTP_TILE) {
379 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
380 } else if (texture->pixmap.subtype == WTP_CENTER) {
381 color1.red = texture->pixmap.normal.red>>8;
382 color1.green = texture->pixmap.normal.green>>8;
383 color1.blue = texture->pixmap.normal.blue>>8;
384 color1.alpha = 255;
385 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height,
386 &color1);
387 } else {
388 image = RScaleImage(texture->pixmap.pixmap, width, height);
390 break;
392 case WTEX_HGRADIENT:
393 subtype = RGRD_HORIZONTAL;
394 goto render_gradient;
396 case WTEX_VGRADIENT:
397 subtype = RGRD_VERTICAL;
398 goto render_gradient;
400 case WTEX_DGRADIENT:
401 subtype = RGRD_DIAGONAL;
402 render_gradient:
404 image = RRenderGradient(width, height, &texture->gradient.color1,
405 &texture->gradient.color2, subtype);
406 break;
408 case WTEX_MHGRADIENT:
409 subtype = RGRD_HORIZONTAL;
410 goto render_mgradient;
412 case WTEX_MVGRADIENT:
413 subtype = RGRD_VERTICAL;
414 goto render_mgradient;
416 case WTEX_MDGRADIENT:
417 subtype = RGRD_DIAGONAL;
418 render_mgradient:
419 image = RRenderMultiGradient(width, height,
420 &(texture->mgradient.colors[1]),
421 subtype);
422 break;
424 case WTEX_THGRADIENT:
425 subtype = RGRD_HORIZONTAL;
426 goto render_tgradient;
428 case WTEX_TVGRADIENT:
429 subtype = RGRD_VERTICAL;
430 goto render_tgradient;
432 case WTEX_TDGRADIENT:
433 subtype = RGRD_DIAGONAL;
434 render_tgradient:
436 RImage *grad;
438 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
439 if (!image)
440 break;
442 grad = RRenderGradient(width, height, &texture->tgradient.color1,
443 &texture->tgradient.color2, subtype);
444 if (!grad) {
445 RDestroyImage(image);
446 image = NULL;
447 break;
450 RCombineImagesWithOpaqueness(image, grad,
451 texture->tgradient.opacity);
452 RDestroyImage(grad);
454 break;
456 default:
457 puts("ERROR in wTextureRenderImage()");
458 image = NULL;
459 break;
462 if (!image) {
463 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
464 return None;
468 /* render bevel */
470 switch (relief) {
471 case WREL_ICON:
472 d = RBEV_RAISED3;
473 break;
475 case WREL_RAISED:
476 d = RBEV_RAISED2;
477 break;
479 case WREL_SUNKEN:
480 d = RBEV_SUNKEN;
481 break;
483 case WREL_FLAT:
484 d = 0;
485 break;
487 case WREL_MENUENTRY:
488 d = -WREL_MENUENTRY;
489 break;
491 default:
492 d = 0;
495 if (d > 0) {
496 RBevelImage(image, d);
497 } else if (d < 0) {
498 bevelImage(image, -d);
501 return image;
505 /* used only for menu entries */
506 void
507 wTextureRender(WScreen *scr, WTexture *texture, Pixmap *data,
508 int width, int height, int relief)
510 if (!texture)
511 return;
513 switch (texture->any.type) {
514 case WTEX_DGRADIENT:
515 case WTEX_VGRADIENT:
516 case WTEX_HGRADIENT:
517 case WTEX_MHGRADIENT:
518 case WTEX_MVGRADIENT:
519 case WTEX_MDGRADIENT:
520 case WTEX_PIXMAP:
522 if (!*data) {
523 *data = renderTexture(scr, width, height, texture, relief);
525 break;
531 static void
532 bevelImage(RImage *image, int relief)
534 int width = image->width;
535 int height = image->height;
536 RColor color;
538 switch (relief) {
539 case WREL_MENUENTRY:
540 color.red = color.green = color.blue = 80;
541 color.alpha = 0;
542 ROperateLine(image, RAddOperation, 1, 0, width-2, 0, &color);
544 ROperateLine(image, RAddOperation, 0, 0, 0, height-1, &color);
546 color.red = color.green = color.blue = 40;
547 color.alpha = 0;
548 ROperateLine(image, RSubtractOperation, width-1, 0, width-1,
549 height-1, &color);
551 ROperateLine(image, RSubtractOperation, 1, height-2, width-2,
552 height-2, &color);
554 color.red = color.green = color.blue = 0;
555 color.alpha = 255;
556 RDrawLine(image, 0, height-1, width-1, height-1, &color);
557 break;
564 static Pixmap
565 renderTexture(WScreen *scr, int width, int height, WTexture *texture,
566 int rel)
568 RImage *img;
569 Pixmap pix;
571 img = wTextureRenderImage(texture, width, height, rel);
573 if (!img) {
574 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
575 return None;
577 if (!RConvertImage(scr->rcontext, img, &pix)) {
578 wwarning(_("error rendering image:%s"), RMessageForError(RErrorCode));
580 RDestroyImage(img);
581 return pix;
585 void
586 wDrawBevel(Drawable d, unsigned width, unsigned height,
587 WTexSolid *texture, int relief)
589 GC light, dim, dark;
590 XSegment segs[4];
592 if (relief==WREL_FLAT) return;
594 light = texture->light_gc;
595 dim = texture->dim_gc;
596 dark = texture->dark_gc;
597 switch (relief) {
598 case WREL_FLAT:
599 return;
600 case WREL_MENUENTRY:
601 case WREL_RAISED:
602 case WREL_ICON:
603 segs[0].x1 = 1;
604 segs[0].x2 = width - 2;
605 segs[0].y2 = segs[0].y1 = height - 2;
606 segs[1].x1 = width - 2;
607 segs[1].y1 = 1;
608 segs[1].x2 = width - 2;
609 segs[1].y2 = height - 2;
610 XDrawSegments(dpy, d, dim, segs, 2);
611 segs[0].x1 = 0;
612 segs[0].x2 = width - 1;
613 segs[0].y2 = segs[0].y1 = height - 1;
614 segs[1].x1 = segs[1].x2 = width - 1;
615 segs[1].y1 = 0;
616 segs[1].y2 = height - 1;
617 XDrawSegments(dpy, d, dark, segs, 2);
618 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
619 segs[0].x2 = width - 2;
620 segs[1].x1 = segs[1].y1 = 0;
621 segs[1].x2 = 0;
622 segs[1].y2 = height - 2;
623 XDrawSegments(dpy, d, light, segs, 2);
624 if (relief==WREL_ICON) {
625 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
626 segs[0].x2 = width - 2;
627 segs[1].x1 = segs[1].y1 = 1;
628 segs[1].x2 = 1;
629 segs[1].y2 = height - 2;
630 XDrawSegments(dpy, d, light, segs, 2);
632 break;
633 #ifdef unused
634 case WREL_SUNKEN:
635 segs[0].x1 = 0;
636 segs[0].x2 = width - 1;
637 segs[0].y2 = segs[0].y1 = 0;
638 segs[1].x1 = segs[1].x2 = 0;
639 segs[1].y1 = 0;
640 segs[1].y2 = height - 1;
641 XDrawSegments(dpy, d, dark, segs, 2);
643 segs[0].x1 = 0;
644 segs[0].y1 = segs[0].y2 = height - 1;
645 segs[0].x2 = width - 1;
646 segs[1].x2 = segs[1].x1 = width - 1;
647 segs[1].y1 = 1;
648 segs[1].y2 = height - 1;
649 XDrawSegments(dpy, d, light, segs, 2);
650 break;
651 #endif