WPrefs: set default to 1st color in gradient texture
[wmaker-crm.git] / src / texture.c
blobc73c85a00f972ed702c2dc0f20436c690f850480
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
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 along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "wconfig.h"
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include <wraster.h>
32 #include "WindowMaker.h"
33 #include "texture.h"
34 #include "window.h"
35 #include "misc.h"
38 static void bevelImage(RImage * image, int relief);
39 static RImage * get_texture_image(WScreen *scr, const char *pixmap_file);
41 WTexSolid *wTextureMakeSolid(WScreen * scr, XColor * color)
43 WTexSolid *texture;
44 int gcm;
45 XGCValues gcv;
47 texture = wmalloc(sizeof(WTexture));
49 texture->type = WTEX_SOLID;
50 texture->subtype = 0;
52 XAllocColor(dpy, scr->w_colormap, color);
53 texture->normal = *color;
54 if (color->red == 0 && color->blue == 0 && color->green == 0) {
55 texture->light.red = 0xb6da;
56 texture->light.green = 0xb6da;
57 texture->light.blue = 0xb6da;
58 texture->dim.red = 0x6185;
59 texture->dim.green = 0x6185;
60 texture->dim.blue = 0x6185;
61 } else {
62 RColor rgb;
63 RHSVColor hsv, hsv2;
64 int v;
66 rgb.red = color->red >> 8;
67 rgb.green = color->green >> 8;
68 rgb.blue = color->blue >> 8;
69 RRGBtoHSV(&rgb, &hsv);
70 RHSVtoRGB(&hsv, &rgb);
71 hsv2 = hsv;
73 v = hsv.value * 16 / 10;
74 hsv.value = (v > 255 ? 255 : v);
75 RHSVtoRGB(&hsv, &rgb);
76 texture->light.red = rgb.red << 8;
77 texture->light.green = rgb.green << 8;
78 texture->light.blue = rgb.blue << 8;
80 hsv2.value = hsv2.value / 2;
81 RHSVtoRGB(&hsv2, &rgb);
82 texture->dim.red = rgb.red << 8;
83 texture->dim.green = rgb.green << 8;
84 texture->dim.blue = rgb.blue << 8;
86 texture->dark.red = 0;
87 texture->dark.green = 0;
88 texture->dark.blue = 0;
89 XAllocColor(dpy, scr->w_colormap, &texture->light);
90 XAllocColor(dpy, scr->w_colormap, &texture->dim);
91 XAllocColor(dpy, scr->w_colormap, &texture->dark);
93 gcm = GCForeground | GCBackground | GCGraphicsExposures;
94 gcv.graphics_exposures = False;
96 gcv.background = gcv.foreground = texture->light.pixel;
97 texture->light_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
99 gcv.background = gcv.foreground = texture->dim.pixel;
100 texture->dim_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
102 gcv.background = gcv.foreground = texture->dark.pixel;
103 texture->dark_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
105 gcv.background = gcv.foreground = color->pixel;
106 texture->normal_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
108 return texture;
111 static int dummyErrorHandler(Display * foo, XErrorEvent * bar)
113 /* Parameter not used, but tell the compiler that it is ok */
114 (void) foo;
115 (void) bar;
117 return 0;
120 void wTextureDestroy(WScreen * scr, WTexture * texture)
122 int i;
123 int count = 0;
124 unsigned long colors[8];
127 * some stupid servers don't like white or black being freed...
129 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
130 switch (texture->any.type) {
131 case WTEX_SOLID:
132 XFreeGC(dpy, texture->solid.light_gc);
133 XFreeGC(dpy, texture->solid.dark_gc);
134 XFreeGC(dpy, texture->solid.dim_gc);
135 if (CANFREE(texture->solid.light.pixel))
136 colors[count++] = texture->solid.light.pixel;
137 if (CANFREE(texture->solid.dim.pixel))
138 colors[count++] = texture->solid.dim.pixel;
139 if (CANFREE(texture->solid.dark.pixel))
140 colors[count++] = texture->solid.dark.pixel;
141 break;
143 case WTEX_PIXMAP:
144 RReleaseImage(texture->pixmap.pixmap);
145 break;
147 case WTEX_MHGRADIENT:
148 case WTEX_MVGRADIENT:
149 case WTEX_MDGRADIENT:
150 for (i = 0; texture->mgradient.colors[i] != NULL; i++) {
151 wfree(texture->mgradient.colors[i]);
153 wfree(texture->mgradient.colors);
154 break;
156 case WTEX_THGRADIENT:
157 case WTEX_TVGRADIENT:
158 case WTEX_TDGRADIENT:
159 RReleaseImage(texture->tgradient.pixmap);
160 break;
163 if (CANFREE(texture->any.color.pixel))
164 colors[count++] = texture->any.color.pixel;
165 if (count > 0) {
166 XErrorHandler oldhandler;
168 /* ignore error from buggy servers that don't know how
169 * to do reference counting for colors. */
170 XSync(dpy, 0);
171 oldhandler = XSetErrorHandler(dummyErrorHandler);
172 XFreeColors(dpy, scr->w_colormap, colors, count, 0);
173 XSync(dpy, 0);
174 XSetErrorHandler(oldhandler);
176 XFreeGC(dpy, texture->any.gc);
177 wfree(texture);
178 #undef CANFREE
181 WTexGradient *wTextureMakeGradient(WScreen *scr, int style, const RColor *from, const RColor *to)
183 WTexGradient *texture;
184 XGCValues gcv;
186 texture = wmalloc(sizeof(WTexture));
187 texture->type = style;
188 texture->subtype = 0;
190 texture->color1 = *from;
191 texture->color2 = *to;
193 texture->normal.red = (from->red + to->red) << 7;
194 texture->normal.green = (from->green + to->green) << 7;
195 texture->normal.blue = (from->blue + to->blue) << 7;
197 XAllocColor(dpy, scr->w_colormap, &texture->normal);
198 gcv.background = gcv.foreground = texture->normal.pixel;
199 gcv.graphics_exposures = False;
200 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
202 return texture;
205 WTexIGradient *wTextureMakeIGradient(WScreen *scr, int thickness1, const RColor colors1[2],
206 int thickness2, const RColor colors2[2])
208 WTexIGradient *texture;
209 XGCValues gcv;
210 int i;
212 texture = wmalloc(sizeof(WTexture));
213 texture->type = WTEX_IGRADIENT;
214 for (i = 0; i < 2; i++) {
215 texture->colors1[i] = colors1[i];
216 texture->colors2[i] = colors2[i];
218 texture->thickness1 = thickness1;
219 texture->thickness2 = thickness2;
220 if (thickness1 >= thickness2) {
221 texture->normal.red = (colors1[0].red + colors1[1].red) << 7;
222 texture->normal.green = (colors1[0].green + colors1[1].green) << 7;
223 texture->normal.blue = (colors1[0].blue + colors1[1].blue) << 7;
224 } else {
225 texture->normal.red = (colors2[0].red + colors2[1].red) << 7;
226 texture->normal.green = (colors2[0].green + colors2[1].green) << 7;
227 texture->normal.blue = (colors2[0].blue + colors2[1].blue) << 7;
229 XAllocColor(dpy, scr->w_colormap, &texture->normal);
230 gcv.background = gcv.foreground = texture->normal.pixel;
231 gcv.graphics_exposures = False;
232 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
234 return texture;
237 WTexMGradient *wTextureMakeMGradient(WScreen * scr, int style, RColor ** colors)
239 WTexMGradient *texture;
240 XGCValues gcv;
241 int i;
243 texture = wmalloc(sizeof(WTexture));
244 texture->type = style;
245 texture->subtype = 0;
247 i = 0;
248 while (colors[i] != NULL)
249 i++;
250 i--;
251 texture->normal.red = (colors[0]->red << 8);
252 texture->normal.green = (colors[0]->green << 8);
253 texture->normal.blue = (colors[0]->blue << 8);
255 texture->colors = colors;
257 XAllocColor(dpy, scr->w_colormap, &texture->normal);
258 gcv.background = gcv.foreground = texture->normal.pixel;
259 gcv.graphics_exposures = False;
260 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
262 return texture;
265 WTexPixmap *wTextureMakePixmap(WScreen *scr, int style, const char *pixmap_file, XColor *color)
267 WTexPixmap *texture;
268 XGCValues gcv;
269 RImage *image;
271 image = get_texture_image(scr, pixmap_file);
272 if (!image)
273 return NULL;
275 texture = wmalloc(sizeof(WTexture));
276 texture->type = WTEX_PIXMAP;
277 texture->subtype = style;
279 texture->normal = *color;
281 XAllocColor(dpy, scr->w_colormap, &texture->normal);
282 gcv.background = gcv.foreground = texture->normal.pixel;
283 gcv.graphics_exposures = False;
284 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
286 texture->pixmap = image;
288 return texture;
291 WTexTGradient *wTextureMakeTGradient(WScreen *scr, int style, const RColor *from, const RColor *to,
292 const char *pixmap_file, int opacity)
294 WTexTGradient *texture;
295 XGCValues gcv;
296 RImage *image;
298 image = get_texture_image(scr, pixmap_file);
299 if (!image)
300 return NULL;
302 texture = wmalloc(sizeof(WTexture));
303 texture->type = style;
305 texture->opacity = opacity;
307 texture->color1 = *from;
308 texture->color2 = *to;
310 texture->normal.red = (from->red + to->red) << 7;
311 texture->normal.green = (from->green + to->green) << 7;
312 texture->normal.blue = (from->blue + to->blue) << 7;
314 XAllocColor(dpy, scr->w_colormap, &texture->normal);
315 gcv.background = gcv.foreground = texture->normal.pixel;
316 gcv.graphics_exposures = False;
317 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
319 texture->pixmap = image;
321 return texture;
324 static RImage * get_texture_image(WScreen *scr, const char *pixmap_file)
326 char *file;
327 RImage *image;
329 file = FindImage(wPreferences.pixmap_path, pixmap_file);
330 if (!file) {
331 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
332 return NULL;
334 image = RLoadImage(scr->rcontext, file, 0);
335 if (!image) {
336 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
337 wfree(file);
338 return NULL;
340 wfree(file);
342 return image;
345 RImage *wTextureRenderImage(WTexture * texture, int width, int height, int relief)
347 RImage *image = NULL;
348 RColor color1;
349 int d;
350 int subtype;
352 switch (texture->any.type) {
353 case WTEX_SOLID:
354 image = RCreateImage(width, height, False);
356 color1.red = texture->solid.normal.red >> 8;
357 color1.green = texture->solid.normal.green >> 8;
358 color1.blue = texture->solid.normal.blue >> 8;
359 color1.alpha = 255;
361 RClearImage(image, &color1);
362 break;
364 case WTEX_PIXMAP:
365 if (texture->pixmap.subtype == WTP_TILE) {
366 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
367 } else if (texture->pixmap.subtype == WTP_CENTER) {
368 color1.red = texture->pixmap.normal.red >> 8;
369 color1.green = texture->pixmap.normal.green >> 8;
370 color1.blue = texture->pixmap.normal.blue >> 8;
371 color1.alpha = 255;
372 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height, &color1);
373 } else {
374 image = RScaleImage(texture->pixmap.pixmap, width, height);
376 break;
378 case WTEX_IGRADIENT:
379 image = RRenderInterwovenGradient(width, height,
380 texture->igradient.colors1,
381 texture->igradient.thickness1,
382 texture->igradient.colors2, texture->igradient.thickness2);
383 break;
385 case WTEX_HGRADIENT:
386 subtype = RGRD_HORIZONTAL;
387 goto render_gradient;
389 case WTEX_VGRADIENT:
390 subtype = RGRD_VERTICAL;
391 goto render_gradient;
393 case WTEX_DGRADIENT:
394 subtype = RGRD_DIAGONAL;
395 render_gradient:
397 image = RRenderGradient(width, height, &texture->gradient.color1,
398 &texture->gradient.color2, subtype);
399 break;
401 case WTEX_MHGRADIENT:
402 subtype = RGRD_HORIZONTAL;
403 goto render_mgradient;
405 case WTEX_MVGRADIENT:
406 subtype = RGRD_VERTICAL;
407 goto render_mgradient;
409 case WTEX_MDGRADIENT:
410 subtype = RGRD_DIAGONAL;
411 render_mgradient:
412 image = RRenderMultiGradient(width, height, &(texture->mgradient.colors[1]), subtype);
413 break;
415 case WTEX_THGRADIENT:
416 subtype = RGRD_HORIZONTAL;
417 goto render_tgradient;
419 case WTEX_TVGRADIENT:
420 subtype = RGRD_VERTICAL;
421 goto render_tgradient;
423 case WTEX_TDGRADIENT:
424 subtype = RGRD_DIAGONAL;
425 render_tgradient:
427 RImage *grad;
429 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
430 if (!image)
431 break;
433 grad = RRenderGradient(width, height, &texture->tgradient.color1,
434 &texture->tgradient.color2, subtype);
435 if (!grad) {
436 RReleaseImage(image);
437 image = NULL;
438 break;
441 RCombineImagesWithOpaqueness(image, grad, texture->tgradient.opacity);
442 RReleaseImage(grad);
444 break;
445 default:
446 puts("ERROR in wTextureRenderImage()");
447 image = NULL;
448 break;
451 if (!image) {
452 RColor gray;
454 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
456 image = RCreateImage(width, height, False);
457 if (image == NULL) {
458 wwarning(_("could not allocate image buffer"));
459 return NULL;
462 gray.red = 190;
463 gray.green = 190;
464 gray.blue = 190;
465 gray.alpha = 255;
466 RClearImage(image, &gray);
469 /* render bevel */
471 switch (relief) {
472 case WREL_ICON:
473 d = RBEV_RAISED3;
474 break;
476 case WREL_RAISED:
477 d = RBEV_RAISED2;
478 break;
480 case WREL_SUNKEN:
481 d = RBEV_SUNKEN;
482 break;
484 case WREL_FLAT:
485 d = 0;
486 break;
488 case WREL_MENUENTRY:
489 d = -WREL_MENUENTRY;
490 break;
492 default:
493 d = 0;
496 if (d > 0) {
497 RBevelImage(image, d);
498 } else if (d < 0) {
499 bevelImage(image, -d);
502 return image;
505 static void bevelImage(RImage * image, int relief)
507 int width = image->width;
508 int height = image->height;
509 RColor color;
511 switch (relief) {
512 case WREL_MENUENTRY:
513 color.red = color.green = color.blue = 80;
514 color.alpha = 0;
515 /**/ ROperateLine(image, RAddOperation, 1, 0, width - 2, 0, &color);
516 /**/ ROperateLine(image, RAddOperation, 0, 0, 0, height - 1, &color);
518 color.red = color.green = color.blue = 40;
519 color.alpha = 0;
520 ROperateLine(image, RSubtractOperation, width - 1, 0, width - 1, height - 1, &color);
522 /**/ ROperateLine(image, RSubtractOperation, 1, height - 2, width - 2, height - 2, &color);
524 color.red = color.green = color.blue = 0;
525 color.alpha = 255;
526 RDrawLine(image, 0, height - 1, width - 1, height - 1, &color);
527 /**/ break;
532 void wDrawBevel(Drawable d, unsigned width, unsigned height, WTexSolid * texture, int relief)
534 GC light, dim, dark;
535 XSegment segs[4];
537 if (relief == WREL_FLAT)
538 return;
540 light = texture->light_gc;
541 dim = texture->dim_gc;
542 dark = texture->dark_gc;
543 switch (relief) {
544 case WREL_FLAT:
545 return;
546 case WREL_MENUENTRY:
547 case WREL_RAISED:
548 case WREL_ICON:
549 segs[0].x1 = 1;
550 segs[0].x2 = width - 2;
551 segs[0].y2 = segs[0].y1 = height - 2;
552 segs[1].x1 = width - 2;
553 segs[1].y1 = 1;
554 segs[1].x2 = width - 2;
555 segs[1].y2 = height - 2;
556 if (wPreferences.new_style == TS_NEXT) {
557 XDrawSegments(dpy, d, dark, segs, 2);
558 } else {
559 XDrawSegments(dpy, d, dim, segs, 2);
561 segs[0].x1 = 0;
562 segs[0].x2 = width - 1;
563 segs[0].y2 = segs[0].y1 = height - 1;
564 segs[1].x1 = segs[1].x2 = width - 1;
565 segs[1].y1 = 0;
566 segs[1].y2 = height - 1;
567 if (wPreferences.new_style == TS_NEXT) {
568 XDrawSegments(dpy, d, light, segs, 2);
569 } else {
570 XDrawSegments(dpy, d, dark, segs, 2);
572 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
573 segs[0].x2 = width - 2;
574 segs[1].x1 = segs[1].y1 = 0;
575 segs[1].x2 = 0;
576 segs[1].y2 = height - 2;
577 if (wPreferences.new_style == TS_NEXT) {
578 XDrawSegments(dpy, d, dark, segs, 2);
579 } else {
580 XDrawSegments(dpy, d, light, segs, 2);
582 if (relief == WREL_ICON) {
583 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
584 segs[0].x2 = width - 2;
585 segs[1].x1 = segs[1].y1 = 1;
586 segs[1].x2 = 1;
587 segs[1].y2 = height - 2;
588 XDrawSegments(dpy, d, light, segs, 2);
590 break;