* FvwmTheme/FvwmTheme.1: Language check, general edits,
[fvwm.git] / libs / Colorset.c
blob861dbb01fab7fe62ddca9c0273fb1c0636f9888e
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
5 */
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)
9 * 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 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
24 #include "config.h"
26 #include <stdio.h>
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"
36 /* globals */
37 colorset_t *Colorset = NULL;
38 int nColorsets = 0;
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 */
48 if (n < nColorsets)
50 return;
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 */
59 if (n == 0)
61 memset(
62 &Colorset[nColorsets], 0,
63 (n - nColorsets) * sizeof(colorset_t));
65 else
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++)
71 memcpy(
72 &Colorset[nColorsets], Colorset,
73 sizeof(colorset_t));
76 nColorsets = n;
78 return;
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)
87 sprintf(csetbuf,
88 "Colorset "
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);
97 return csetbuf;
100 /*****************************************************************************
101 * LoadColorset() takes a strings and stuffs it into the array
102 *****************************************************************************/
103 int LoadColorset(char *line)
105 colorset_t *cs;
106 unsigned int n, chars;
107 Pixel fg, bg, hilite, shadow, fgsh, tint, icon_tint;
108 Pixmap pixmap;
109 Pixmap shape_mask;
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;
115 if (line == NULL)
117 return -1;
119 if (sscanf(line, "%x%n", &n, &chars) < 1)
121 return -1;
123 line += chars;
124 if (sscanf(line,
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)
132 return -1;
134 AllocColorset(n);
135 cs = &Colorset[n];
136 cs->fg = fg;
137 cs->bg = bg;
138 cs->hilite = hilite;
139 cs->shadow = shadow;
140 cs->fgsh = fgsh;
141 cs->tint = tint;
142 cs->icon_tint = icon_tint;
143 cs->pixmap = pixmap;
144 cs->shape_mask = shape_mask;
145 cs->fg_alpha_percent = fg_alpha_percent;
146 cs->width = width;
147 cs->height = height;
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;
157 return n;
160 /* scrolls a pixmap by x_off/y_off pixels, wrapping around at the edges. */
161 Pixmap ScrollPixmap(
162 Display *dpy, Pixmap p, GC gc, int x_off, int y_off, int width,
163 int height, unsigned int depth)
165 GC tgc;
166 XGCValues xgcv;
167 Pixmap p2;
169 if (p == None || p == ParentRelative || (x_off == 0 && y_off == 0))
171 return p;
173 tgc = fvwmlib_XCreateGC(dpy, p, 0, &xgcv);
174 if (tgc == None)
176 return p;
178 XCopyGC(dpy, gc, GCFunction | GCPlaneMask| GCSubwindowMode |
179 GCClipXOrigin | GCClipYOrigin | GCClipMask, tgc);
180 xgcv.tile = p;
181 xgcv.ts_x_origin = x_off;
182 xgcv.ts_y_origin = y_off;
183 xgcv.fill_style = FillTiled;
184 XChangeGC(
185 dpy, tgc, GCTile | GCTileStipXOrigin | GCTileStipYOrigin |
186 GCFillStyle, &xgcv);
187 p2 = XCreatePixmap(dpy, p, width, height, depth);
188 if (p2 == None)
190 return p;
192 XFillRectangle(dpy, p2, tgc, 0, 0, width, height);
193 XFreeGC(dpy, tgc);
195 return p2;
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;
206 Pixmap mask = None;
207 XID junk;
209 if (0 == width || 0 == height)
211 if (!XGetGeometry(
212 dpy, win, &junk, (int *)&junk, (int *)&junk,
213 (unsigned int *)&width, (unsigned int *)&height,
214 (unsigned int *)&junk, (unsigned int *)&junk))
216 return;
220 if (FHaveShapeExtension && colorset->shape_mask)
222 mask = CreateBackgroundPixmap(
223 dpy, 0, width, height, colorset, 1, None, True);
224 if (mask != None)
226 FShapeCombineMask(
227 dpy, win, FShapeBounding, 0, 0, mask,
228 FShapeSet);
229 XFreePixmap(dpy, mask);
232 if (!colorset->pixmap)
234 /* use the bg pixel */
235 XSetWindowBackground(dpy, win, colorset->bg);
236 if (clear_area)
238 XClearArea(dpy, win, 0, 0, width, height, True);
241 else
244 pixmap = CreateBackgroundPixmap(
245 dpy, win, width, height, colorset, depth, gc, False);
246 if (x_off != 0 || y_off != 0)
248 Pixmap p2;
250 p2 = ScrollPixmap(
251 dpy, pixmap, gc, x_off, y_off, width, height,
252 depth);
253 if (p2 != None && p2 != ParentRelative && p2 != pixmap)
255 XFreePixmap(dpy, pixmap);
256 pixmap = p2;
259 if (pixmap)
261 XSetWindowBackgroundPixmap(dpy, win, pixmap);
262 if (clear_area)
264 XClearArea(dpy, win, 0, 0, width, height, True);
266 if (pixmap != ParentRelative)
268 XFreePixmap(dpy, pixmap);
273 return;
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))
282 return False;
284 else if (!CSETS_IS_TRANSPARENT_PR_PURE(colorset))
286 SetWindowBackgroundWithOffset(
287 dpy, win, 0, 0, width, height, colorset, depth, gc,
288 True);
290 else
292 XClearArea(dpy, win, 0,0,0,0, clear_area);
295 return True;
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);
305 return;
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;
315 XGCValues xgcv;
316 static GC shape_gc = None;
317 GC fill_gc = None; /* not static as dpy may change (FvwmBacker) */
318 int cs_width;
319 int cs_height;
320 Bool cs_keep_aspect;
321 Bool cs_stretch_x;
322 Bool cs_stretch_y;
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;
332 XGrabServer(dpy);
333 pixmap = PGraphicsCreateTransprency(
334 dpy, win, &fra, gc, 0, 0, width, height, True);
335 XUngrabServer(dpy);
336 if (pixmap == None)
338 return ParentRelative;
340 return pixmap;
342 else if (colorset->pixmap == ParentRelative && !is_shape_mask)
344 return ParentRelative;
346 else if (CSETS_IS_TRANSPARENT_ROOT(colorset) && colorset->pixmap
347 && !is_shape_mask)
349 int sx,sy;
350 int h,w;
351 XID dummy;
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 */
359 XID dummy;
361 if (!XGetGeometry(
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))
368 return None;
370 if (w != cs_width || h != cs_height)
372 return None;
375 XTranslateCoordinates(
376 dpy, win, DefaultRootWindow(dpy), 0, 0, &sx, &sy,
377 &dummy);
378 pixmap = XCreatePixmap(dpy, win, width, height, Pdepth);
379 if (!pixmap)
381 return None;
383 /* make sx and sy positif */
384 while (sx < 0)
386 sx = sx + cs_width;
388 while (sy < 0)
390 sy = sy + cs_height;
392 /* make sx and sy in (0,0,cs_width,cs_height) */
393 while (sx >= cs_width)
395 sx = sx - cs_width;
397 while (sy >= cs_height)
399 sy = 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,
420 fill_gc, None, None,
421 0, 0, width, height,
422 0, 0, width, height, False);
424 XFreeGC(dpy,fill_gc);
425 return pixmap;
427 if (!is_shape_mask)
429 cs_pixmap = colorset->pixmap;
430 cs_width = colorset->width;
431 cs_height = colorset->height;
432 cs_keep_aspect =
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);
439 else
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)
446 xgcv.foreground = 1;
447 xgcv.background = 0;
448 /* create a gc for 1 bit depth */
449 shape_gc = fvwmlib_XCreateGC(
450 dpy, win, GCForeground|GCBackground, &xgcv);
452 gc = shape_gc;
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)
471 Bool trim_side;
472 int big_width, big_height;
473 Pixmap big_pixmap;
474 int x, y;
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,
485 big_height, gc);
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)
494 XCopyArea(
495 dpy, big_pixmap, pixmap, gc, x, y, width, height,
496 0, 0);
498 if (big_pixmap)
500 XFreePixmap(dpy, big_pixmap);
503 else if (!cs_stretch_x && !cs_stretch_y)
505 /* it's a tiled pixmap, create an unstretched one */
506 if (!is_shape_mask)
508 pixmap = XCreatePixmap(
509 dpy, cs_pixmap, cs_width, cs_height, depth);
510 if (pixmap)
512 XCopyArea(
513 dpy, cs_pixmap, pixmap, gc, 0, 0,
514 cs_width, cs_height, 0, 0);
517 else
519 /* can't tile masks, create a tiled version of the
520 * mask */
521 pixmap = CreateTiledPixmap(
522 dpy, cs_pixmap, cs_width, cs_height, width,
523 height, 1, gc);
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);
538 else
540 /* It's a full window pixmap */
541 pixmap = CreateStretchPixmap(
542 dpy, cs_pixmap, cs_width, cs_height, depth, width,
543 height, gc);
546 return pixmap;
550 /* Draws a colorset background into the specified rectangle in the target
551 * drawable. */
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);
559 return;
562 /* Draws a colorset background into the specified rectangle in the target
563 * drawable. */
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)
569 GC draw_gc;
570 Pixmap pixmap2;
571 Pixmap pixmap = None;
572 static int last_depth = -1;
573 static GC last_gc = None;
574 XGCValues xgcv;
575 Pixmap clipmask = None;
576 GC clip_gc = 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;
584 if (clip)
586 dest_x = clip->x;
587 dest_y = clip->y;
588 dest_w = clip->width;
589 dest_h = clip->height;
591 else
593 dest_x = x;
594 dest_y = y;
595 dest_w = width;
596 dest_h = 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);
605 return;
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 */
611 return;
613 if (CSETS_IS_TRANSPARENT_ROOT(colorset))
615 /* FIXME: optimize this ! */
616 x = y = 0;
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);
624 last_gc = None;
626 if (last_gc == None)
628 last_gc = fvwmlib_XCreateGC(dpy, win, 0, &xgcv);
630 draw_gc = last_gc;
631 last_depth = depth;
633 if (FHaveShapeExtension && colorset->shape_mask != None)
635 clipmask = CreateBackgroundPixmap(
636 dpy, 0, width, height, colorset, 1, None, True);
637 if (clipmask)
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 |
645 GCClipMask, &xgcv);
646 draw_gc = clip_gc;
650 if (!colorset->pixmap)
652 /* use the bg pixel */
653 XSetForeground(dpy, draw_gc, colorset->bg);
654 XFillRectangle(
655 dpy, win, draw_gc, dest_x, dest_y, dest_w, dest_h);
657 else
659 pixmap = CreateBackgroundPixmap(
660 dpy, win, width, height, colorset, depth, gc, False);
661 if (keep_aspect)
663 /* nothing to do */
665 if (stretch_x || stretch_y)
667 if (!stretch_x && colorset->width != width)
669 pixmap2 = CreateStretchXPixmap(
670 dpy, pixmap, colorset->width, height,
671 depth, width, gc);
672 XFreePixmap(dpy, pixmap);
673 pixmap = pixmap2;
675 if (!stretch_y && colorset->height != height)
677 pixmap2 = CreateStretchYPixmap(
678 dpy, pixmap, width, colorset->height,
679 depth, height, gc);
680 XFreePixmap(dpy, pixmap);
681 pixmap = pixmap2;
684 else
686 pixmap2 = CreateTiledPixmap(
687 dpy, pixmap, colorset->width, colorset->height,
688 width, height, depth, gc);
689 XFreePixmap(dpy, pixmap);
690 pixmap = pixmap2;
693 if (pixmap)
695 /* Copy the pixmap into the rectangle. */
696 XCopyArea(
697 dpy, pixmap, win, draw_gc,
698 dest_x - x, dest_y - y, dest_w, dest_h,
699 dest_x, dest_y);
700 XFreePixmap(dpy, pixmap);
704 if (FHaveShapeExtension)
706 if (clipmask != None)
708 XFreePixmap(dpy, clipmask);
710 if (clip_gc != None)
712 XFreeGC(dpy, clip_gc);
716 return;