2 /* Fvwm colorset technology is Copyright (C) 1999 Joey Shutup
3 * http://www.streetmap.co.uk/streetmap.dll?Postcode2Map?BS24+9TZ
4 * You may use this code for any purpose, as long as the original copyright
5 * and this notice remains in the source code and all documentation
7 /* This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <X11/Intrinsic.h>
27 #include "libs/fvwmlib.h"
28 #include "libs/FShape.h"
29 #include "libs/Colorset.h"
30 #include "libs/PictureBase.h"
31 #include "libs/Graphics.h"
32 #include "libs/Grab.h"
33 #include "libs/PictureGraphics.h"
34 #include "libs/XError.h"
37 colorset_t
*Colorset
= NULL
;
40 /* stretch the src rectangle to the dest ractangle keeping its aspect so that
41 * it fills the destination completely. */
42 static int get_aspect_dimensions(
43 int *ret_w
, int *ret_h
, int dest_w
, int dest_h
, int src_w
, int src_h
)
48 ax
= (double)dest_w
/ (double)src_w
;
49 ay
= (double)dest_h
/ (double)src_h
;
52 /* fit in x direction */
54 *ret_h
= (src_h
* dest_w
) / src_w
;
59 /* fit in y direction */
60 *ret_w
= (src_w
* dest_h
) / src_h
;
67 * AllocColorset() grows the size of the Colorset array to include set n
68 * colorset_t *Colorset will be altered
69 * returns the address of the member
71 void AllocColorset(int n
)
73 /* do nothing if it already exists */
79 /* increment n to get the required array size, get a new array */
80 Colorset
= (colorset_t
*)saferealloc(
81 (char *)Colorset
, ++n
* sizeof(colorset_t
));
83 /* zero out colorset 0
84 it's always defined so will be filled in during module startup */
88 &Colorset
[nColorsets
], 0,
89 (n
- nColorsets
) * sizeof(colorset_t
));
93 /* copy colorset 0 into new members so that if undefined ones
94 * are referenced at least they don't give black on black */
95 for ( ; nColorsets
< n
; nColorsets
++)
98 &Colorset
[nColorsets
], Colorset
,
108 * DumpColorset() returns a char * to the colorset contents in printable form
110 static char csetbuf
[256];
111 char *DumpColorset(int n
, colorset_t
*cs
)
115 "%x %lx %lx %lx %lx %lx %lx %lx %lx %lx "
116 "%x %x %x %x %x %x %x %x %x %x %x",
117 n
, cs
->fg
, cs
->bg
, cs
->hilite
, cs
->shadow
, cs
->fgsh
, cs
->tint
,
118 cs
->icon_tint
, cs
->pixmap
, cs
->shape_mask
,
119 cs
->fg_alpha_percent
, cs
->width
, cs
->height
, cs
->pixmap_type
,
120 cs
->shape_width
, cs
->shape_height
, cs
->shape_type
,
121 cs
->tint_percent
, cs
->do_dither_icon
, cs
->icon_tint_percent
,
122 cs
->icon_alpha_percent
);
127 * LoadColorset() takes a strings and stuffs it into the array
129 int LoadColorset(char *line
)
132 unsigned int n
, chars
;
133 Pixel fg
, bg
, hilite
, shadow
, fgsh
, tint
, icon_tint
;
136 unsigned int fg_alpha_percent
, width
, height
, pixmap_type
;
137 unsigned int shape_width
, shape_height
, shape_type
;
138 unsigned int tint_percent
, do_dither_icon
, icon_tint_percent
;
139 unsigned int icon_alpha_percent
;
145 if (sscanf(line
, "%x%n", &n
, &chars
) < 1)
151 /* migo: if you modify this sscanf or other colorset definitions,
152 * please update perllib/FVWM/Tracker/Colorsets.pm too */
154 "%lx %lx %lx %lx %lx %lx %lx %lx %lx "
155 "%x %x %x %x %x %x %x %x %x %x %x",
156 &fg
, &bg
, &hilite
, &shadow
, &fgsh
, &tint
, &icon_tint
,
157 &pixmap
, &shape_mask
, &fg_alpha_percent
, &width
, &height
,
158 &pixmap_type
, &shape_width
, &shape_height
, &shape_type
,
159 &tint_percent
, &do_dither_icon
, &icon_tint_percent
,
160 &icon_alpha_percent
) != 20)
171 cs
->icon_tint
= icon_tint
;
173 cs
->shape_mask
= shape_mask
;
174 cs
->fg_alpha_percent
= fg_alpha_percent
;
177 cs
->pixmap_type
= pixmap_type
;
178 cs
->shape_width
= shape_width
;
179 cs
->shape_height
= shape_height
;
180 cs
->shape_type
= shape_type
;
181 cs
->tint_percent
= tint_percent
;
182 cs
->do_dither_icon
= do_dither_icon
;
183 cs
->icon_tint_percent
= icon_tint_percent
;
184 cs
->icon_alpha_percent
= icon_alpha_percent
;
189 /* scrolls a pixmap by x_off/y_off pixels, wrapping around at the edges. */
191 Display
*dpy
, Pixmap p
, GC gc
, int x_off
, int y_off
, int width
,
192 int height
, unsigned int depth
)
198 if (p
== None
|| p
== ParentRelative
|| (x_off
== 0 && y_off
== 0))
202 tgc
= fvwmlib_XCreateGC(dpy
, p
, 0, &xgcv
);
207 XCopyGC(dpy
, gc
, GCFunction
| GCPlaneMask
| GCSubwindowMode
|
208 GCClipXOrigin
| GCClipYOrigin
| GCClipMask
, tgc
);
210 xgcv
.ts_x_origin
= x_off
;
211 xgcv
.ts_y_origin
= y_off
;
212 xgcv
.fill_style
= FillTiled
;
214 dpy
, tgc
, GCTile
| GCTileStipXOrigin
| GCTileStipYOrigin
|
216 p2
= XCreatePixmap(dpy
, p
, width
, height
, depth
);
221 XFillRectangle(dpy
, p2
, tgc
, 0, 0, width
, height
);
227 /* sets a window background from a colorset
228 * if width or height are zero the window size is queried
230 void SetWindowBackgroundWithOffset(
231 Display
*dpy
, Window win
, int x_off
, int y_off
, int width
, int height
,
232 colorset_t
*colorset
, unsigned int depth
, GC gc
, Bool clear_area
)
234 Pixmap pixmap
= None
;
238 if (0 == width
|| 0 == height
)
241 dpy
, win
, &junk
, (int *)&junk
, (int *)&junk
,
242 (unsigned int *)&width
, (unsigned int *)&height
,
243 (unsigned int *)&junk
, (unsigned int *)&junk
))
249 if (FHaveShapeExtension
&& colorset
->shape_mask
)
251 mask
= CreateBackgroundPixmap(
252 dpy
, None
, width
, height
, colorset
, 1, None
, True
);
256 dpy
, win
, FShapeBounding
, 0, 0, mask
,
258 XFreePixmap(dpy
, mask
);
261 if (!colorset
->pixmap
)
263 /* use the bg pixel */
264 XSetWindowBackground(dpy
, win
, colorset
->bg
);
267 XClearArea(dpy
, win
, 0, 0, width
, height
, True
);
273 pixmap
= CreateOffsetBackgroundPixmap(
274 dpy
, win
, x_off
, y_off
, width
, height
, colorset
,
278 XSetWindowBackgroundPixmap(dpy
, win
, pixmap
);
281 XClearArea(dpy
, win
, 0, 0, width
, height
, True
);
283 if (pixmap
!= ParentRelative
)
285 XFreePixmap(dpy
, pixmap
);
293 Bool
UpdateBackgroundTransparency(
294 Display
*dpy
, Window win
, int width
, int height
,
295 colorset_t
*colorset
, unsigned int depth
, GC gc
, Bool clear_area
)
297 if (!CSETS_IS_TRANSPARENT(colorset
))
301 else if (!CSETS_IS_TRANSPARENT_PR_PURE(colorset
))
303 SetWindowBackgroundWithOffset(
304 dpy
, win
, 0, 0, width
, height
, colorset
, depth
, gc
,
309 XClearArea(dpy
, win
, 0,0,0,0, clear_area
);
315 void SetWindowBackground(
316 Display
*dpy
, Window win
, int width
, int height
,
317 colorset_t
*colorset
, unsigned int depth
, GC gc
, Bool clear_area
)
319 SetWindowBackgroundWithOffset(
320 dpy
, win
, 0, 0, width
, height
, colorset
, depth
, gc
, clear_area
);
325 void GetWindowBackgroundPixmapSize(
326 colorset_t
*cs_t
, int width
, int height
, int *w
, int *h
)
328 if (cs_t
->pixmap
== None
)
336 switch (cs_t
->pixmap_type
)
338 case PIXMAP_STRETCH_ASPECT
:
339 get_aspect_dimensions(
340 w
, h
, width
, height
, cs_t
->width
, cs_t
->height
);
342 case PIXMAP_STRETCH_X
:
345 case PIXMAP_STRETCH_Y
:
354 static int is_bad_gc
= 0;
355 static int BadGCErrorHandler(Display
*dpy
, XErrorEvent
*error
)
357 if (error
->error_code
== BadGC
)
367 /* delegate error to original handler */
368 rc
= ferror_call_next_error_handler(dpy
, error
);
374 /* create a pixmap suitable for plonking on the background of a part of a
376 Pixmap
CreateOffsetBackgroundPixmap(
377 Display
*dpy
, Window win
, int x
, int y
, int width
, int height
,
378 colorset_t
*colorset
, unsigned int depth
, GC gc
, Bool is_shape_mask
)
380 Pixmap pixmap
= None
;
381 Pixmap cs_pixmap
= None
;
383 static GC shape_gc
= None
;
384 GC fill_gc
= None
; /* not static as dpy may change (FvwmBacker) */
391 if (colorset
->pixmap
== ParentRelative
&& !is_shape_mask
&&
392 colorset
->tint_percent
> 0)
394 FvwmRenderAttributes fra
;
396 fra
.mask
= FRAM_DEST_IS_A_WINDOW
| FRAM_HAVE_TINT
;
397 fra
.tint
= colorset
->tint
;
398 fra
.tint_percent
= colorset
->tint_percent
;
400 pixmap
= PGraphicsCreateTransparency(
401 dpy
, win
, &fra
, gc
, x
, y
, width
, height
, True
);
402 MyXUngrabServer(dpy
);
405 return ParentRelative
;
409 else if (colorset
->pixmap
== ParentRelative
&& !is_shape_mask
)
411 return ParentRelative
;
413 else if (CSETS_IS_TRANSPARENT_ROOT(colorset
) && colorset
->pixmap
420 cs_pixmap
= colorset
->pixmap
;
421 cs_width
= colorset
->width
;
422 cs_height
= colorset
->height
;
423 if (CSETS_IS_TRANSPARENT_ROOT_PURE(colorset
))
425 /* check if it is still here */
427 /* a priori we should grab the server, but this
428 * cause PositiveWrite error when you move a
429 * window with a transparent title bar */
431 dpy
, colorset
->pixmap
, &dummy
,
432 (int *)&dummy
, (int *)&dummy
,
433 (unsigned int *)&w
, (unsigned int *)&h
,
434 (unsigned int *)&dummy
,
435 (unsigned int *)&dummy
) ||
436 w
!= cs_width
|| h
!= cs_height
)
441 XTranslateCoordinates(
442 dpy
, win
, DefaultRootWindow(dpy
), x
, y
, &sx
, &sy
,
444 pixmap
= XCreatePixmap(dpy
, win
, width
, height
, Pdepth
);
449 /* make sx and sy positif */
458 /* make sx and sy in (0,0,cs_width,cs_height) */
459 while (sx
>= cs_width
)
463 while (sy
>= cs_height
)
467 xgcv
.fill_style
= FillTiled
;
468 xgcv
.tile
= cs_pixmap
;
469 xgcv
.ts_x_origin
= cs_width
-sx
;
470 xgcv
.ts_y_origin
= cs_height
-sy
;
471 fill_gc
= fvwmlib_XCreateGC(
472 dpy
, win
, GCTile
| GCTileStipXOrigin
|
473 GCTileStipYOrigin
| GCFillStyle
, &xgcv
);
476 XFreePixmap(dpy
, pixmap
);
481 ferror_set_temp_error_handler(BadGCErrorHandler
);
482 XFillRectangle(dpy
, pixmap
, fill_gc
, 0, 0, width
, height
);
485 CSETS_IS_TRANSPARENT_ROOT_PURE(colorset
) &&
486 colorset
->tint_percent
> 0)
488 FvwmRenderAttributes fra
;
490 fra
.mask
= FRAM_HAVE_TINT
;
491 fra
.tint
= colorset
->tint
;
492 fra
.tint_percent
= colorset
->tint_percent
;
493 PGraphicsRenderPixmaps(
494 dpy
, win
, pixmap
, None
, None
,
495 Pdepth
, &fra
, pixmap
,
498 0, 0, width
, height
, False
);
501 ferror_reset_temp_error_handler();
505 XFreePixmap(dpy
, pixmap
);
508 XFreeGC(dpy
,fill_gc
);
513 cs_pixmap
= colorset
->pixmap
;
514 cs_width
= colorset
->width
;
515 cs_height
= colorset
->height
;
517 (colorset
->pixmap_type
== PIXMAP_STRETCH_ASPECT
);
518 cs_stretch_x
= (colorset
->pixmap_type
== PIXMAP_STRETCH_X
)
519 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
520 cs_stretch_y
= (colorset
->pixmap_type
== PIXMAP_STRETCH_Y
)
521 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
525 /* In spite of the name, win contains the pixmap */
526 cs_pixmap
= colorset
->shape_mask
;
527 win
= colorset
->shape_mask
;
528 if (shape_gc
== None
)
532 /* create a gc for 1 bit depth */
533 shape_gc
= fvwmlib_XCreateGC(
534 dpy
, win
, GCForeground
|GCBackground
, &xgcv
);
537 cs_width
= colorset
->shape_width
;
538 cs_height
= colorset
->shape_height
;
539 cs_keep_aspect
= (colorset
->shape_type
== SHAPE_STRETCH_ASPECT
);
540 cs_stretch_x
= !(colorset
->shape_type
== SHAPE_TILED
);
541 cs_stretch_y
= !(colorset
->shape_type
== SHAPE_TILED
);
544 if (cs_pixmap
== None
)
546 xgcv
.foreground
= colorset
->bg
;
547 fill_gc
= fvwmlib_XCreateGC(dpy
, win
, GCForeground
, &xgcv
);
548 /* create a solid pixmap - not very useful most of the time */
549 pixmap
= XCreatePixmap(dpy
, win
, 1, 1, depth
);
550 XFillRectangle(dpy
, pixmap
, fill_gc
, 0, 0, 1, 1);
551 XFreeGC(dpy
,fill_gc
);
553 else if (cs_keep_aspect
)
556 int big_width
, big_height
;
560 /* make a pixmap big enough to cover the destination but with
561 * the aspect ratio of the cs_pixmap */
562 trim_side
= get_aspect_dimensions(
563 &big_width
, &big_height
, width
, height
, cs_width
,
565 big_pixmap
= CreateStretchPixmap(
566 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, big_width
,
569 /* work out where to trim */
570 x
= trim_side
? (big_width
- width
) / 2 : 0;
571 y
= trim_side
? 0 : (big_height
- height
) / 2;
573 pixmap
= XCreatePixmap(dpy
, cs_pixmap
, width
, height
, depth
);
574 if (pixmap
&& big_pixmap
)
577 dpy
, big_pixmap
, pixmap
, gc
, x
, y
, width
,
582 XFreePixmap(dpy
, big_pixmap
);
585 else if (!cs_stretch_x
&& !cs_stretch_y
)
587 /* it's a tiled pixmap, create an unstretched one */
590 pixmap
= XCreatePixmap(
591 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
);
595 dpy
, cs_pixmap
, pixmap
, gc
, 0, 0,
596 cs_width
, cs_height
, 0, 0);
601 /* can't tile masks, create a tiled version of the
603 pixmap
= CreateTiledPixmap(
604 dpy
, cs_pixmap
, cs_width
, cs_height
, width
,
608 else if (!cs_stretch_x
)
610 /* it's an HGradient */
611 pixmap
= CreateStretchYPixmap(
612 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, height
, gc
);
614 else if (!cs_stretch_y
)
616 /* it's a VGradient */
617 pixmap
= CreateStretchXPixmap(
618 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, width
, gc
);
622 /* It's a full window pixmap */
623 pixmap
= CreateStretchPixmap(
624 dpy
, cs_pixmap
, cs_width
, cs_height
, depth
, width
,
628 if (x
!= 0 || y
!= 0)
633 dpy
, pixmap
, gc
, x
, y
, width
, height
,
635 if (p2
!= None
&& p2
!= ParentRelative
&& p2
!= pixmap
)
637 XFreePixmap(dpy
, pixmap
);
645 /* create a pixmap suitable for plonking on the background of a window */
646 Pixmap
CreateBackgroundPixmap(Display
*dpy
, Window win
, int width
, int height
,
647 colorset_t
*colorset
, unsigned int depth
,
648 GC gc
, Bool is_shape_mask
)
650 return CreateOffsetBackgroundPixmap(
651 dpy
, win
, 0, 0, width
, height
, colorset
, depth
, gc
,
655 /* Draws a colorset background into the specified rectangle in the target
657 void SetRectangleBackground(
658 Display
*dpy
, Window win
, int x
, int y
, int width
, int height
,
659 colorset_t
*colorset
, unsigned int depth
, GC gc
)
661 SetClippedRectangleBackground(
662 dpy
, win
, x
, y
, width
, height
, NULL
, colorset
, depth
, gc
);
667 /* Draws a colorset background into the specified rectangle in the target
669 void SetClippedRectangleBackground(
670 Display
*dpy
, Window win
, int x
, int y
, int width
, int height
,
671 XRectangle
*clip
, colorset_t
*colorset
,
672 unsigned int depth
, GC gc
)
676 Pixmap pixmap
= None
;
677 static int last_depth
= -1;
678 static GC last_gc
= None
;
680 Pixmap clipmask
= None
;
682 Bool keep_aspect
= (colorset
->pixmap_type
== PIXMAP_STRETCH_ASPECT
);
683 Bool stretch_x
= (colorset
->pixmap_type
== PIXMAP_STRETCH_X
)
684 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
685 Bool stretch_y
= (colorset
->pixmap_type
== PIXMAP_STRETCH_Y
)
686 || (colorset
->pixmap_type
== PIXMAP_STRETCH
);
687 int dest_x
, dest_y
, dest_w
, dest_h
;
693 dest_w
= clip
->width
;
694 dest_h
= clip
->height
;
703 if (CSETS_IS_TRANSPARENT_PR_TINT(colorset
))
705 XClearArea(dpy
, win
, dest_x
, dest_y
, dest_w
, dest_h
, False
);
706 PGraphicsTintRectangle(
707 dpy
, win
, colorset
->tint
, colorset
->tint_percent
,
708 win
, True
, gc
, None
, None
,
709 dest_x
, dest_y
, dest_w
, dest_h
);
712 if (CSETS_IS_TRANSPARENT_PR_PURE(colorset
))
714 XClearArea(dpy
, win
, dest_x
, dest_y
, dest_w
, dest_h
, False
);
715 /* don't do anything */
718 if (CSETS_IS_TRANSPARENT_ROOT(colorset
))
720 /* FIXME: optimize this ! */
722 width
= width
+ dest_x
;
723 height
= height
+ dest_y
;
725 /* minimize gc creation by remembering the last requested depth */
726 if (last_gc
!= None
&& depth
!= last_depth
)
728 XFreeGC(dpy
, last_gc
);
733 last_gc
= fvwmlib_XCreateGC(dpy
, win
, 0, &xgcv
);
738 if (FHaveShapeExtension
&& colorset
->shape_mask
!= None
)
740 clipmask
= CreateBackgroundPixmap(
741 dpy
, 0, width
, height
, colorset
, 1, None
, True
);
744 /* create a GC for clipping */
745 xgcv
.clip_x_origin
= x
;
746 xgcv
.clip_y_origin
= y
;
747 xgcv
.clip_mask
= clipmask
;
748 clip_gc
= fvwmlib_XCreateGC(
749 dpy
, win
, GCClipXOrigin
| GCClipYOrigin
|
755 if (!colorset
->pixmap
)
757 /* use the bg pixel */
758 XSetForeground(dpy
, draw_gc
, colorset
->bg
);
760 dpy
, win
, draw_gc
, dest_x
, dest_y
, dest_w
, dest_h
);
764 pixmap
= CreateBackgroundPixmap(
765 dpy
, win
, width
, height
, colorset
, depth
, gc
, False
);
770 if (stretch_x
|| stretch_y
)
772 if (!stretch_x
&& colorset
->width
!= width
)
774 pixmap2
= CreateStretchXPixmap(
775 dpy
, pixmap
, colorset
->width
, height
,
777 XFreePixmap(dpy
, pixmap
);
780 if (!stretch_y
&& colorset
->height
!= height
)
782 pixmap2
= CreateStretchYPixmap(
783 dpy
, pixmap
, width
, colorset
->height
,
785 XFreePixmap(dpy
, pixmap
);
791 pixmap2
= CreateTiledPixmap(
792 dpy
, pixmap
, colorset
->width
, colorset
->height
,
793 width
, height
, depth
, gc
);
794 XFreePixmap(dpy
, pixmap
);
800 /* Copy the pixmap into the rectangle. */
802 dpy
, pixmap
, win
, draw_gc
,
803 dest_x
- x
, dest_y
- y
, dest_w
, dest_h
,
805 XFreePixmap(dpy
, pixmap
);
809 if (FHaveShapeExtension
)
811 if (clipmask
!= None
)
813 XFreePixmap(dpy
, clipmask
);
817 XFreeGC(dpy
, clip_gc
);