Avoid icon change to default on winspector save
[wmaker-crm.git] / src / texture.c
bloba29406a30c8d55c8d14bdb25018e809e00dbe540
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 "funcs.h"
36 extern WPreferences wPreferences;
38 static void bevelImage(RImage * image, int relief);
39 static RImage * get_texture_image(WScreen *scr, 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 return 0;
116 void wTextureDestroy(WScreen * scr, WTexture * texture)
118 int i;
119 int count = 0;
120 unsigned long colors[8];
123 * some stupid servers don't like white or black being freed...
125 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
126 switch (texture->any.type) {
127 case WTEX_SOLID:
128 XFreeGC(dpy, texture->solid.light_gc);
129 XFreeGC(dpy, texture->solid.dark_gc);
130 XFreeGC(dpy, texture->solid.dim_gc);
131 if (CANFREE(texture->solid.light.pixel))
132 colors[count++] = texture->solid.light.pixel;
133 if (CANFREE(texture->solid.dim.pixel))
134 colors[count++] = texture->solid.dim.pixel;
135 if (CANFREE(texture->solid.dark.pixel))
136 colors[count++] = texture->solid.dark.pixel;
137 break;
139 case WTEX_PIXMAP:
140 RReleaseImage(texture->pixmap.pixmap);
141 break;
143 case WTEX_MHGRADIENT:
144 case WTEX_MVGRADIENT:
145 case WTEX_MDGRADIENT:
146 for (i = 0; texture->mgradient.colors[i] != NULL; i++) {
147 wfree(texture->mgradient.colors[i]);
149 wfree(texture->mgradient.colors);
150 break;
152 case WTEX_THGRADIENT:
153 case WTEX_TVGRADIENT:
154 case WTEX_TDGRADIENT:
155 RReleaseImage(texture->tgradient.pixmap);
156 break;
159 if (CANFREE(texture->any.color.pixel))
160 colors[count++] = texture->any.color.pixel;
161 if (count > 0) {
162 XErrorHandler oldhandler;
164 /* ignore error from buggy servers that don't know how
165 * to do reference counting for colors. */
166 XSync(dpy, 0);
167 oldhandler = XSetErrorHandler(dummyErrorHandler);
168 XFreeColors(dpy, scr->w_colormap, colors, count, 0);
169 XSync(dpy, 0);
170 XSetErrorHandler(oldhandler);
172 XFreeGC(dpy, texture->any.gc);
173 wfree(texture);
174 #undef CANFREE
177 WTexGradient *wTextureMakeGradient(WScreen * scr, int style, RColor * from, RColor * to)
179 WTexGradient *texture;
180 XGCValues gcv;
182 texture = wmalloc(sizeof(WTexture));
183 texture->type = style;
184 texture->subtype = 0;
186 texture->color1 = *from;
187 texture->color2 = *to;
189 texture->normal.red = (from->red + to->red) << 7;
190 texture->normal.green = (from->green + to->green) << 7;
191 texture->normal.blue = (from->blue + to->blue) << 7;
193 XAllocColor(dpy, scr->w_colormap, &texture->normal);
194 gcv.background = gcv.foreground = texture->normal.pixel;
195 gcv.graphics_exposures = False;
196 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
198 return texture;
201 WTexIGradient *wTextureMakeIGradient(WScreen * scr, int thickness1, RColor colors1[2],
202 int thickness2, RColor colors2[2])
204 WTexIGradient *texture;
205 XGCValues gcv;
206 int i;
208 texture = wmalloc(sizeof(WTexture));
209 texture->type = WTEX_IGRADIENT;
210 for (i = 0; i < 2; i++) {
211 texture->colors1[i] = colors1[i];
212 texture->colors2[i] = colors2[i];
214 texture->thickness1 = thickness1;
215 texture->thickness2 = thickness2;
216 if (thickness1 >= thickness2) {
217 texture->normal.red = (colors1[0].red + colors1[1].red) << 7;
218 texture->normal.green = (colors1[0].green + colors1[1].green) << 7;
219 texture->normal.blue = (colors1[0].blue + colors1[1].blue) << 7;
220 } else {
221 texture->normal.red = (colors2[0].red + colors2[1].red) << 7;
222 texture->normal.green = (colors2[0].green + colors2[1].green) << 7;
223 texture->normal.blue = (colors2[0].blue + colors2[1].blue) << 7;
225 XAllocColor(dpy, scr->w_colormap, &texture->normal);
226 gcv.background = gcv.foreground = texture->normal.pixel;
227 gcv.graphics_exposures = False;
228 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
230 return texture;
233 WTexMGradient *wTextureMakeMGradient(WScreen * scr, int style, RColor ** colors)
235 WTexMGradient *texture;
236 XGCValues gcv;
237 int i;
239 texture = wmalloc(sizeof(WTexture));
240 texture->type = style;
241 texture->subtype = 0;
243 i = 0;
244 while (colors[i] != NULL)
245 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 | GCGraphicsExposures, &gcv);
258 return texture;
261 WTexPixmap *wTextureMakePixmap(WScreen * scr, int style, char *pixmap_file, XColor * color)
263 WTexPixmap *texture;
264 XGCValues gcv;
265 RImage *image;
267 image = get_texture_image(scr, pixmap_file);
268 if (!image)
269 return NULL;
271 texture = wmalloc(sizeof(WTexture));
272 texture->type = WTEX_PIXMAP;
273 texture->subtype = style;
275 texture->normal = *color;
277 XAllocColor(dpy, scr->w_colormap, &texture->normal);
278 gcv.background = gcv.foreground = texture->normal.pixel;
279 gcv.graphics_exposures = False;
280 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
282 texture->pixmap = image;
284 return texture;
287 WTexTGradient *wTextureMakeTGradient(WScreen * scr, int style, RColor * from, RColor * to,
288 char *pixmap_file, int opacity)
290 WTexTGradient *texture;
291 XGCValues gcv;
292 RImage *image;
294 image = get_texture_image(scr, pixmap_file);
295 if (!image)
296 return NULL;
298 texture = wmalloc(sizeof(WTexture));
299 texture->type = style;
301 texture->opacity = opacity;
303 texture->color1 = *from;
304 texture->color2 = *to;
306 texture->normal.red = (from->red + to->red) << 7;
307 texture->normal.green = (from->green + to->green) << 7;
308 texture->normal.blue = (from->blue + to->blue) << 7;
310 XAllocColor(dpy, scr->w_colormap, &texture->normal);
311 gcv.background = gcv.foreground = texture->normal.pixel;
312 gcv.graphics_exposures = False;
313 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
315 texture->pixmap = image;
317 return texture;
320 static RImage * get_texture_image(WScreen *scr, char *pixmap_file)
322 char *file;
323 RImage *image;
325 file = FindImage(wPreferences.pixmap_path, pixmap_file);
326 if (!file) {
327 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
328 return NULL;
330 image = RLoadImage(scr->rcontext, file, 0);
331 if (!image) {
332 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
333 wfree(file);
334 return NULL;
336 wfree(file);
338 return image;
341 RImage *wTextureRenderImage(WTexture * texture, int width, int height, int relief)
343 RImage *image = NULL;
344 RColor color1;
345 int d;
346 int subtype;
348 switch (texture->any.type) {
349 case WTEX_SOLID:
350 image = RCreateImage(width, height, False);
352 color1.red = texture->solid.normal.red >> 8;
353 color1.green = texture->solid.normal.green >> 8;
354 color1.blue = texture->solid.normal.blue >> 8;
355 color1.alpha = 255;
357 RClearImage(image, &color1);
358 break;
360 case WTEX_PIXMAP:
361 if (texture->pixmap.subtype == WTP_TILE) {
362 image = RMakeTiledImage(texture->pixmap.pixmap, width, height);
363 } else if (texture->pixmap.subtype == WTP_CENTER) {
364 color1.red = texture->pixmap.normal.red >> 8;
365 color1.green = texture->pixmap.normal.green >> 8;
366 color1.blue = texture->pixmap.normal.blue >> 8;
367 color1.alpha = 255;
368 image = RMakeCenteredImage(texture->pixmap.pixmap, width, height, &color1);
369 } else {
370 image = RScaleImage(texture->pixmap.pixmap, width, height);
372 break;
374 case WTEX_IGRADIENT:
375 image = RRenderInterwovenGradient(width, height,
376 texture->igradient.colors1,
377 texture->igradient.thickness1,
378 texture->igradient.colors2, texture->igradient.thickness2);
379 break;
381 case WTEX_HGRADIENT:
382 subtype = RGRD_HORIZONTAL;
383 goto render_gradient;
385 case WTEX_VGRADIENT:
386 subtype = RGRD_VERTICAL;
387 goto render_gradient;
389 case WTEX_DGRADIENT:
390 subtype = RGRD_DIAGONAL;
391 render_gradient:
393 image = RRenderGradient(width, height, &texture->gradient.color1,
394 &texture->gradient.color2, subtype);
395 break;
397 case WTEX_MHGRADIENT:
398 subtype = RGRD_HORIZONTAL;
399 goto render_mgradient;
401 case WTEX_MVGRADIENT:
402 subtype = RGRD_VERTICAL;
403 goto render_mgradient;
405 case WTEX_MDGRADIENT:
406 subtype = RGRD_DIAGONAL;
407 render_mgradient:
408 image = RRenderMultiGradient(width, height, &(texture->mgradient.colors[1]), subtype);
409 break;
411 case WTEX_THGRADIENT:
412 subtype = RGRD_HORIZONTAL;
413 goto render_tgradient;
415 case WTEX_TVGRADIENT:
416 subtype = RGRD_VERTICAL;
417 goto render_tgradient;
419 case WTEX_TDGRADIENT:
420 subtype = RGRD_DIAGONAL;
421 render_tgradient:
423 RImage *grad;
425 image = RMakeTiledImage(texture->tgradient.pixmap, width, height);
426 if (!image)
427 break;
429 grad = RRenderGradient(width, height, &texture->tgradient.color1,
430 &texture->tgradient.color2, subtype);
431 if (!grad) {
432 RReleaseImage(image);
433 image = NULL;
434 break;
437 RCombineImagesWithOpaqueness(image, grad, texture->tgradient.opacity);
438 RReleaseImage(grad);
440 break;
441 default:
442 puts("ERROR in wTextureRenderImage()");
443 image = NULL;
444 break;
447 if (!image) {
448 RColor gray;
450 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode));
452 image = RCreateImage(width, height, False);
453 if (image == NULL) {
454 wwarning(_("could not allocate image buffer"));
455 return NULL;
458 gray.red = 190;
459 gray.green = 190;
460 gray.blue = 190;
461 gray.alpha = 255;
462 RClearImage(image, &gray);
465 /* render bevel */
467 switch (relief) {
468 case WREL_ICON:
469 d = RBEV_RAISED3;
470 break;
472 case WREL_RAISED:
473 d = RBEV_RAISED2;
474 break;
476 case WREL_SUNKEN:
477 d = RBEV_SUNKEN;
478 break;
480 case WREL_FLAT:
481 d = 0;
482 break;
484 case WREL_MENUENTRY:
485 d = -WREL_MENUENTRY;
486 break;
488 default:
489 d = 0;
492 if (d > 0) {
493 RBevelImage(image, d);
494 } else if (d < 0) {
495 bevelImage(image, -d);
498 return image;
501 static void bevelImage(RImage * image, int relief)
503 int width = image->width;
504 int height = image->height;
505 RColor color;
507 switch (relief) {
508 case WREL_MENUENTRY:
509 color.red = color.green = color.blue = 80;
510 color.alpha = 0;
511 /**/ ROperateLine(image, RAddOperation, 1, 0, width - 2, 0, &color);
512 /**/ ROperateLine(image, RAddOperation, 0, 0, 0, height - 1, &color);
514 color.red = color.green = color.blue = 40;
515 color.alpha = 0;
516 ROperateLine(image, RSubtractOperation, width - 1, 0, width - 1, height - 1, &color);
518 /**/ ROperateLine(image, RSubtractOperation, 1, height - 2, width - 2, height - 2, &color);
520 color.red = color.green = color.blue = 0;
521 color.alpha = 255;
522 RDrawLine(image, 0, height - 1, width - 1, height - 1, &color);
523 /**/ break;
528 void wDrawBevel(Drawable d, unsigned width, unsigned height, WTexSolid * texture, int relief)
530 GC light, dim, dark;
531 XSegment segs[4];
533 if (relief == WREL_FLAT)
534 return;
536 light = texture->light_gc;
537 dim = texture->dim_gc;
538 dark = texture->dark_gc;
539 switch (relief) {
540 case WREL_FLAT:
541 return;
542 case WREL_MENUENTRY:
543 case WREL_RAISED:
544 case WREL_ICON:
545 segs[0].x1 = 1;
546 segs[0].x2 = width - 2;
547 segs[0].y2 = segs[0].y1 = height - 2;
548 segs[1].x1 = width - 2;
549 segs[1].y1 = 1;
550 segs[1].x2 = width - 2;
551 segs[1].y2 = height - 2;
552 if (wPreferences.new_style == TS_NEXT) {
553 XDrawSegments(dpy, d, dark, segs, 2);
554 } else {
555 XDrawSegments(dpy, d, dim, segs, 2);
557 segs[0].x1 = 0;
558 segs[0].x2 = width - 1;
559 segs[0].y2 = segs[0].y1 = height - 1;
560 segs[1].x1 = segs[1].x2 = width - 1;
561 segs[1].y1 = 0;
562 segs[1].y2 = height - 1;
563 if (wPreferences.new_style == TS_NEXT) {
564 XDrawSegments(dpy, d, light, segs, 2);
565 } else {
566 XDrawSegments(dpy, d, dark, segs, 2);
568 segs[0].x1 = segs[0].y1 = segs[0].y2 = 0;
569 segs[0].x2 = width - 2;
570 segs[1].x1 = segs[1].y1 = 0;
571 segs[1].x2 = 0;
572 segs[1].y2 = height - 2;
573 if (wPreferences.new_style == TS_NEXT) {
574 XDrawSegments(dpy, d, dark, segs, 2);
575 } else {
576 XDrawSegments(dpy, d, light, segs, 2);
578 if (relief == WREL_ICON) {
579 segs[0].x1 = segs[0].y1 = segs[0].y2 = 1;
580 segs[0].x2 = width - 2;
581 segs[1].x1 = segs[1].y1 = 1;
582 segs[1].x2 = 1;
583 segs[1].y2 = height - 2;
584 XDrawSegments(dpy, d, light, segs, 2);
586 break;