1 /* Fvwm colorset technology is Copyright (C) 1999 Joey Shutup
2 * http://www.streetmap.co.uk/streetmap.dll?Postcode2Map?BS24+9TZ
3 * You may use this code for any purpose, as long as the original copyright
4 * and this notice remains in the source code and all documentation
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, or (at your option)
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 software; see the file COPYING.GPL. If not, write to
18 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307 USA
27 #include <X11/Intrinsic.h>
29 #include "libs/fvwmlib.h"
30 #include "libs/FShape.h"
31 #include "libs/Colorset.h"
32 #include "libs/safemalloc.h"
33 #include "libs/PictureBase.h"
34 #include "libs/PictureGraphics.h"
37 colorset_t
*Colorset
= NULL
;
40 /*****************************************************************************
41 * AllocColorset() grows the size of the Colorset array to include set n
42 * colorset_t *Colorset will be altered
43 * returns the address of the member
44 *****************************************************************************/
45 void AllocColorset(int n
)
47 /* do nothing if it already exists */
53 /* increment n to get the required array size, get a new array */
54 Colorset
= (colorset_t
*)saferealloc(
55 (char *)Colorset
, ++n
* sizeof(colorset_t
));
57 /* zero out colorset 0
58 it's always defined so will be filled in during module startup */
62 &Colorset
[nColorsets
], 0,
63 (n
- nColorsets
) * sizeof(colorset_t
));
67 /* copy colorset 0 into new members so that if undefined ones
68 * are referenced at least they don't give black on black */
69 for ( ; nColorsets
< n
; nColorsets
++)
72 &Colorset
[nColorsets
], Colorset
,
81 /*****************************************************************************
82 * DumpColorset() returns a char * to the colorset contents in printable form
83 *****************************************************************************/
84 static char csetbuf
[256];
85 char *DumpColorset(int n
, colorset_t
*cs
)
89 "%x %lx %lx %lx %lx %lx %lx %lx %lx %lx "
90 "%x %x %x %x %x %x %x %x %x %x %x",
91 n
, cs
->fg
, cs
->bg
, cs
->hilite
, cs
->shadow
, cs
->fgsh
, cs
->tint
,
92 cs
->icon_tint
, cs
->pixmap
, cs
->shape_mask
,
93 cs
->fg_alpha_percent
, cs
->width
, cs
->height
, cs
->pixmap_type
,
94 cs
->shape_width
, cs
->shape_height
, cs
->shape_type
,
95 cs
->tint_percent
, cs
->do_dither_icon
, cs
->icon_tint_percent
,
96 cs
->icon_alpha_percent
);
100 /*****************************************************************************
101 * LoadColorset() takes a strings and stuffs it into the array
102 *****************************************************************************/
103 int LoadColorset(char *line
)
106 unsigned int n
, chars
;
107 Pixel fg
, bg
, hilite
, shadow
, fgsh
, tint
, icon_tint
;
110 unsigned int fg_alpha_percent
, width
, height
, pixmap_type
;
111 unsigned int shape_width
, shape_height
, shape_type
;
112 unsigned int tint_percent
, do_dither_icon
, icon_tint_percent
;
113 unsigned int icon_alpha_percent
;
119 if (sscanf(line
, "%x%n", &n
, &chars
) < 1)
125 "%lx %lx %lx %lx %lx %lx %lx %lx %lx "
126 "%x %x %x %x %x %x %x %x %x %x %x",
127 &fg
, &bg
, &hilite
, &shadow
, &fgsh
, &tint
, &icon_tint
,
128 &pixmap
, &shape_mask
, &fg_alpha_percent
, &width
, &height
,
129 &pixmap_type
, &shape_width
, &shape_height
, &shape_type
,
130 &tint_percent
, &do_dither_icon
, &icon_tint_percent
,
131 &icon_alpha_percent
) != 20)
142 cs
->icon_tint
= icon_tint
;
144 cs
->shape_mask
= shape_mask
;
145 cs
->fg_alpha_percent
= fg_alpha_percent
;
148 cs
->pixmap_type
= pixmap_type
;
149 cs
->shape_width
= shape_width
;
150 cs
->shape_height
= shape_height
;
151 cs
->shape_type
= shape_type
;
152 cs
->tint_percent
= tint_percent
;
153 cs
->do_dither_icon
= do_dither_icon
;
154 cs
->icon_tint_percent
= icon_tint_percent
;
155 cs
->icon_alpha_percent
= icon_alpha_percent
;
160 /* scrolls a pixmap by x_off/y_off pixels, wrapping around at the edges. */
162 Display
*dpy
, Pixmap p
, GC gc
, int x_off
, int y_off
, int width
,
163 int height
, unsigned int depth
)
169 if (p
== None
|| p
== ParentRelative
|| (x_off
== 0 && y_off
== 0))
173 tgc
= fvwmlib_XCreateGC(dpy
, p
, 0, &xgcv
);
178 XCopyGC(dpy
, gc
, GCFunction
| GCPlaneMask
| GCSubwindowMode
|
179 GCClipXOrigin
| GCClipYOrigin
| GCClipMask
, tgc
);
181 xgcv
.ts_x_origin
= x_off
;
182 xgcv
.ts_y_origin
= y_off
;
183 xgcv
.fill_style
= FillTiled
;
185 dpy
, tgc
, GCTile
| GCTileStipXOrigin
| GCTileStipYOrigin
|
187 p2
= XCreatePixmap(dpy
, p
, width
, height
, depth
);
192 XFillRectangle(dpy
, p2
, tgc
, 0, 0, width
, height
);
198 /* sets a window background from a colorset
199 * if width or height are zero the window size is queried
201 void SetWindowBackgroundWithOffset(
202 Display
*dpy
, Window win
, int x_off
, int y_off
, int width
, int height
,
203 colorset_t
*colorset
, unsigned int depth
, GC gc
, Bool clear_area
)
205 Pixmap pixmap
= None
;
209 if (0 == width
|| 0 == height
)
212 dpy
, win
, &junk
, (int *)&junk
, (int *)&junk
,
213 (unsigned int *)&width
, (unsigned int *)&height
,
214 (unsigned int *)&junk
, (unsigned int *)&junk
))
220 if (FHaveShapeExtension
&& colorset
->shape_mask
)
222 mask
= CreateBackgroundPixmap(
223 dpy
, 0, width
, height
, colorset
, 1, None
, True
);
227 dpy
, win
, FShapeBounding
, 0, 0, mask
,
229 XFreePixmap(dpy
, mask
);
232 if (!colorset
->pixmap
)
234 /* use the bg pixel */
235 XSetWindowBackground(dpy
, win
, colorset
->bg
);
238 XClearArea(dpy
, win
, 0, 0, width
, height
, True
);
244 pixmap
= CreateBackgroundPixmap(
245 dpy
, win
, width
, height
, colorset
, depth
, gc
, False
);
246 if (x_off
!= 0 || y_off
!= 0)
251 dpy
, pixmap
, gc
, x_off
, y_off
, width
, height
,
253 if (p2
!= None
&& p2
!= ParentRelative
&& p2
!= pixmap
)
255 XFreePixmap(dpy
, pixmap
);
261 XSetWindowBackgroundPixmap(dpy
, win
, pixmap
);
264 XClearArea(dpy
, win
, 0, 0, width
, height
, True
);
266 if (pixmap
!= ParentRelative
)
268 XFreePixmap(dpy
, pixmap
);
276 Bool
UpdateBackgroundTransparency(
277 Display
*dpy
, Window win
, int width
, int height
,
278 colorset_t
*colorset
, unsigned int depth
, GC gc
, Bool clear_area
)
280 if (!CSETS_IS_TRANSPARENT(colorset
))
284 else if (!CSETS_IS_TRANSPARENT_PR_PURE(colorset
))
286 SetWindowBackgroundWithOffset(
287 dpy
, win
, 0, 0, width
, height
, colorset
, depth
, gc
,
292 XClearArea(dpy
, win
, 0,0,0,0, clear_area
);
298 void SetWindowBackground(
299 Display
*dpy
, Window win
, int width
, int height
,
300 colorset_t
*colorset
, unsigned int depth
, GC gc
, Bool clear_area
)
302 SetWindowBackgroundWithOffset(
303 dpy
, win
, 0, 0, width
, height
, colorset
, depth
, gc
, clear_area
);
308 /* create a pixmap suitable for plonking on the background of a window */
309 Pixmap
CreateBackgroundPixmap(Display
*dpy
, Window win
, int width
, int height
,
310 colorset_t
*colorset
, unsigned int depth
,
311 GC gc
, Bool is_shape_mask
)
313 Pixmap pixmap
= None
;
314 Pixmap cs_pixmap
= None
;
316 static GC shape_gc
= None
;
317 GC fill_gc
= None
; /* not static as dpy may change (FvwmBacker) */
324 if (colorset
->pixmap
== ParentRelative
&& !is_shape_mask
&&
325 colorset
->tint_percent
> 0)
327 FvwmRenderAttributes fra
;
329 fra
.mask
= FRAM_DEST_IS_A_WINDOW
| FRAM_HAVE_TINT
;
330 fra
.tint
= colorset
->tint
;
331 fra
.tint_percent
= colorset
->tint_percent
;
333 pixmap
= PGraphicsCreateTransprency(
334 dpy
, win
, &fra
, gc
, 0, 0, width
, height
, True
);
338 return ParentRelative
;
342 else if (colorset
->pixmap
== ParentRelative
&& !is_shape_mask
)
344 return ParentRelative
;
346 else if (CSETS_IS_TRANSPARENT_ROOT(colorset
) && colorset
->pixmap
353 cs_pixmap
= colorset
->pixmap
;
354 cs_width
= colorset
->width
;
355 cs_height
= colorset
->height
;
356 if (CSETS_IS_TRANSPARENT_ROOT_PURE(colorset
))
358 /* check if it is still here */
362 dpy
, colorset
->pixmap
, &dummy
,
363 (int *)&dummy
, (int *)&dummy
,
364 (unsigned int *)&w
, (unsigned int *)&h
,
365 (unsigned int *)&dummy
,
366 (unsigned int *)&dummy
))
370 if (w
!= cs_width
|| h
!= cs_height
)
375 XTranslateCoordinates(
376 dpy
, win
, DefaultRootWindow(dpy
), 0, 0, &sx
, &sy
,
378 pixmap
= XCreatePixmap(dpy
, win
, width
, height
, Pdepth
);
383 /* make sx and sy positif */
392 /* make sx and sy in (0,0,cs_width,cs_height) */
393 while (sx
>= cs_width
)
397 while (sy
>= cs_height
)
401 xgcv
.fill_style
= FillTiled
;
402 xgcv
.tile
= cs_pixmap
;
403 xgcv
.ts_x_origin
= cs_width
-sx
;
404 xgcv
.ts_y_origin
= cs_height
-sy
;
405 fill_gc
= fvwmlib_XCreateGC(
406 dpy
, win
, GCTile
| GCTileStipXOrigin
| GCTileStipYOrigin
407 | GCFillStyle
, &xgcv
);
408 XFillRectangle(dpy
, pixmap
, fill_gc
, 0, 0, width
, height
);
409 if (CSETS_IS_TRANSPARENT_ROOT_PURE(colorset
) &&
410 colorset
->tint_percent
> 0)
412 FvwmRenderAttributes fra
;
414 fra
.mask
= FRAM_HAVE_TINT
;
415 fra
.tint
= colorset
->tint
;
416 fra
.tint_percent
= colorset
->tint_percent
;
417 PGraphicsRenderPixmaps(
418 dpy
, win
, pixmap
, None
, None
,
419 Pdepth
, &fra
, pixmap
,
422 0, 0, width
, height
, False
);
424 XFreeGC(dpy
,fill_gc
);
429 cs_pixmap
= colorset
->pixmap
;
430 cs_width
= colorset
->width
;
431 cs_height
= colorset
->height
;
433 (colorset
->pixmap_type
== PIXMAP_STRETCH_ASPECT
);
434 cs_stretch_x
= (colorset
->pixmap_type
== PIXMAP_STRETCH_X
)
435 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
436 cs_stretch_y
= (colorset
->pixmap_type
== PIXMAP_STRETCH_Y
)
437 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
441 /* In spite of the name, win contains the pixmap */
442 cs_pixmap
= colorset
->shape_mask
;
443 win
= colorset
->shape_mask
;
444 if (shape_gc
== None
)
448 /* create a gc for 1 bit depth */
449 shape_gc
= fvwmlib_XCreateGC(
450 dpy
, win
, GCForeground
|GCBackground
, &xgcv
);
453 cs_width
= colorset
->shape_width
;
454 cs_height
= colorset
->shape_height
;
455 cs_keep_aspect
= (colorset
->shape_type
== SHAPE_STRETCH_ASPECT
);
456 cs_stretch_x
= !(colorset
->shape_type
== SHAPE_TILED
);
457 cs_stretch_y
= !(colorset
->shape_type
== SHAPE_TILED
);
460 if (cs_pixmap
== None
)
462 xgcv
.foreground
= colorset
->bg
;
463 fill_gc
= fvwmlib_XCreateGC(dpy
, win
, GCForeground
, &xgcv
);
464 /* create a solid pixmap - not very useful most of the time */
465 pixmap
= XCreatePixmap(dpy
, win
, 1, 1, depth
);
466 XFillRectangle(dpy
, pixmap
, fill_gc
, 0, 0, 1, 1);
467 XFreeGC(dpy
,fill_gc
);
469 else if (cs_keep_aspect
)
472 int big_width
, big_height
;
476 /* do sides need triming or top/bottom? */
477 trim_side
= (cs_width
* height
> cs_height
* width
);
479 /* make a pixmap big enough to cover the destination but with
480 * the aspect ratio of the cs_pixmap */
481 big_width
= trim_side
? height
* cs_width
/ cs_height
: width
;
482 big_height
= trim_side
? height
: width
* cs_width
/ cs_width
;
483 big_pixmap
= CreateStretchPixmap(
484 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, big_width
,
487 /* work out where to trim */
488 x
= trim_side
? (big_width
- width
) / 2 : 0;
489 y
= trim_side
? 0 : (big_height
- height
) / 2;
491 pixmap
= XCreatePixmap(dpy
, cs_pixmap
, width
, height
, depth
);
492 if (pixmap
&& big_pixmap
)
495 dpy
, big_pixmap
, pixmap
, gc
, x
, y
, width
, height
,
500 XFreePixmap(dpy
, big_pixmap
);
503 else if (!cs_stretch_x
&& !cs_stretch_y
)
505 /* it's a tiled pixmap, create an unstretched one */
508 pixmap
= XCreatePixmap(
509 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
);
513 dpy
, cs_pixmap
, pixmap
, gc
, 0, 0,
514 cs_width
, cs_height
, 0, 0);
519 /* can't tile masks, create a tiled version of the
521 pixmap
= CreateTiledPixmap(
522 dpy
, cs_pixmap
, cs_width
, cs_height
, width
,
526 else if (!cs_stretch_x
)
528 /* it's an HGradient */
529 pixmap
= CreateStretchYPixmap(
530 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, height
, gc
);
532 else if (!cs_stretch_y
)
534 /* it's a VGradient */
535 pixmap
= CreateStretchXPixmap(
536 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, width
, gc
);
540 /* It's a full window pixmap */
541 pixmap
= CreateStretchPixmap(
542 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, width
,
550 /* Draws a colorset background into the specified rectangle in the target
552 void SetRectangleBackground(
553 Display
*dpy
, Window win
, int x
, int y
, int width
, int height
,
554 colorset_t
*colorset
, unsigned int depth
, GC gc
)
556 SetClippedRectangleBackground(
557 dpy
, win
, x
, y
, width
, height
, NULL
, colorset
, depth
, gc
);
562 /* Draws a colorset background into the specified rectangle in the target
564 void SetClippedRectangleBackground(
565 Display
*dpy
, Window win
, int x
, int y
, int width
, int height
,
566 XRectangle
*clip
, colorset_t
*colorset
,
567 unsigned int depth
, GC gc
)
571 Pixmap pixmap
= None
;
572 static int last_depth
= -1;
573 static GC last_gc
= None
;
575 Pixmap clipmask
= None
;
577 Bool keep_aspect
= (colorset
->pixmap_type
== PIXMAP_STRETCH_ASPECT
);
578 Bool stretch_x
= (colorset
->pixmap_type
== PIXMAP_STRETCH_X
)
579 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
580 Bool stretch_y
= (colorset
->pixmap_type
== PIXMAP_STRETCH_Y
)
581 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
582 int dest_x
, dest_y
, dest_w
, dest_h
;
588 dest_w
= clip
->width
;
589 dest_h
= clip
->height
;
598 if (CSETS_IS_TRANSPARENT_PR_TINT(colorset
))
600 XClearArea(dpy
, win
, dest_x
, dest_y
, dest_w
, dest_h
, False
);
601 PGraphicsTintRectangle(
602 dpy
, win
, colorset
->tint
, colorset
->tint_percent
,
603 win
, True
, gc
, None
, None
,
604 dest_x
, dest_y
, dest_w
, dest_h
);
607 if (CSETS_IS_TRANSPARENT_PR_PURE(colorset
))
609 XClearArea(dpy
, win
, dest_x
, dest_y
, dest_w
, dest_h
, False
);
610 /* don't do anything */
613 if (CSETS_IS_TRANSPARENT_ROOT(colorset
))
615 /* FIXME: optimize this ! */
617 width
= width
+ dest_x
;
618 height
= height
+ dest_y
;
620 /* minimize gc creation by remembering the last requested depth */
621 if (last_gc
!= None
&& depth
!= last_depth
)
623 XFreeGC(dpy
, last_gc
);
628 last_gc
= fvwmlib_XCreateGC(dpy
, win
, 0, &xgcv
);
633 if (FHaveShapeExtension
&& colorset
->shape_mask
!= None
)
635 clipmask
= CreateBackgroundPixmap(
636 dpy
, 0, width
, height
, colorset
, 1, None
, True
);
639 /* create a GC for clipping */
640 xgcv
.clip_x_origin
= x
;
641 xgcv
.clip_y_origin
= y
;
642 xgcv
.clip_mask
= clipmask
;
643 clip_gc
= fvwmlib_XCreateGC(
644 dpy
, win
, GCClipXOrigin
| GCClipYOrigin
|
650 if (!colorset
->pixmap
)
652 /* use the bg pixel */
653 XSetForeground(dpy
, draw_gc
, colorset
->bg
);
655 dpy
, win
, draw_gc
, dest_x
, dest_y
, dest_w
, dest_h
);
659 pixmap
= CreateBackgroundPixmap(
660 dpy
, win
, width
, height
, colorset
, depth
, gc
, False
);
665 if (stretch_x
|| stretch_y
)
667 if (!stretch_x
&& colorset
->width
!= width
)
669 pixmap2
= CreateStretchXPixmap(
670 dpy
, pixmap
, colorset
->width
, height
,
672 XFreePixmap(dpy
, pixmap
);
675 if (!stretch_y
&& colorset
->height
!= height
)
677 pixmap2
= CreateStretchYPixmap(
678 dpy
, pixmap
, width
, colorset
->height
,
680 XFreePixmap(dpy
, pixmap
);
686 pixmap2
= CreateTiledPixmap(
687 dpy
, pixmap
, colorset
->width
, colorset
->height
,
688 width
, height
, depth
, gc
);
689 XFreePixmap(dpy
, pixmap
);
695 /* Copy the pixmap into the rectangle. */
697 dpy
, pixmap
, win
, draw_gc
,
698 dest_x
- x
, dest_y
- y
, dest_w
, dest_h
,
700 XFreePixmap(dpy
, pixmap
);
704 if (FHaveShapeExtension
)
706 if (clipmask
!= None
)
708 XFreePixmap(dpy
, clipmask
);
712 XFreeGC(dpy
, clip_gc
);