2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 /* Graphics.c: misc convenience functions for drawing stuff */
19 /* ---------------------------- included header files ---------------------- */
28 #include "libs/fvwmlib.h"
29 #include "libs/PictureBase.h"
30 #include "libs/PictureUtils.h"
31 #include "libs/PictureGraphics.h"
32 #include "libs/gravity.h"
33 #include "libs/FImage.h"
35 /* ---------------------------- local definitions -------------------------- */
37 /* Define some standard constants that are not defined on QNX 4.25 */
39 #define M_PI 3.14159265358979323846
42 #define M_PI_2 1.57079632679489661923
45 /* ---------------------------- local macros ------------------------------- */
47 /* ---------------------------- imports ------------------------------------ */
49 /* ---------------------------- included code files ------------------------ */
51 /* ---------------------------- local types -------------------------------- */
53 /* ---------------------------- forward declarations ----------------------- */
55 /* ---------------------------- local variables ---------------------------- */
57 /* ---------------------------- exported variables (globals) --------------- */
59 /* ---------------------------- local functions ---------------------------- */
61 /* ---------------------------- interface functions ------------------------ */
63 /* Draws the relief pattern around a window
64 * Draws a line_width wide rectangle from (x,y) to (x+w,y+h) i.e w+1 wide,
66 * Draws end points assuming CAP_NOT_LAST style in GC
67 * Draws anti-clockwise in case CAP_BUTT is the style and the end points overlap
68 * Top and bottom lines come out full length, the sides come out 1 pixel less
69 * This is so FvwmBorder windows have a correct bottom edge and the sticky lines
70 * look like just lines
71 * rotation rotate the relief and shadow part
73 void do_relieve_rectangle_with_rotation(
74 Display
*dpy
, Drawable d
, int x
, int y
, int w
, int h
,
75 GC ReliefGC
, GC ShadowGC
, int line_width
, Bool use_alternate_shading
,
79 GC shadow_gc
, relief_gc
;
84 a
= (use_alternate_shading
) ? 1 : 0;
90 /* If line_width is negative, reverse the rotation, which will */
91 /* have the effect of inverting the relief. */
94 line_width
= -line_width
;
95 rotation
= gravity_add_rotations(rotation
, ROTATION_180
);
101 rotation
= gravity_add_rotations(rotation
, ROTATION_180
);
102 shadow_gc
= ReliefGC
;
103 relief_gc
= ShadowGC
;
106 shadow_gc
= ShadowGC
;
107 relief_gc
= ReliefGC
;
110 seg
= (XSegment
*)alloca((sizeof(XSegment
) * line_width
) * 2);
111 /* from 0 to the lesser of line_width & just over half w */
112 for (i
= 0; (i
< line_width
) && (i
<= w
/ 2); i
++)
114 if (rotation
== ROTATION_0
)
117 seg
[i
].x1
= x
+i
; seg
[i
].y1
= y
+i
+a
;
118 seg
[i
].x2
= x
+i
; seg
[i
].y2
= y
+h
-i
+a
;
120 else /* ROTATION_90 */
123 seg
[i
].x1
= x
+w
-i
; seg
[i
].y1
= y
+h
-i
-a
;
124 seg
[i
].x2
= x
+w
-i
; seg
[i
].y2
= y
+i
+1-a
;
128 /* draw top segments */
129 for (i
= 0; (i
< line_width
) && (i
<= h
/ 2); i
++,i2
++)
131 seg
[i2
].x1
= x
+w
-i
-a
; seg
[i2
].y1
= y
+i
;
132 seg
[i2
].x2
= x
+i
+1-a
; seg
[i2
].y2
= y
+i
;
134 XDrawSegments(dpy
, d
, relief_gc
, seg
, i2
);
136 for (i
= 0; (i
< line_width
) && (i
<= h
/ 2); i
++)
138 seg
[i
].x1
= x
+i
+a
+l
; seg
[i
].y1
= y
+h
-i
;
139 seg
[i
].x2
= x
+w
-i
-1+a
; seg
[i
].y2
= y
+h
-i
;
142 for (i
= 0; (i
< line_width
) && (i
<= w
/ 2); i
++,i2
++)
144 if (rotation
== ROTATION_0
)
147 seg
[i2
].x1
= x
+w
-i
; seg
[i2
].y1
= y
+h
-i
-a
;
148 seg
[i2
].x2
= x
+w
-i
; seg
[i2
].y2
= y
+i
+1-a
;
150 else /* ROTATION_90 */
153 seg
[i2
].x1
= x
+i
; seg
[i2
].y1
= y
+i
+a
;
154 seg
[i2
].x2
= x
+i
; seg
[i2
].y2
= y
+h
-i
+a
;
157 XDrawSegments(dpy
, d
, shadow_gc
, seg
, i2
);
162 void do_relieve_rectangle(
163 Display
*dpy
, Drawable d
, int x
, int y
, int w
, int h
,
164 GC ReliefGC
, GC ShadowGC
, int line_width
, Bool use_alternate_shading
)
166 do_relieve_rectangle_with_rotation(
167 dpy
, d
, x
, y
, w
, h
, ReliefGC
, ShadowGC
, line_width
,
168 use_alternate_shading
, ROTATION_0
);
172 /* Creates a pixmap that is a horizontally stretched version of the input
175 Pixmap
CreateStretchXPixmap(
176 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int src_depth
,
177 int dest_width
, GC gc
)
183 if (src_width
< 0 || src_height
< 0 || dest_width
< 0)
187 pixmap
= XCreatePixmap(dpy
, src
, dest_width
, src_height
, src_depth
);
194 my_gc
= fvwmlib_XCreateGC(dpy
, pixmap
, 0, 0);
196 for (i
= 0; i
< dest_width
; i
++)
199 dpy
, src
, pixmap
, (gc
== None
)? my_gc
:gc
,
200 (i
* src_width
) / dest_width
, 0, 1, src_height
, i
, 0);
210 /* Creates a pixmap that is a vertically stretched version of the input
213 Pixmap
CreateStretchYPixmap(
214 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int src_depth
,
215 int dest_height
, GC gc
)
221 if (src_height
< 0 || src_depth
< 0 || dest_height
< 0)
225 pixmap
= XCreatePixmap(dpy
, src
, src_width
, dest_height
, src_depth
);
232 my_gc
= fvwmlib_XCreateGC(dpy
, pixmap
, 0, 0);
234 for (i
= 0; i
< dest_height
; i
++)
237 dpy
, src
, pixmap
, (gc
== None
)? my_gc
:gc
,
238 0, (i
* src_height
) / dest_height
, src_width
, 1, 0, i
);
248 /* Creates a pixmap that is a stretched version of the input
251 Pixmap
CreateStretchPixmap(
252 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int src_depth
,
253 int dest_width
, int dest_height
, GC gc
)
255 Pixmap pixmap
= None
;
259 if (src_width
< 0 || src_height
< 0 || src_depth
< 0 || dest_width
< 0)
265 my_gc
= fvwmlib_XCreateGC(dpy
, src
, 0, 0);
267 temp_pixmap
= CreateStretchXPixmap(
268 dpy
, src
, src_width
, src_height
, src_depth
, dest_width
,
269 (gc
== None
)? my_gc
:gc
);
270 if (temp_pixmap
== None
)
278 pixmap
= CreateStretchYPixmap(
279 dpy
, temp_pixmap
, dest_width
, src_height
, src_depth
,
280 dest_height
, (gc
== None
)? my_gc
:gc
);
281 XFreePixmap(dpy
, temp_pixmap
);
289 /* Creates a pixmap that is a tiled version of the input pixmap. Modifies the
290 * sets the fill_style of the GC to FillSolid and the tile to None. */
291 Pixmap
CreateTiledPixmap(
292 Display
*dpy
, Pixmap src
, int src_width
, int src_height
,
293 int dest_width
, int dest_height
, int depth
, GC gc
)
298 if (src_width
< 0 || src_height
< 0 ||
299 dest_width
< 0 || dest_height
< 0)
303 pixmap
= XCreatePixmap(dpy
, src
, dest_width
, dest_height
, depth
);
308 xgcv
.fill_style
= FillTiled
;
310 xgcv
.ts_x_origin
= 0;
311 xgcv
.ts_y_origin
= 0;
313 dpy
, gc
, GCFillStyle
| GCTile
| GCTileStipXOrigin
|
314 GCTileStipYOrigin
, &xgcv
);
315 XFillRectangle(dpy
, pixmap
, gc
, 0, 0, dest_width
, dest_height
);
316 xgcv
.fill_style
= FillSolid
;
317 XChangeGC(dpy
, gc
, GCFillStyle
, &xgcv
);
322 Pixmap
CreateRotatedPixmap(
323 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int depth
,
327 Pixmap pixmap
= None
;
328 int dest_width
, dest_height
, i
, j
;
331 FImage
*src_fim
= NULL
;
333 if (src_width
<= 0 || src_height
<= 0)
341 dest_width
= src_height
;
342 dest_height
= src_width
;
346 dest_width
= src_width
;
347 dest_height
= src_height
;
353 pixmap
= XCreatePixmap(dpy
, src
, dest_width
, dest_height
, depth
);
360 my_gc
= fvwmlib_XCreateGC(dpy
, src
, 0, 0);
362 if (rotation
== ROTATION_0
)
365 dpy
, src
, pixmap
, (gc
== None
)? my_gc
:gc
,
366 0, 0, src_width
, src_height
, 0, 0);
370 if (!(src_fim
= FGetFImage(
371 dpy
, src
, Pvisual
, depth
, 0, 0, src_width
, src_height
,
372 AllPlanes
, ZPixmap
)))
377 if (!(fim
= FCreateFImage(
378 dpy
, Pvisual
, depth
, ZPixmap
, dest_width
, dest_height
)))
384 for (j
= 0; j
< src_height
; j
++)
386 for (i
= 0; i
< src_width
; i
++)
392 fim
->im
, j
, src_width
- i
- 1,
393 XGetPixel(src_fim
->im
, i
, j
));
397 fim
->im
, src_height
- j
- 1, i
,
398 XGetPixel(src_fim
->im
, i
, j
));
403 src_width
- i
- 1, src_height
- j
- 1,
404 XGetPixel(src_fim
->im
, i
, j
));
411 FPutFImage(dpy
, pixmap
, gc
, fim
, 0, 0, 0, 0, dest_width
, dest_height
);
415 XFreePixmap(dpy
,pixmap
);
420 FDestroyFImage(dpy
, fim
);
424 FDestroyFImage(dpy
, src_fim
);
435 * Returns True if the given type of gradient is supported.
438 Bool
IsGradientTypeSupported(char type
)
440 switch (toupper(type
))
452 fprintf(stderr
, "%cGradient type is not supported\n",
460 * Allocates a linear color gradient (veliaa@rpi.edu)
464 XColor
*AllocLinearGradient(
465 char *s_from
, char *s_to
, int npixels
, int skip_first_color
, int dither
)
482 "AllocLinearGradient: Invalid number of pixels: %d\n",
486 if (!s_from
|| !XParseColor(Pdpy
, Pcmap
, s_from
, &from
))
488 fprintf(stderr
, "Cannot parse color \"%s\"\n",
489 s_from
? s_from
: "<blank>");
492 if (!s_to
|| !XParseColor(Pdpy
, Pcmap
, s_to
, &to
))
494 fprintf(stderr
, "Cannot parse color \"%s\"\n",
495 s_to
? s_to
: "<blank>");
499 /* divisor must not be zero, hence this calculation */
500 div
= (npixels
== 1) ? 1 : npixels
- 1;
502 /* red part and step width */
504 dr
= (float)(to
.red
- from
.red
);
505 /* green part and step width */
507 dg
= (float)(to
.green
- from
.green
);
508 /* blue part and step width */
510 db
= (float)(to
.blue
- from
.blue
);
511 xcs
= (XColor
*)safemalloc(sizeof(XColor
) * npixels
);
512 memset(xcs
, 0, sizeof(XColor
) * npixels
);
513 c
.flags
= DoRed
| DoGreen
| DoBlue
;
514 for (i
= (skip_first_color
) ? 1 : 0; i
< npixels
&& div
> 0; ++i
)
516 c
.red
= (unsigned short)
517 ((int)(r
+ dr
/ (float)div
* (float)i
+ 0.5));
518 c
.green
= (unsigned short)
519 ((int)(g
+ dg
/ (float)div
* (float)i
+ 0.5));
520 c
.blue
= (unsigned short)
521 ((int)(b
+ db
/ (float)div
* (float)i
+ 0.5));
522 if (dither
== 0 && !PictureAllocColor(Pdpy
, Pcmap
, &c
, False
))
528 if (!got_all
&& dither
== 0)
530 fprintf(stderr
, "Cannot alloc color gradient %s to %s\n",
539 * Allocates a nonlinear color gradient (veliaa@rpi.edu)
542 static XColor
*AllocNonlinearGradient(
543 char *s_colors
[], int clen
[], int nsegs
, int npixels
, int dither
)
545 XColor
*xcs
= (XColor
*)safemalloc(sizeof(XColor
) * npixels
);
550 float color_sum
= 0.0;
552 if (nsegs
< 1 || npixels
< 2)
555 "Gradients must specify at least one segment and"
560 for (i
= 0; i
< npixels
; i
++)
565 /* get total length of all segments */
566 for (i
= 0; i
< nsegs
; i
++)
571 /* calculate the index of a segment's las color */
572 seg_end_colors
= alloca(nsegs
* sizeof(int));
575 seg_end_colors
[0] = npixels
- 1;
579 for (i
= 0; i
< nsegs
; i
++)
581 color_sum
+= (float)(clen
[i
] * (npixels
- 1)) /
583 seg_end_colors
[i
] = (int)(color_sum
+ 0.5);
585 if (seg_end_colors
[nsegs
- 1] > npixels
- 1)
588 "BUG: (AllocNonlinearGradient): "
589 "seg_end_colors[nsegs - 1] (%d)"
590 " > npixels - 1 (%d)."
591 " Gradient drawing aborted\n",
592 seg_end_colors
[nsegs
- 1], npixels
- 1);
595 /* take care of rounding errors */
596 seg_end_colors
[nsegs
- 1] = npixels
- 1;
599 for (i
= 0; i
< nsegs
; ++i
)
604 int skip_first_color
= (curpixel
!= 0);
608 n
= seg_end_colors
[0] + 1;
612 n
= seg_end_colors
[i
] - seg_end_colors
[i
- 1] + 1;
617 c
= AllocLinearGradient(
618 s_colors
[i
], s_colors
[i
+ 1], n
,
619 skip_first_color
, dither
);
620 if (!c
&& (n
- skip_first_color
) != 0)
625 for (j
= skip_first_color
; j
< n
; ++j
)
627 xcs
[curpixel
+ j
] = c
[j
];
636 if (curpixel
!= seg_end_colors
[i
])
639 "BUG: (AllocNonlinearGradient): "
640 "nsegs %d, i %d, curpixel %d,"
641 " seg_end_colors[i] = %d,"
642 " npixels %d, n %d\n",
644 seg_end_colors
[i
],npixels
,n
);
651 /* Convenience function. Calls AllocNonLinearGradient to fetch all colors and
652 * then frees the color names and the perc and color_name arrays. */
653 XColor
*AllocAllGradientColors(
654 char *color_names
[], int perc
[], int nsegs
, int ncolors
, int dither
)
659 /* grab the colors */
660 xcs
= AllocNonlinearGradient(
661 color_names
, perc
, nsegs
, ncolors
, dither
);
662 for (i
= 0; i
<= nsegs
; i
++)
666 free(color_names
[i
]);
673 fprintf(stderr
, "couldn't create gradient\n");
680 /* groks a gradient string and creates arrays of colors and percentages
681 * returns the number of colors asked for (No. allocated may be less due
682 * to the ColorLimit command). A return of 0 indicates an error
684 unsigned int ParseGradient(
685 char *gradient
, char **rest
, char ***colors_return
, int **perc_return
,
690 unsigned int npixels
;
694 Bool is_syntax_error
= False
;
696 /* get the number of colors specified */
703 if (GetIntegerArguments(gradient
, &gradient
, (int *)&npixels
, 1) != 1 ||
707 stderr
, "ParseGradient: illegal number of colors in"
708 " gradient: '%s'\n", orig
);
712 /* get the starting color or number of segments */
713 gradient
= GetNextToken(gradient
, &item
);
716 gradient
= SkipSpaces(gradient
, NULL
, 0);
718 if (!gradient
|| !*gradient
|| !item
)
720 fprintf(stderr
, "Incomplete gradient style: '%s'\n", orig
);
732 if (GetIntegerArguments(item
, NULL
, &nsegs
, 1) != 1)
734 /* get the end color of a simple gradient */
735 s_colors
= (char **)safemalloc(sizeof(char *) * 2);
736 perc
= (int *)safemalloc(sizeof(int));
739 gradient
= GetNextToken(gradient
, &item
);
746 /* get a list of colors and percentages */
749 if (nsegs
> MAX_GRADIENT_SEGMENTS
)
750 nsegs
= MAX_GRADIENT_SEGMENTS
;
751 s_colors
= (char **)safemalloc(sizeof(char *) * (nsegs
+ 1));
752 perc
= (int *)safemalloc(sizeof(int) * nsegs
);
753 for (i
= 0; !is_syntax_error
&& i
<= nsegs
; i
++)
756 gradient
= GetNextToken(gradient
, &s_colors
[i
]);
759 if (GetIntegerArguments(
760 gradient
, &gradient
, &perc
[i
], 1)
761 != 1 || perc
[i
] <= 0)
768 if (s_colors
[nsegs
] == NULL
)
771 stderr
, "ParseGradient: too few gradient"
772 " segments: '%s'\n", orig
);
773 is_syntax_error
= True
;
778 for (i
= 0, sum
= 0; !is_syntax_error
&& i
< nsegs
; ++i
)
785 /* integer overflow */
787 stderr
, "ParseGradient: multi gradient"
788 " overflow: '%s'", orig
);
795 for (i
= 0; i
<= nsegs
; ++i
)
812 /* sensible limits */
815 if (npixels
> MAX_GRADIENT_COLORS
)
816 npixels
= MAX_GRADIENT_COLORS
;
819 *colors_return
= s_colors
;
821 *nsegs_return
= nsegs
;
828 /* Calculate the prefered dimensions of a gradient, based on the number of
829 * colors and the gradient type. Returns False if the gradient type is not
831 Bool
CalculateGradientDimensions(
832 Display
*dpy
, Drawable d
, int ncolors
, char type
, int dither
,
833 unsigned int *width_ret
, unsigned int *height_ret
)
835 static unsigned int best_width
= 0, best_height
= 0;
836 int dither_factor
= (dither
> 0)? 128:1;
838 /* get the best tile size (once) */
841 if (!XQueryBestTile(dpy
, d
, 1, 1, &best_width
, &best_height
))
846 /* this is needed for buggy X servers like XFree 3.3.3.1 */
855 *width_ret
= ncolors
;
856 *height_ret
= best_height
* dither_factor
;
859 *width_ret
= best_width
* dither_factor
;
860 *height_ret
= ncolors
;
864 /* diagonal gradients are rendered into a rectangle for which
865 * the width plus the height is equal to ncolors + 1. The
866 * rectangle is square when ncolors is odd and one pixel
867 * taller than wide with even numbers */
868 *width_ret
= (ncolors
+ 1) / 2;
869 *height_ret
= ncolors
+ 1 - *width_ret
;
872 /* square gradients have the last color as a single pixel in
874 *width_ret
= *height_ret
= 2 * ncolors
- 1;
877 /* circular gradients have the first color as a pixel in each
879 *width_ret
= *height_ret
= 2 * ncolors
- 1;
883 /* swept types need each color to occupy at least one pixel at
884 * the edge. Get the smallest odd number that will provide
887 (double)(*width_ret
- 1) * M_PI
< (double)ncolors
;
890 /* nothing to do here */
892 *height_ret
= *width_ret
;
895 fprintf(stderr
, "%cGradient not supported\n", type
);
901 /* Does the actual drawing of the pixmap. If the in_drawable argument is None,
902 * a new pixmap of the given depth, width and height is created. If it is not
903 * None the gradient is drawn into it. The d_width, d_height, d_x and d_y
904 * describe the traget rectangle within the drawable. */
905 Drawable
CreateGradientPixmap(
906 Display
*dpy
, Drawable d
, GC gc
, int type
, int g_width
, int g_height
,
907 int ncolors
, XColor
*xcs
, int dither
, Pixel
**d_pixels
, int *d_npixels
,
908 Drawable in_drawable
, int d_x
, int d_y
, int d_width
, int d_height
,
911 Pixmap pixmap
= None
;
912 PictureImageColorAllocator
*pica
= NULL
;
924 if (d_pixels
!= NULL
&& *d_pixels
!= NULL
)
926 if (d_npixels
!= NULL
&& *d_npixels
> 0)
929 dpy
, Pcmap
, *d_pixels
, *d_npixels
, 0, False
);
934 if (d_npixels
!= NULL
)
938 if (g_height
< 0 || g_width
< 0 || d_width
< 0 || d_height
< 0)
941 if (in_drawable
== None
)
943 /* create a pixmap to use */
944 pixmap
= XCreatePixmap(dpy
, d
, g_width
, g_height
, Pdepth
);
955 target
= in_drawable
;
963 dpy
, Pvisual
, Pdepth
, ZPixmap
, t_width
, t_height
);
966 fprintf(stderr
, "%cGradient couldn't get image\n", type
);
968 XFreePixmap(dpy
, pixmap
);
973 pica
= PictureOpenImageColorAllocator(
974 dpy
, Pcmap
, t_width
, t_height
,
975 False
, False
, dither
, False
);
977 ps
= t_width
* t_height
;
978 /* now do the fancy drawing */
983 for (i
= 0; i
< t_width
; i
++)
985 int d
= i
* ncolors
/ t_width
;
987 for (j
= 0; j
< t_height
; j
++)
992 PictureAllocColorImage(
993 dpy
, pica
, &c
, i
, j
);
995 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1002 for (j
= 0; j
< t_height
; j
++)
1004 int d
= j
* ncolors
/ t_height
;
1006 for (i
= 0; i
< t_width
; i
++)
1011 PictureAllocColorImage(
1012 dpy
, pica
, &c
, i
, j
);
1014 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1021 register int t_scale
= t_width
+ t_height
- 1;
1022 for (i
= 0; i
< t_width
; i
++)
1024 for (j
= 0; j
< t_height
; j
++)
1026 c
= xcs
[(i
+j
) * ncolors
/ t_scale
];
1029 PictureAllocColorImage(
1030 dpy
, pica
, &c
, i
, j
);
1032 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1039 register int t_scale
= t_width
+ t_height
- 1;
1040 for (i
= 0; i
< t_width
; i
++)
1042 for (j
= 0; j
< t_height
; j
++)
1044 c
= xcs
[(i
+ (t_height
- j
- 1)) * ncolors
/
1048 PictureAllocColorImage(
1049 dpy
, pica
, &c
, i
, j
);
1051 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1058 register int t_scale
= t_width
* t_height
;
1059 register int myncolors
= ncolors
* 2;
1060 for (i
= 0; i
< t_width
; i
++) {
1061 register int pi
= min(i
, t_width
- 1 - i
) * t_height
;
1062 for (j
= 0; j
< t_height
; j
++) {
1064 min(j
, t_height
- 1 - j
) * t_width
;
1065 c
= xcs
[(min(pi
, pj
) * myncolors
- 1) /
1069 PictureAllocColorImage(
1070 dpy
, pica
, &c
, i
, j
);
1072 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1079 register double t_scale
=
1080 (double)(t_width
* t_height
) / sqrt(8);
1081 for (i
= 0; i
< t_width
; i
++)
1083 for (j
= 0; j
< t_height
; j
++)
1086 (double)((2 * i
- t_width
) * t_height
) /
1089 (double)((t_height
- 2 * j
) * t_width
) /
1091 register double rad
= sqrt(x
* x
+ y
* y
);
1092 c
= xcs
[(int)((rad
* ncolors
- 0.5) / t_scale
)];
1095 PictureAllocColorImage(
1096 dpy
, pica
, &c
, i
, j
);
1098 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1105 register int w
= t_width
- 1;
1106 register int h
= t_height
- 1;
1107 /* g_width == g_height, both are odd, therefore x can be 0.0 */
1108 for (i
= 0; i
<= w
; i
++) {
1109 for (j
= 0; j
<= h
; j
++) {
1111 (double)((2 * i
- w
) * h
) / 4.0;
1113 (double)((h
- 2 * j
) * w
) / 4.0;
1114 /* angle ranges from -pi/2 to +pi/2 */
1115 register double angle
;
1117 angle
= atan(y
/ x
);
1119 angle
= (y
< 0) ? - M_PI_2
: M_PI_2
;
1121 /* extend to -pi/2 to 3pi/2 */
1124 /* move range from -pi/2:3*pi/2 to 0:2*pi */
1126 angle
+= M_PI
* 2.0;
1127 /* normalize to gradient */
1128 c
= xcs
[(int)(angle
* M_1_PI
* 0.5 * ncolors
)];
1131 PictureAllocColorImage(
1132 dpy
, pica
, &c
, i
, j
);
1134 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1140 * The Yin Yang gradient style and the following code are:
1141 * Copyright 1999 Sir Boris. (email to sir_boris@bigfoot.com may be
1142 * read by his groom but is not guaranteed to elicit a response)
1143 * No restrictions are placed on this code, as long as the copyright
1144 * notice is preserved.
1148 register int r
= t_width
* t_height
/ 4;
1149 for (i
= 0; i
< t_width
; i
++) {
1150 for (j
= 0; j
< t_height
; j
++) {
1152 (double)((2 * i
- t_width
) * t_height
) /
1155 (double)((t_height
- 2 * j
) * t_width
) /
1157 register double rad
= sqrt(x
* x
+ y
* y
);
1158 /* angle ranges from -pi/2 to +pi/2 */
1159 register double angle
;
1162 angle
= atan(y
/ x
);
1164 angle
= (y
< 0) ? - M_PI_2
: M_PI_2
;
1166 /* extend to -pi/2 to 3pi/2 */
1169 /* warp the angle within the yinyang circle */
1171 angle
-= acos(rad
/ r
);
1173 /* move range from -pi/2:3*pi/2 to 0:2*pi */
1175 angle
+= M_PI
* 2.0;
1176 /* normalize to gradient */
1177 c
= xcs
[(int)(angle
* M_1_PI
* 0.5 * ncolors
)];
1180 PictureAllocColorImage(
1181 dpy
, pica
, &c
, i
, j
);
1183 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1189 /* placeholder function, just fills the pixmap with the first
1191 memset(fim
->im
->data
, 0, fim
->im
->bytes_per_line
* t_height
);
1192 XAddPixel(fim
->im
, xcs
[0].pixel
);
1198 if (d_pixels
!= NULL
&& d_npixels
!= NULL
)
1200 PictureCloseImageColorAllocator(
1201 dpy
, pica
, d_npixels
, d_pixels
, 0);
1205 /* possible color leak */
1209 /* set the gc style */
1210 xgcv
.function
= GXcopy
;
1211 xgcv
.plane_mask
= AllPlanes
;
1212 xgcv
.fill_style
= FillSolid
;
1213 xgcv
.clip_mask
= None
;
1214 XChangeGC(dpy
, gc
, GCFunction
|GCPlaneMask
|GCFillStyle
|GCClipMask
,
1218 XSetClipRectangles(dpy
, gc
, 0, 0, rclip
, 1, Unsorted
);
1220 /* copy the image to the server */
1221 FPutFImage(dpy
, target
, gc
, fim
, 0, 0, t_x
, t_y
, t_width
, t_height
);
1224 XSetClipMask(dpy
, gc
, None
);
1226 FDestroyFImage(dpy
, fim
);
1231 /* Create a pixmap from a gradient specifier, width and height are hints
1232 * that are only used for gradients that can be tiled e.g. H or V types
1233 * types are HVDBSCRY for Horizontal, Vertical, Diagonal, Back-diagonal, Square,
1234 * Circular, Radar and Yin/Yang respectively (in order of bloatiness)
1236 Pixmap
CreateGradientPixmapFromString(
1237 Display
*dpy
, Drawable d
, GC gc
, int type
, char *action
,
1238 unsigned int *width_return
, unsigned int *height_return
,
1239 Pixel
**pixels_return
, int *nalloc_pixels
, int dither
)
1241 Pixel
*d_pixels
= NULL
;
1242 unsigned int d_npixels
= 0;
1244 unsigned int ncolors
= 0;
1247 Pixmap pixmap
= None
;
1249 /* set return pixels to NULL in case of premature return */
1251 *pixels_return
= NULL
;
1255 /* translate the gradient string into an array of colors etc */
1256 if (!(ncolors
= ParseGradient(action
, NULL
, &colors
, &perc
, &nsegs
))) {
1257 fprintf(stderr
, "Can't parse gradient: '%s'\n", action
);
1260 /* grab the colors */
1261 xcs
= AllocAllGradientColors(
1262 colors
, perc
, nsegs
, ncolors
, dither
);
1268 /* grok the size to create from the type */
1269 type
= toupper(type
);
1271 if (CalculateGradientDimensions(
1272 dpy
, d
, ncolors
, type
, dither
, width_return
, height_return
))
1274 pixmap
= CreateGradientPixmap(
1275 dpy
, d
, gc
, type
, *width_return
, *height_return
,
1276 ncolors
, xcs
, dither
, &d_pixels
, &d_npixels
,
1277 None
, 0, 0, 0, 0, NULL
);
1280 /* if the caller has not asked for the pixels there is probably a leak
1282 if (PUseDynamicColors
)
1284 if (!(pixels_return
&& nalloc_pixels
))
1286 /* if the caller has not asked for the pixels there is
1287 * probably a leak */
1289 "CreateGradient: potential color leak, losing track"
1291 if (d_pixels
!= NULL
)
1303 pixels
= (Pixel
*)safemalloc(
1304 ncolors
* sizeof(Pixel
));
1305 for(i
=0; i
<ncolors
; i
++)
1307 pixels
[i
] = xcs
[i
].pixel
;
1309 *pixels_return
= pixels
;
1310 *nalloc_pixels
= ncolors
;
1314 *pixels_return
= d_pixels
;
1315 *nalloc_pixels
= d_npixels
;
1319 else if (d_pixels
!= NULL
)
1321 /* should not happen */
1332 * Draws a little Triangle pattern within a window
1335 void DrawTrianglePattern(
1336 Display
*dpy
, Drawable d
, GC ReliefGC
, GC ShadowGC
, GC FillGC
,
1337 int x
, int y
, int width
, int height
, int bw
, char orientation
,
1338 Bool draw_relief
, Bool do_fill
, Bool is_pressed
)
1343 const char point
[3];
1346 { { 1, 0, 0 }, { 1, 1, 0 } }, /* up */
1347 { { 1, 0, 1 }, { 1, 0, 0 } }, /* down */
1348 { { 1, 0, 0 }, { 1, 1, 0 } }, /* left */
1349 { { 1, 0, 1 }, { 1, 1, 0 } } /* right */
1360 /* remove border width from target area */
1365 if (width
< 1 || height
< 1)
1369 orientation
= tolower(orientation
);
1370 switch (orientation
)
1375 short_side
= height
;
1376 type
= (orientation
== 'd');
1382 type
= (orientation
== 'r') + 2;
1385 /* unknowm orientation */
1389 /* assure the base side has an odd length */
1390 if ((long_side
& 0x1) == 0)
1392 /* reduce base length if short sides don't fit */
1393 if (short_side
< long_side
/ 2 + 1)
1394 long_side
= 2 * short_side
- 1;
1396 short_side
= long_side
/ 2 + 1;
1398 if (orientation
== 'u' || orientation
== 'd')
1400 t_width
= long_side
;
1401 t_height
= short_side
;
1405 t_width
= short_side
;
1406 t_height
= long_side
;
1408 /* find proper x/y coordinate */
1409 x
+= (width
- t_width
) / 2;
1410 y
+= (height
- t_height
) / 2;
1411 /* decrement width and height for convenience of calculation */
1415 /* get the list of points to draw */
1416 switch (orientation
)
1420 t_height
= -t_height
;
1422 points
[1].x
= x
+ t_width
/ 2;
1423 points
[1].y
= y
+ t_height
;
1424 points
[2].x
= x
+ t_width
;
1431 points
[1].x
= x
+ t_width
;
1432 points
[1].y
= y
+ t_height
/ 2;
1434 points
[2].y
= y
+ t_height
;
1444 /* solid triangle */
1446 dpy
, d
, FillGC
, points
, 3, Convex
, CoordModeOrigin
);
1450 /* relief triangle */
1451 for (i
= 0; i
< 3; i
++)
1453 temp_gc
= (is_pressed
^ hi
[type
].line
[i
]) ?
1454 ReliefGC
: ShadowGC
;
1456 dpy
, d
, temp_gc
, points
[i
].x
, points
[i
].y
,
1457 points
[i
+1].x
, points
[i
+1].y
);
1459 for (i
= 0; i
< 3; i
++)
1461 temp_gc
= (is_pressed
^ hi
[type
].point
[i
]) ?
1462 ReliefGC
: ShadowGC
;
1463 XDrawPoint(dpy
, d
, temp_gc
, points
[i
].x
, points
[i
].y
);
1470 GC
fvwmlib_XCreateGC(
1471 Display
*display
, Drawable drawable
, unsigned long valuemask
,
1482 f
= values
->graphics_exposures
;
1483 if (!(valuemask
& GCGraphicsExposures
))
1485 valuemask
|= GCGraphicsExposures
;
1486 values
->graphics_exposures
= 0;
1488 gc
= XCreateGC(display
, drawable
, valuemask
, values
);
1489 values
->graphics_exposures
= f
;