New titlebar button style
[wmaker-crm.git] / src / texture.c
blob1fbf0c98702fb1ab566ec02b9a14d362ade5768f
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
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 "texture.h"
35 #include "funcs.h"
37 extern WPreferences wPreferences;
39 static void bevelImage(RImage * image, int relief);
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 memset(texture, 0, sizeof(WTexture));
184 texture->type = style;
185 texture->subtype = 0;
187 texture->color1 = *from;
188 texture->color2 = *to;
190 texture->normal.red = (from->red + to->red) << 7;
191 texture->normal.green = (from->green + to->green) << 7;
192 texture->normal.blue = (from->blue + to->blue) << 7;
194 XAllocColor(dpy, scr->w_colormap, &texture->normal);
195 gcv.background = gcv.foreground = texture->normal.pixel;
196 gcv.graphics_exposures = False;
197 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
199 return texture;
202 WTexIGradient *wTextureMakeIGradient(WScreen * scr, int thickness1, RColor colors1[2],
203 int thickness2, RColor colors2[2])
205 WTexIGradient *texture;
206 XGCValues gcv;
207 int i;
209 texture = wmalloc(sizeof(WTexture));
210 memset(texture, 0, sizeof(WTexture));
211 texture->type = WTEX_IGRADIENT;
212 for (i = 0; i < 2; i++) {
213 texture->colors1[i] = colors1[i];
214 texture->colors2[i] = colors2[i];
216 texture->thickness1 = thickness1;
217 texture->thickness2 = thickness2;
218 if (thickness1 >= thickness2) {
219 texture->normal.red = (colors1[0].red + colors1[1].red) << 7;
220 texture->normal.green = (colors1[0].green + colors1[1].green) << 7;
221 texture->normal.blue = (colors1[0].blue + colors1[1].blue) << 7;
222 } else {
223 texture->normal.red = (colors2[0].red + colors2[1].red) << 7;
224 texture->normal.green = (colors2[0].green + colors2[1].green) << 7;
225 texture->normal.blue = (colors2[0].blue + colors2[1].blue) << 7;
227 XAllocColor(dpy, scr->w_colormap, &texture->normal);
228 gcv.background = gcv.foreground = texture->normal.pixel;
229 gcv.graphics_exposures = False;
230 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
232 return texture;
235 WTexMGradient *wTextureMakeMGradient(WScreen * scr, int style, RColor ** colors)
237 WTexMGradient *texture;
238 XGCValues gcv;
239 int i;
241 texture = wmalloc(sizeof(WTexture));
242 memset(texture, 0, sizeof(WTexture));
243 texture->type = style;
244 texture->subtype = 0;
246 i = 0;
247 while (colors[i] != NULL)
248 i++;
249 i--;
250 texture->normal.red = (colors[0]->red << 8);
251 texture->normal.green = (colors[0]->green << 8);
252 texture->normal.blue = (colors[0]->blue << 8);
254 texture->colors = colors;
256 XAllocColor(dpy, scr->w_colormap, &texture->normal);
257 gcv.background = gcv.foreground = texture->normal.pixel;
258 gcv.graphics_exposures = False;
259 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
261 return texture;
264 WTexPixmap *wTextureMakePixmap(WScreen * scr, int style, char *pixmap_file, XColor * color)
266 WTexPixmap *texture;
267 XGCValues gcv;
268 RImage *image;
269 char *file;
271 file = FindImage(wPreferences.pixmap_path, pixmap_file);
272 if (!file) {
273 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
274 return NULL;
276 image = RLoadImage(scr->rcontext, file, 0);
277 if (!image) {
278 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
279 wfree(file);
280 return NULL;
282 wfree(file);
284 texture = wmalloc(sizeof(WTexture));
285 memset(texture, 0, sizeof(WTexture));
286 texture->type = WTEX_PIXMAP;
287 texture->subtype = style;
289 texture->normal = *color;
291 XAllocColor(dpy, scr->w_colormap, &texture->normal);
292 gcv.background = gcv.foreground = texture->normal.pixel;
293 gcv.graphics_exposures = False;
294 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
296 texture->pixmap = image;
298 return texture;
301 WTexTGradient *wTextureMakeTGradient(WScreen * scr, int style, RColor * from, RColor * to,
302 char *pixmap_file, int opacity)
304 WTexTGradient *texture;
305 XGCValues gcv;
306 RImage *image;
307 char *file;
309 file = FindImage(wPreferences.pixmap_path, pixmap_file);
310 if (!file) {
311 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file);
312 return NULL;
314 image = RLoadImage(scr->rcontext, file, 0);
315 if (!image) {
316 wwarning(_("could not load texture pixmap \"%s\":%s"), file, RMessageForError(RErrorCode));
317 wfree(file);
318 return NULL;
320 wfree(file);
322 texture = wmalloc(sizeof(WTexture));
323 memset(texture, 0, sizeof(WTexture));
324 texture->type = style;
326 texture->opacity = opacity;
328 texture->color1 = *from;
329 texture->color2 = *to;
331 texture->normal.red = (from->red + to->red) << 7;
332 texture->normal.green = (from->green + to->green) << 7;
333 texture->normal.blue = (from->blue + to->blue) << 7;
335 XAllocColor(dpy, scr->w_colormap, &texture->normal);
336 gcv.background = gcv.foreground = texture->normal.pixel;
337 gcv.graphics_exposures = False;
338 texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
340 texture->pixmap = image;
342 return texture;
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;