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,
25 #include <X11/Xutil.h>
39 #include "WindowMaker.h"
44 extern WPreferences wPreferences
;
46 static void bevelImage(RImage
* image
, int relief
);
48 WTexSolid
*wTextureMakeSolid(WScreen
* scr
, XColor
* color
)
54 texture
= wmalloc(sizeof(WTexture
));
56 texture
->type
= WTEX_SOLID
;
59 XAllocColor(dpy
, scr
->w_colormap
, color
);
60 texture
->normal
= *color
;
61 if (color
->red
== 0 && color
->blue
== 0 && color
->green
== 0) {
62 texture
->light
.red
= 0xb6da;
63 texture
->light
.green
= 0xb6da;
64 texture
->light
.blue
= 0xb6da;
65 texture
->dim
.red
= 0x6185;
66 texture
->dim
.green
= 0x6185;
67 texture
->dim
.blue
= 0x6185;
73 rgb
.red
= color
->red
>> 8;
74 rgb
.green
= color
->green
>> 8;
75 rgb
.blue
= color
->blue
>> 8;
76 RRGBtoHSV(&rgb
, &hsv
);
77 RHSVtoRGB(&hsv
, &rgb
);
80 v
= hsv
.value
* 16 / 10;
81 hsv
.value
= (v
> 255 ? 255 : v
);
82 RHSVtoRGB(&hsv
, &rgb
);
83 texture
->light
.red
= rgb
.red
<< 8;
84 texture
->light
.green
= rgb
.green
<< 8;
85 texture
->light
.blue
= rgb
.blue
<< 8;
87 hsv2
.value
= hsv2
.value
/ 2;
88 RHSVtoRGB(&hsv2
, &rgb
);
89 texture
->dim
.red
= rgb
.red
<< 8;
90 texture
->dim
.green
= rgb
.green
<< 8;
91 texture
->dim
.blue
= rgb
.blue
<< 8;
93 texture
->dark
.red
= 0;
94 texture
->dark
.green
= 0;
95 texture
->dark
.blue
= 0;
96 XAllocColor(dpy
, scr
->w_colormap
, &texture
->light
);
97 XAllocColor(dpy
, scr
->w_colormap
, &texture
->dim
);
98 XAllocColor(dpy
, scr
->w_colormap
, &texture
->dark
);
100 gcm
= GCForeground
| GCBackground
| GCGraphicsExposures
;
101 gcv
.graphics_exposures
= False
;
103 gcv
.background
= gcv
.foreground
= texture
->light
.pixel
;
104 texture
->light_gc
= XCreateGC(dpy
, scr
->w_win
, gcm
, &gcv
);
106 gcv
.background
= gcv
.foreground
= texture
->dim
.pixel
;
107 texture
->dim_gc
= XCreateGC(dpy
, scr
->w_win
, gcm
, &gcv
);
109 gcv
.background
= gcv
.foreground
= texture
->dark
.pixel
;
110 texture
->dark_gc
= XCreateGC(dpy
, scr
->w_win
, gcm
, &gcv
);
112 gcv
.background
= gcv
.foreground
= color
->pixel
;
113 texture
->normal_gc
= XCreateGC(dpy
, scr
->w_win
, gcm
, &gcv
);
118 static int dummyErrorHandler(Display
* foo
, XErrorEvent
* bar
)
121 wwarning("your server is buggy. Tell the author if some error related to color occurs");
126 void wTextureDestroy(WScreen
* scr
, WTexture
* texture
)
130 unsigned long colors
[8];
133 if (texture
== NULL
) {
134 printf("BUG: trying to free NULL texture\n");
140 * some stupid servers don't like white or black being freed...
142 #define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
143 switch (texture
->any
.type
) {
145 XFreeGC(dpy
, texture
->solid
.light_gc
);
146 XFreeGC(dpy
, texture
->solid
.dark_gc
);
147 XFreeGC(dpy
, texture
->solid
.dim_gc
);
148 if (CANFREE(texture
->solid
.light
.pixel
))
149 colors
[count
++] = texture
->solid
.light
.pixel
;
150 if (CANFREE(texture
->solid
.dim
.pixel
))
151 colors
[count
++] = texture
->solid
.dim
.pixel
;
152 if (CANFREE(texture
->solid
.dark
.pixel
))
153 colors
[count
++] = texture
->solid
.dark
.pixel
;
157 RReleaseImage(texture
->pixmap
.pixmap
);
160 case WTEX_MHGRADIENT
:
161 case WTEX_MVGRADIENT
:
162 case WTEX_MDGRADIENT
:
163 for (i
= 0; texture
->mgradient
.colors
[i
] != NULL
; i
++) {
164 wfree(texture
->mgradient
.colors
[i
]);
166 wfree(texture
->mgradient
.colors
);
169 case WTEX_THGRADIENT
:
170 case WTEX_TVGRADIENT
:
171 case WTEX_TDGRADIENT
:
172 RReleaseImage(texture
->tgradient
.pixmap
);
175 #ifdef TEXTURE_PLUGIN
178 if (texture
->function
.handle
) {
179 dlclose(texture
->function
.handle
);
182 for (i
= 0; i
< texture
->function
.argc
; i
++) {
183 wfree(texture
->function
.argv
[i
]);
185 wfree(texture
->function
.argv
);
187 #endif /* TEXTURE_PLUGIN */
189 if (CANFREE(texture
->any
.color
.pixel
))
190 colors
[count
++] = texture
->any
.color
.pixel
;
192 XErrorHandler oldhandler
;
194 /* ignore error from buggy servers that don't know how
195 * to do reference counting for colors. */
197 oldhandler
= XSetErrorHandler(dummyErrorHandler
);
198 XFreeColors(dpy
, scr
->w_colormap
, colors
, count
, 0);
200 XSetErrorHandler(oldhandler
);
202 XFreeGC(dpy
, texture
->any
.gc
);
207 WTexGradient
*wTextureMakeGradient(WScreen
* scr
, int style
, RColor
* from
, RColor
* to
)
209 WTexGradient
*texture
;
212 texture
= wmalloc(sizeof(WTexture
));
213 memset(texture
, 0, sizeof(WTexture
));
214 texture
->type
= style
;
215 texture
->subtype
= 0;
217 texture
->color1
= *from
;
218 texture
->color2
= *to
;
220 texture
->normal
.red
= (from
->red
+ to
->red
) << 7;
221 texture
->normal
.green
= (from
->green
+ to
->green
) << 7;
222 texture
->normal
.blue
= (from
->blue
+ to
->blue
) << 7;
224 XAllocColor(dpy
, scr
->w_colormap
, &texture
->normal
);
225 gcv
.background
= gcv
.foreground
= texture
->normal
.pixel
;
226 gcv
.graphics_exposures
= False
;
227 texture
->normal_gc
= XCreateGC(dpy
, scr
->w_win
, GCForeground
| GCBackground
| GCGraphicsExposures
, &gcv
);
232 WTexIGradient
*wTextureMakeIGradient(WScreen
* scr
, int thickness1
, RColor colors1
[2],
233 int thickness2
, RColor colors2
[2])
235 WTexIGradient
*texture
;
239 texture
= wmalloc(sizeof(WTexture
));
240 memset(texture
, 0, sizeof(WTexture
));
241 texture
->type
= WTEX_IGRADIENT
;
242 for (i
= 0; i
< 2; i
++) {
243 texture
->colors1
[i
] = colors1
[i
];
244 texture
->colors2
[i
] = colors2
[i
];
246 texture
->thickness1
= thickness1
;
247 texture
->thickness2
= thickness2
;
248 if (thickness1
>= thickness2
) {
249 texture
->normal
.red
= (colors1
[0].red
+ colors1
[1].red
) << 7;
250 texture
->normal
.green
= (colors1
[0].green
+ colors1
[1].green
) << 7;
251 texture
->normal
.blue
= (colors1
[0].blue
+ colors1
[1].blue
) << 7;
253 texture
->normal
.red
= (colors2
[0].red
+ colors2
[1].red
) << 7;
254 texture
->normal
.green
= (colors2
[0].green
+ colors2
[1].green
) << 7;
255 texture
->normal
.blue
= (colors2
[0].blue
+ colors2
[1].blue
) << 7;
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
);
265 WTexMGradient
*wTextureMakeMGradient(WScreen
* scr
, int style
, RColor
** colors
)
267 WTexMGradient
*texture
;
271 texture
= wmalloc(sizeof(WTexture
));
272 memset(texture
, 0, sizeof(WTexture
));
273 texture
->type
= style
;
274 texture
->subtype
= 0;
277 while (colors
[i
] != NULL
)
280 texture
->normal
.red
= (colors
[0]->red
<< 8);
281 texture
->normal
.green
= (colors
[0]->green
<< 8);
282 texture
->normal
.blue
= (colors
[0]->blue
<< 8);
284 texture
->colors
= colors
;
286 XAllocColor(dpy
, scr
->w_colormap
, &texture
->normal
);
287 gcv
.background
= gcv
.foreground
= texture
->normal
.pixel
;
288 gcv
.graphics_exposures
= False
;
289 texture
->normal_gc
= XCreateGC(dpy
, scr
->w_win
, GCForeground
| GCBackground
| GCGraphicsExposures
, &gcv
);
294 WTexPixmap
*wTextureMakePixmap(WScreen
* scr
, int style
, char *pixmap_file
, XColor
* color
)
301 file
= FindImage(wPreferences
.pixmap_path
, pixmap_file
);
303 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file
);
306 image
= RLoadImage(scr
->rcontext
, file
, 0);
308 wwarning(_("could not load texture pixmap \"%s\":%s"), file
, RMessageForError(RErrorCode
));
314 texture
= wmalloc(sizeof(WTexture
));
315 memset(texture
, 0, sizeof(WTexture
));
316 texture
->type
= WTEX_PIXMAP
;
317 texture
->subtype
= style
;
319 texture
->normal
= *color
;
321 XAllocColor(dpy
, scr
->w_colormap
, &texture
->normal
);
322 gcv
.background
= gcv
.foreground
= texture
->normal
.pixel
;
323 gcv
.graphics_exposures
= False
;
324 texture
->normal_gc
= XCreateGC(dpy
, scr
->w_win
, GCForeground
| GCBackground
| GCGraphicsExposures
, &gcv
);
326 texture
->pixmap
= image
;
331 WTexTGradient
*wTextureMakeTGradient(WScreen
* scr
, int style
, RColor
* from
, RColor
* to
,
332 char *pixmap_file
, int opacity
)
334 WTexTGradient
*texture
;
339 file
= FindImage(wPreferences
.pixmap_path
, pixmap_file
);
341 wwarning(_("image file \"%s\" used as texture could not be found."), pixmap_file
);
344 image
= RLoadImage(scr
->rcontext
, file
, 0);
346 wwarning(_("could not load texture pixmap \"%s\":%s"), file
, RMessageForError(RErrorCode
));
352 texture
= wmalloc(sizeof(WTexture
));
353 memset(texture
, 0, sizeof(WTexture
));
354 texture
->type
= style
;
356 texture
->opacity
= opacity
;
358 texture
->color1
= *from
;
359 texture
->color2
= *to
;
361 texture
->normal
.red
= (from
->red
+ to
->red
) << 7;
362 texture
->normal
.green
= (from
->green
+ to
->green
) << 7;
363 texture
->normal
.blue
= (from
->blue
+ to
->blue
) << 7;
365 XAllocColor(dpy
, scr
->w_colormap
, &texture
->normal
);
366 gcv
.background
= gcv
.foreground
= texture
->normal
.pixel
;
367 gcv
.graphics_exposures
= False
;
368 texture
->normal_gc
= XCreateGC(dpy
, scr
->w_win
, GCForeground
| GCBackground
| GCGraphicsExposures
, &gcv
);
370 texture
->pixmap
= image
;
375 #ifdef TEXTURE_PLUGIN
376 WTexFunction
*wTextureMakeFunction(WScreen
* scr
, char *lib
, char *func
, int argc
, char **argv
)
378 XColor fallbackColor
;
380 WTexFunction
*texture
;
382 texture
= wmalloc(sizeof(WTexture
));
383 texture
->type
= WTEX_FUNCTION
;
384 texture
->handle
= NULL
;
386 texture
->argc
= argc
;
387 texture
->argv
= argv
;
389 fallbackColor
.red
= 0x8000;
390 fallbackColor
.green
= 0x8000;
391 fallbackColor
.blue
= 0x8000;
393 gcv
.background
= gcv
.foreground
= fallbackColor
.pixel
;
394 gcv
.graphics_exposures
= False
;
395 texture
->normal_gc
= XCreateGC(dpy
, scr
->w_win
, GCForeground
| GCBackground
| GCGraphicsExposures
, &gcv
);
398 /* open the library */
399 texture
->handle
= dlopen(lib
, RTLD_LAZY
);
400 if (!texture
->handle
) {
401 wwarning(_("library \"%s\" cound not be opened."), lib
);
407 /* find the function */
408 texture
->render
= dlsym(texture
->handle
, func
);
409 if (!texture
->render
) {
410 wwarning(_("function \"%s\" not found in library \"%s\""), func
, lib
);
412 dlclose(texture
->handle
);
417 wwarning(_("function textures not supported on this system, sorry."));
423 #endif /* TEXTURE_PLUGIN */
425 RImage
*wTextureRenderImage(WTexture
* texture
, int width
, int height
, int relief
)
427 RImage
*image
= NULL
;
432 switch (texture
->any
.type
) {
434 image
= RCreateImage(width
, height
, False
);
436 color1
.red
= texture
->solid
.normal
.red
>> 8;
437 color1
.green
= texture
->solid
.normal
.green
>> 8;
438 color1
.blue
= texture
->solid
.normal
.blue
>> 8;
441 RClearImage(image
, &color1
);
445 if (texture
->pixmap
.subtype
== WTP_TILE
) {
446 image
= RMakeTiledImage(texture
->pixmap
.pixmap
, width
, height
);
447 } else if (texture
->pixmap
.subtype
== WTP_CENTER
) {
448 color1
.red
= texture
->pixmap
.normal
.red
>> 8;
449 color1
.green
= texture
->pixmap
.normal
.green
>> 8;
450 color1
.blue
= texture
->pixmap
.normal
.blue
>> 8;
452 image
= RMakeCenteredImage(texture
->pixmap
.pixmap
, width
, height
, &color1
);
454 image
= RScaleImage(texture
->pixmap
.pixmap
, width
, height
);
459 image
= RRenderInterwovenGradient(width
, height
,
460 texture
->igradient
.colors1
,
461 texture
->igradient
.thickness1
,
462 texture
->igradient
.colors2
, texture
->igradient
.thickness2
);
466 subtype
= RGRD_HORIZONTAL
;
467 goto render_gradient
;
470 subtype
= RGRD_VERTICAL
;
471 goto render_gradient
;
474 subtype
= RGRD_DIAGONAL
;
477 image
= RRenderGradient(width
, height
, &texture
->gradient
.color1
,
478 &texture
->gradient
.color2
, subtype
);
481 case WTEX_MHGRADIENT
:
482 subtype
= RGRD_HORIZONTAL
;
483 goto render_mgradient
;
485 case WTEX_MVGRADIENT
:
486 subtype
= RGRD_VERTICAL
;
487 goto render_mgradient
;
489 case WTEX_MDGRADIENT
:
490 subtype
= RGRD_DIAGONAL
;
492 image
= RRenderMultiGradient(width
, height
, &(texture
->mgradient
.colors
[1]), subtype
);
495 case WTEX_THGRADIENT
:
496 subtype
= RGRD_HORIZONTAL
;
497 goto render_tgradient
;
499 case WTEX_TVGRADIENT
:
500 subtype
= RGRD_VERTICAL
;
501 goto render_tgradient
;
503 case WTEX_TDGRADIENT
:
504 subtype
= RGRD_DIAGONAL
;
509 image
= RMakeTiledImage(texture
->tgradient
.pixmap
, width
, height
);
513 grad
= RRenderGradient(width
, height
, &texture
->tgradient
.color1
,
514 &texture
->tgradient
.color2
, subtype
);
516 RReleaseImage(image
);
521 RCombineImagesWithOpaqueness(image
, grad
, texture
->tgradient
.opacity
);
526 #ifdef TEXTURE_PLUGIN
529 if (texture
->function
.render
) {
530 image
= texture
->function
.render(texture
->function
.argc
, texture
->function
.argv
,
531 width
, height
, relief
);
535 RErrorCode
= RERR_INTERNAL
;
538 #endif /* TEXTURE_PLUGIN */
541 puts("ERROR in wTextureRenderImage()");
549 wwarning(_("could not render texture: %s"), RMessageForError(RErrorCode
));
551 image
= RCreateImage(width
, height
, False
);
553 wwarning(_("could not allocate image buffer"));
561 RClearImage(image
, &gray
);
592 RBevelImage(image
, d
);
594 bevelImage(image
, -d
);
600 static void bevelImage(RImage
* image
, int relief
)
602 int width
= image
->width
;
603 int height
= image
->height
;
608 color
.red
= color
.green
= color
.blue
= 80;
610 /**/ ROperateLine(image
, RAddOperation
, 1, 0, width
- 2, 0, &color
);
611 /**/ ROperateLine(image
, RAddOperation
, 0, 0, 0, height
- 1, &color
);
613 color
.red
= color
.green
= color
.blue
= 40;
615 ROperateLine(image
, RSubtractOperation
, width
- 1, 0, width
- 1, height
- 1, &color
);
617 /**/ ROperateLine(image
, RSubtractOperation
, 1, height
- 2, width
- 2, height
- 2, &color
);
619 color
.red
= color
.green
= color
.blue
= 0;
621 RDrawLine(image
, 0, height
- 1, width
- 1, height
- 1, &color
);
627 void wDrawBevel(Drawable d
, unsigned width
, unsigned height
, WTexSolid
* texture
, int relief
)
632 if (relief
== WREL_FLAT
)
635 light
= texture
->light_gc
;
636 dim
= texture
->dim_gc
;
637 dark
= texture
->dark_gc
;
645 segs
[0].x2
= width
- 2;
646 segs
[0].y2
= segs
[0].y1
= height
- 2;
647 segs
[1].x1
= width
- 2;
649 segs
[1].x2
= width
- 2;
650 segs
[1].y2
= height
- 2;
651 XDrawSegments(dpy
, d
, dim
, segs
, 2);
653 segs
[0].x2
= width
- 1;
654 segs
[0].y2
= segs
[0].y1
= height
- 1;
655 segs
[1].x1
= segs
[1].x2
= width
- 1;
657 segs
[1].y2
= height
- 1;
658 XDrawSegments(dpy
, d
, dark
, segs
, 2);
659 segs
[0].x1
= segs
[0].y1
= segs
[0].y2
= 0;
660 segs
[0].x2
= width
- 2;
661 segs
[1].x1
= segs
[1].y1
= 0;
663 segs
[1].y2
= height
- 2;
664 XDrawSegments(dpy
, d
, light
, segs
, 2);
665 if (relief
== WREL_ICON
) {
666 segs
[0].x1
= segs
[0].y1
= segs
[0].y2
= 1;
667 segs
[0].x2
= width
- 2;
668 segs
[1].x1
= segs
[1].y1
= 1;
670 segs
[1].y2
= height
- 2;
671 XDrawSegments(dpy
, d
, light
, segs
, 2);
677 segs
[0].x2
= width
- 1;
678 segs
[0].y2
= segs
[0].y1
= 0;
679 segs
[1].x1
= segs
[1].x2
= 0;
681 segs
[1].y2
= height
- 1;
682 XDrawSegments(dpy
, d
, dark
, segs
, 2);
685 segs
[0].y1
= segs
[0].y2
= height
- 1;
686 segs
[0].x2
= width
- 1;
687 segs
[1].x2
= segs
[1].x1
= width
- 1;
689 segs
[1].y2
= height
- 1;
690 XDrawSegments(dpy
, d
, light
, segs
, 2);