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/Parse.h"
30 #include "libs/PictureBase.h"
31 #include "libs/PictureUtils.h"
32 #include "libs/PictureGraphics.h"
33 #include "libs/gravity.h"
34 #include "libs/FImage.h"
35 #include "libs/Graphics.h"
37 /* ---------------------------- local definitions -------------------------- */
39 /* Define some standard constants that are not included in the C89 standard */
41 #define M_PI 3.14159265358979323846
44 #define M_PI_2 1.57079632679489661923
47 #define M_1_PI 0.31830988618379067154
50 /* ---------------------------- local macros ------------------------------- */
52 /* ---------------------------- imports ------------------------------------ */
54 /* ---------------------------- included code files ------------------------ */
56 /* ---------------------------- local types -------------------------------- */
58 /* ---------------------------- forward declarations ----------------------- */
60 /* ---------------------------- local variables ---------------------------- */
62 /* ---------------------------- exported variables (globals) --------------- */
64 /* ---------------------------- local functions ---------------------------- */
66 /* ---------------------------- interface functions ------------------------ */
68 /* Draws the relief pattern around a window
69 * Draws a line_width wide rectangle from (x,y) to (x+w,y+h) i.e w+1 wide,
71 * Draws end points assuming CAP_NOT_LAST style in GC
72 * Draws anti-clockwise in case CAP_BUTT is the style and the end points overlap
73 * Top and bottom lines come out full length, the sides come out 1 pixel less
74 * This is so FvwmBorder windows have a correct bottom edge and the sticky lines
75 * look like just lines
76 * rotation rotate the relief and shadow part
78 void do_relieve_rectangle_with_rotation(
79 Display
*dpy
, Drawable d
, int x
, int y
, int w
, int h
,
80 GC ReliefGC
, GC ShadowGC
, int line_width
, Bool use_alternate_shading
,
84 GC shadow_gc
, relief_gc
;
91 a
= (use_alternate_shading
) ? 1 : 0;
97 /* If line_width is negative, reverse the rotation, which will */
98 /* have the effect of inverting the relief. */
101 line_width
= -line_width
;
102 rotation
= gravity_add_rotations(rotation
, ROTATION_180
);
108 rotation
= gravity_add_rotations(rotation
, ROTATION_180
);
109 shadow_gc
= ReliefGC
;
110 relief_gc
= ShadowGC
;
113 shadow_gc
= ShadowGC
;
114 relief_gc
= ReliefGC
;
117 max_w
= min((w
+ 1) / 2, line_width
);
118 max_h
= min((h
+ 1) / 2, line_width
);
119 seg
= (XSegment
*)alloca((sizeof(XSegment
) * line_width
) * 2);
120 /* from 0 to the lesser of line_width & just over half w */
121 for (i
= 0; i
< max_w
; i
++)
123 if (rotation
== ROTATION_0
)
126 seg
[i
].x1
= x
+i
; seg
[i
].y1
= y
+i
+a
;
127 seg
[i
].x2
= x
+i
; seg
[i
].y2
= y
+h
-i
+a
;
129 else /* ROTATION_90 */
132 seg
[i
].x1
= x
+w
-i
; seg
[i
].y1
= y
+h
-i
-a
;
133 seg
[i
].x2
= x
+w
-i
; seg
[i
].y2
= y
+i
+1-a
;
137 /* draw top segments */
138 for (i
= 0; i
< max_h
; i
++,i2
++)
140 seg
[i2
].x1
= x
+w
-i
-a
; seg
[i2
].y1
= y
+i
;
141 seg
[i2
].x2
= x
+i
+1-a
; seg
[i2
].y2
= y
+i
;
143 XDrawSegments(dpy
, d
, relief_gc
, seg
, i2
);
145 for (i
= 0; i
< max_h
; i
++)
147 seg
[i
].x1
= x
+i
+a
+l
; seg
[i
].y1
= y
+h
-i
;
148 seg
[i
].x2
= x
+w
-i
-1+a
; seg
[i
].y2
= y
+h
-i
;
151 for (i
= 0; i
< max_w
; i
++,i2
++)
153 if (rotation
== ROTATION_0
)
156 seg
[i2
].x1
= x
+w
-i
; seg
[i2
].y1
= y
+h
-i
-a
;
157 seg
[i2
].x2
= x
+w
-i
; seg
[i2
].y2
= y
+i
+1-a
;
159 else /* ROTATION_90 */
162 seg
[i2
].x1
= x
+i
; seg
[i2
].y1
= y
+i
+a
;
163 seg
[i2
].x2
= x
+i
; seg
[i2
].y2
= y
+h
-i
+a
;
166 XDrawSegments(dpy
, d
, shadow_gc
, seg
, i2
);
171 void do_relieve_rectangle(
172 Display
*dpy
, Drawable d
, int x
, int y
, int w
, int h
,
173 GC ReliefGC
, GC ShadowGC
, int line_width
, Bool use_alternate_shading
)
175 do_relieve_rectangle_with_rotation(
176 dpy
, d
, x
, y
, w
, h
, ReliefGC
, ShadowGC
, line_width
,
177 use_alternate_shading
, ROTATION_0
);
181 /* Creates a pixmap that is a horizontally stretched version of the input
184 Pixmap
CreateStretchXPixmap(
185 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int src_depth
,
186 int dest_width
, GC gc
)
192 if (src_width
< 0 || src_height
< 0 || dest_width
< 0)
196 pixmap
= XCreatePixmap(dpy
, src
, dest_width
, src_height
, src_depth
);
203 my_gc
= fvwmlib_XCreateGC(dpy
, pixmap
, 0, 0);
205 for (i
= 0; i
< dest_width
; i
++)
208 dpy
, src
, pixmap
, (gc
== None
)? my_gc
:gc
,
209 (i
* src_width
) / dest_width
, 0, 1, src_height
, i
, 0);
219 /* Creates a pixmap that is a vertically stretched version of the input
222 Pixmap
CreateStretchYPixmap(
223 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int src_depth
,
224 int dest_height
, GC gc
)
230 if (src_height
< 0 || src_depth
< 0 || dest_height
< 0)
234 pixmap
= XCreatePixmap(dpy
, src
, src_width
, dest_height
, src_depth
);
241 my_gc
= fvwmlib_XCreateGC(dpy
, pixmap
, 0, 0);
243 for (i
= 0; i
< dest_height
; i
++)
246 dpy
, src
, pixmap
, (gc
== None
)? my_gc
:gc
,
247 0, (i
* src_height
) / dest_height
, src_width
, 1, 0, i
);
257 /* Creates a pixmap that is a stretched version of the input
260 Pixmap
CreateStretchPixmap(
261 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int src_depth
,
262 int dest_width
, int dest_height
, GC gc
)
264 Pixmap pixmap
= None
;
268 if (src_width
< 0 || src_height
< 0 || src_depth
< 0 || dest_width
< 0)
274 my_gc
= fvwmlib_XCreateGC(dpy
, src
, 0, 0);
276 temp_pixmap
= CreateStretchXPixmap(
277 dpy
, src
, src_width
, src_height
, src_depth
, dest_width
,
278 (gc
== None
)? my_gc
:gc
);
279 if (temp_pixmap
== None
)
287 pixmap
= CreateStretchYPixmap(
288 dpy
, temp_pixmap
, dest_width
, src_height
, src_depth
,
289 dest_height
, (gc
== None
)? my_gc
:gc
);
290 XFreePixmap(dpy
, temp_pixmap
);
298 /* Creates a pixmap that is a tiled version of the input pixmap. Modifies the
299 * sets the fill_style of the GC to FillSolid and the tile to None. */
300 Pixmap
CreateTiledPixmap(
301 Display
*dpy
, Pixmap src
, int src_width
, int src_height
,
302 int dest_width
, int dest_height
, int depth
, GC gc
)
307 if (src_width
< 0 || src_height
< 0 ||
308 dest_width
< 0 || dest_height
< 0)
312 pixmap
= XCreatePixmap(dpy
, src
, dest_width
, dest_height
, depth
);
317 xgcv
.fill_style
= FillTiled
;
319 xgcv
.ts_x_origin
= 0;
320 xgcv
.ts_y_origin
= 0;
322 dpy
, gc
, GCFillStyle
| GCTile
| GCTileStipXOrigin
|
323 GCTileStipYOrigin
, &xgcv
);
324 XFillRectangle(dpy
, pixmap
, gc
, 0, 0, dest_width
, dest_height
);
325 xgcv
.fill_style
= FillSolid
;
326 XChangeGC(dpy
, gc
, GCFillStyle
, &xgcv
);
331 Pixmap
CreateRotatedPixmap(
332 Display
*dpy
, Pixmap src
, int src_width
, int src_height
, int depth
,
336 Pixmap pixmap
= None
;
337 int dest_width
, dest_height
, i
, j
;
340 FImage
*src_fim
= NULL
;
342 if (src_width
<= 0 || src_height
<= 0)
350 dest_width
= src_height
;
351 dest_height
= src_width
;
355 dest_width
= src_width
;
356 dest_height
= src_height
;
362 pixmap
= XCreatePixmap(dpy
, src
, dest_width
, dest_height
, depth
);
369 my_gc
= fvwmlib_XCreateGC(dpy
, src
, 0, 0);
371 if (rotation
== ROTATION_0
)
374 dpy
, src
, pixmap
, (gc
== None
)? my_gc
:gc
,
375 0, 0, src_width
, src_height
, 0, 0);
379 if (!(src_fim
= FGetFImage(
380 dpy
, src
, Pvisual
, depth
, 0, 0, src_width
, src_height
,
381 AllPlanes
, ZPixmap
)))
386 if (!(fim
= FCreateFImage(
387 dpy
, Pvisual
, depth
, ZPixmap
, dest_width
, dest_height
)))
393 for (j
= 0; j
< src_height
; j
++)
395 for (i
= 0; i
< src_width
; i
++)
401 fim
->im
, j
, src_width
- i
- 1,
402 XGetPixel(src_fim
->im
, i
, j
));
406 fim
->im
, src_height
- j
- 1, i
,
407 XGetPixel(src_fim
->im
, i
, j
));
412 src_width
- i
- 1, src_height
- j
- 1,
413 XGetPixel(src_fim
->im
, i
, j
));
420 FPutFImage(dpy
, pixmap
, gc
, fim
, 0, 0, 0, 0, dest_width
, dest_height
);
424 XFreePixmap(dpy
,pixmap
);
429 FDestroyFImage(dpy
, fim
);
433 FDestroyFImage(dpy
, src_fim
);
444 * Returns True if the given type of gradient is supported.
447 Bool
IsGradientTypeSupported(char type
)
449 switch (toupper(type
))
461 fprintf(stderr
, "%cGradient type is not supported\n",
469 * Allocates a linear color gradient (veliaa@rpi.edu)
473 XColor
*AllocLinearGradient(
474 char *s_from
, char *s_to
, int npixels
, int skip_first_color
, int dither
)
491 "AllocLinearGradient: Invalid number of pixels: %d\n",
495 if (!s_from
|| !XParseColor(Pdpy
, Pcmap
, s_from
, &from
))
497 fprintf(stderr
, "Cannot parse color \"%s\"\n",
498 s_from
? s_from
: "<blank>");
501 if (!s_to
|| !XParseColor(Pdpy
, Pcmap
, s_to
, &to
))
503 fprintf(stderr
, "Cannot parse color \"%s\"\n",
504 s_to
? s_to
: "<blank>");
508 /* divisor must not be zero, hence this calculation */
509 div
= (npixels
== 1) ? 1 : npixels
- 1;
511 /* red part and step width */
513 dr
= (float)(to
.red
- from
.red
);
514 /* green part and step width */
516 dg
= (float)(to
.green
- from
.green
);
517 /* blue part and step width */
519 db
= (float)(to
.blue
- from
.blue
);
520 xcs
= (XColor
*)safemalloc(sizeof(XColor
) * npixels
);
521 memset(xcs
, 0, sizeof(XColor
) * npixels
);
522 c
.flags
= DoRed
| DoGreen
| DoBlue
;
523 for (i
= (skip_first_color
) ? 1 : 0; i
< npixels
&& div
> 0; ++i
)
525 c
.red
= (unsigned short)
526 ((int)(r
+ dr
/ (float)div
* (float)i
+ 0.5));
527 c
.green
= (unsigned short)
528 ((int)(g
+ dg
/ (float)div
* (float)i
+ 0.5));
529 c
.blue
= (unsigned short)
530 ((int)(b
+ db
/ (float)div
* (float)i
+ 0.5));
531 if (dither
== 0 && !PictureAllocColor(Pdpy
, Pcmap
, &c
, False
))
537 if (!got_all
&& dither
== 0)
539 fprintf(stderr
, "Cannot alloc color gradient %s to %s\n",
548 * Allocates a nonlinear color gradient (veliaa@rpi.edu)
551 static XColor
*AllocNonlinearGradient(
552 char *s_colors
[], int clen
[], int nsegs
, int npixels
, int dither
)
554 XColor
*xcs
= (XColor
*)safemalloc(sizeof(XColor
) * npixels
);
559 float color_sum
= 0.0;
561 if (nsegs
< 1 || npixels
< 2)
564 "Gradients must specify at least one segment and"
569 for (i
= 0; i
< npixels
; i
++)
574 /* get total length of all segments */
575 for (i
= 0; i
< nsegs
; i
++)
580 /* calculate the index of a segment's las color */
581 seg_end_colors
= alloca(nsegs
* sizeof(int));
584 seg_end_colors
[0] = npixels
- 1;
588 for (i
= 0; i
< nsegs
; i
++)
590 color_sum
+= (float)(clen
[i
] * (npixels
- 1)) /
592 seg_end_colors
[i
] = (int)(color_sum
+ 0.5);
594 if (seg_end_colors
[nsegs
- 1] > npixels
- 1)
597 "BUG: (AllocNonlinearGradient): "
598 "seg_end_colors[nsegs - 1] (%d)"
599 " > npixels - 1 (%d)."
600 " Gradient drawing aborted\n",
601 seg_end_colors
[nsegs
- 1], npixels
- 1);
604 /* take care of rounding errors */
605 seg_end_colors
[nsegs
- 1] = npixels
- 1;
608 for (i
= 0; i
< nsegs
; ++i
)
613 int skip_first_color
= (curpixel
!= 0);
617 n
= seg_end_colors
[0] + 1;
621 n
= seg_end_colors
[i
] - seg_end_colors
[i
- 1] + 1;
626 c
= AllocLinearGradient(
627 s_colors
[i
], s_colors
[i
+ 1], n
,
628 skip_first_color
, dither
);
629 if (!c
&& (n
- skip_first_color
) != 0)
634 for (j
= skip_first_color
; j
< n
; ++j
)
636 xcs
[curpixel
+ j
] = c
[j
];
645 if (curpixel
!= seg_end_colors
[i
])
648 "BUG: (AllocNonlinearGradient): "
649 "nsegs %d, i %d, curpixel %d,"
650 " seg_end_colors[i] = %d,"
651 " npixels %d, n %d\n",
653 seg_end_colors
[i
],npixels
,n
);
660 /* Convenience function. Calls AllocNonLinearGradient to fetch all colors and
661 * then frees the color names and the perc and color_name arrays. */
662 XColor
*AllocAllGradientColors(
663 char *color_names
[], int perc
[], int nsegs
, int ncolors
, int dither
)
668 /* grab the colors */
669 xcs
= AllocNonlinearGradient(
670 color_names
, perc
, nsegs
, ncolors
, dither
);
671 for (i
= 0; i
<= nsegs
; i
++)
675 free(color_names
[i
]);
682 fprintf(stderr
, "couldn't create gradient\n");
689 /* groks a gradient string and creates arrays of colors and percentages
690 * returns the number of colors asked for (No. allocated may be less due
691 * to the ColorLimit command). A return of 0 indicates an error
694 char *gradient
, char **rest
, char ***colors_return
, int **perc_return
,
703 Bool is_syntax_error
= False
;
705 /* get the number of colors specified */
712 if (GetIntegerArguments(gradient
, &gradient
, (int *)&npixels
, 1) != 1 ||
716 stderr
, "ParseGradient: illegal number of colors in"
717 " gradient: '%s'\n", orig
);
721 /* get the starting color or number of segments */
722 gradient
= GetNextToken(gradient
, &item
);
725 gradient
= SkipSpaces(gradient
, NULL
, 0);
727 if (!gradient
|| !*gradient
|| !item
)
729 fprintf(stderr
, "Incomplete gradient style: '%s'\n", orig
);
741 if (GetIntegerArguments(item
, NULL
, &nsegs
, 1) != 1)
743 /* get the end color of a simple gradient */
744 s_colors
= (char **)safemalloc(sizeof(char *) * 2);
745 perc
= (int *)safemalloc(sizeof(int));
748 gradient
= GetNextToken(gradient
, &item
);
755 /* get a list of colors and percentages */
758 if (nsegs
> MAX_GRADIENT_SEGMENTS
)
759 nsegs
= MAX_GRADIENT_SEGMENTS
;
760 s_colors
= (char **)safemalloc(sizeof(char *) * (nsegs
+ 1));
761 perc
= (int *)safemalloc(sizeof(int) * nsegs
);
762 for (i
= 0; !is_syntax_error
&& i
<= nsegs
; i
++)
765 gradient
= GetNextToken(gradient
, &s_colors
[i
]);
768 if (GetIntegerArguments(
769 gradient
, &gradient
, &perc
[i
], 1)
770 != 1 || perc
[i
] <= 0)
777 if (s_colors
[nsegs
] == NULL
)
780 stderr
, "ParseGradient: too few gradient"
781 " segments: '%s'\n", orig
);
782 is_syntax_error
= True
;
787 for (i
= 0, sum
= 0; !is_syntax_error
&& i
< nsegs
; ++i
)
794 /* integer overflow */
796 stderr
, "ParseGradient: multi gradient"
797 " overflow: '%s'", orig
);
804 for (i
= 0; i
<= nsegs
; ++i
)
821 /* sensible limits */
824 if (npixels
> MAX_GRADIENT_COLORS
)
825 npixels
= MAX_GRADIENT_COLORS
;
828 *colors_return
= s_colors
;
830 *nsegs_return
= nsegs
;
837 /* Calculate the prefered dimensions of a gradient, based on the number of
838 * colors and the gradient type. Returns False if the gradient type is not
840 Bool
CalculateGradientDimensions(
841 Display
*dpy
, Drawable d
, int ncolors
, char type
, int dither
,
842 int *width_ret
, int *height_ret
)
844 static int best_width
= 0, best_height
= 0;
845 int dither_factor
= (dither
> 0)? 128:1;
847 /* get the best tile size (once) */
851 dpy
, d
, 1, 1, (unsigned int*)&best_width
,
852 (unsigned int*)&best_height
))
857 /* this is needed for buggy X servers like XFree 3.3.3.1 */
866 *width_ret
= ncolors
;
867 *height_ret
= best_height
* dither_factor
;
870 *width_ret
= best_width
* dither_factor
;
871 *height_ret
= ncolors
;
875 /* diagonal gradients are rendered into a rectangle for which
876 * the width plus the height is equal to ncolors + 1. The
877 * rectangle is square when ncolors is odd and one pixel
878 * taller than wide with even numbers */
879 *width_ret
= (ncolors
+ 1) / 2;
880 *height_ret
= ncolors
+ 1 - *width_ret
;
883 /* square gradients have the last color as a single pixel in
885 *width_ret
= *height_ret
= 2 * ncolors
- 1;
888 /* circular gradients have the first color as a pixel in each
890 *width_ret
= *height_ret
= 2 * ncolors
- 1;
894 /* swept types need each color to occupy at least one pixel at
895 * the edge. Get the smallest odd number that will provide
898 (double)(*width_ret
- 1) * M_PI
< (double)ncolors
;
901 /* nothing to do here */
903 *height_ret
= *width_ret
;
906 fprintf(stderr
, "%cGradient not supported\n", type
);
912 /* Does the actual drawing of the pixmap. If the in_drawable argument is None,
913 * a new pixmap of the given depth, width and height is created. If it is not
914 * None the gradient is drawn into it. The d_width, d_height, d_x and d_y
915 * describe the traget rectangle within the drawable. */
916 Drawable
CreateGradientPixmap(
917 Display
*dpy
, Drawable d
, GC gc
, int type
, int g_width
,
918 int g_height
, int ncolors
, XColor
*xcs
, int dither
, Pixel
**d_pixels
,
919 int *d_npixels
, Drawable in_drawable
, int d_x
, int d_y
,
920 int d_width
, int d_height
, XRectangle
*rclip
)
922 Pixmap pixmap
= None
;
923 PictureImageColorAllocator
*pica
= NULL
;
935 if (d_pixels
!= NULL
&& *d_pixels
!= NULL
)
937 if (d_npixels
!= NULL
&& *d_npixels
> 0)
940 dpy
, Pcmap
, *d_pixels
, *d_npixels
, 0, False
);
945 if (d_npixels
!= NULL
)
949 if (g_height
< 0 || g_width
< 0 || d_width
< 0 || d_height
< 0)
952 if (in_drawable
== None
)
954 /* create a pixmap to use */
955 pixmap
= XCreatePixmap(dpy
, d
, g_width
, g_height
, Pdepth
);
966 target
= in_drawable
;
974 dpy
, Pvisual
, Pdepth
, ZPixmap
, t_width
, t_height
);
977 fprintf(stderr
, "%cGradient couldn't get image\n", type
);
979 XFreePixmap(dpy
, pixmap
);
984 pica
= PictureOpenImageColorAllocator(
985 dpy
, Pcmap
, t_width
, t_height
,
986 False
, False
, dither
, False
);
988 ps
= t_width
* t_height
;
989 /* now do the fancy drawing */
994 for (i
= 0; i
< t_width
; i
++)
996 int d
= i
* ncolors
/ t_width
;
998 for (j
= 0; j
< t_height
; j
++)
1003 PictureAllocColorImage(
1004 dpy
, pica
, &c
, i
, j
);
1006 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1013 for (j
= 0; j
< t_height
; j
++)
1015 int d
= j
* ncolors
/ t_height
;
1017 for (i
= 0; i
< t_width
; i
++)
1022 PictureAllocColorImage(
1023 dpy
, pica
, &c
, i
, j
);
1025 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1032 register int t_scale
= t_width
+ t_height
- 1;
1033 for (i
= 0; i
< t_width
; i
++)
1035 for (j
= 0; j
< t_height
; j
++)
1037 c
= xcs
[(i
+j
) * ncolors
/ t_scale
];
1040 PictureAllocColorImage(
1041 dpy
, pica
, &c
, i
, j
);
1043 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1050 register int t_scale
= t_width
+ t_height
- 1;
1051 for (i
= 0; i
< t_width
; i
++)
1053 for (j
= 0; j
< t_height
; j
++)
1055 c
= xcs
[(i
+ (t_height
- j
- 1)) * ncolors
/
1059 PictureAllocColorImage(
1060 dpy
, pica
, &c
, i
, j
);
1062 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1069 register int t_scale
= t_width
* t_height
;
1070 register int myncolors
= ncolors
* 2;
1071 for (i
= 0; i
< t_width
; i
++) {
1072 register int pi
= min(i
, t_width
- 1 - i
) * t_height
;
1073 for (j
= 0; j
< t_height
; j
++) {
1075 min(j
, t_height
- 1 - j
) * t_width
;
1076 c
= xcs
[(min(pi
, pj
) * myncolors
- 1) /
1080 PictureAllocColorImage(
1081 dpy
, pica
, &c
, i
, j
);
1083 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1090 register double t_scale
=
1091 (double)(t_width
* t_height
) / sqrt(8);
1092 for (i
= 0; i
< t_width
; i
++)
1094 for (j
= 0; j
< t_height
; j
++)
1097 (double)((2 * i
- t_width
) * t_height
) /
1100 (double)((t_height
- 2 * j
) * t_width
) /
1102 register double rad
= sqrt(x
* x
+ y
* y
);
1103 c
= xcs
[(int)((rad
* ncolors
- 0.5) / t_scale
)];
1106 PictureAllocColorImage(
1107 dpy
, pica
, &c
, i
, j
);
1109 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1116 register int w
= t_width
- 1;
1117 register int h
= t_height
- 1;
1118 /* g_width == g_height, both are odd, therefore x can be 0.0 */
1119 for (i
= 0; i
<= w
; i
++) {
1120 for (j
= 0; j
<= h
; j
++) {
1122 (double)((2 * i
- w
) * h
) / 4.0;
1124 (double)((h
- 2 * j
) * w
) / 4.0;
1125 /* angle ranges from -pi/2 to +pi/2 */
1126 register double angle
;
1128 angle
= atan(y
/ x
);
1130 angle
= (y
< 0) ? - M_PI_2
: M_PI_2
;
1132 /* extend to -pi/2 to 3pi/2 */
1135 /* move range from -pi/2:3*pi/2 to 0:2*pi */
1137 angle
+= M_PI
* 2.0;
1138 /* normalize to gradient */
1139 c
= xcs
[(int)(angle
* M_1_PI
* 0.5 * ncolors
)];
1142 PictureAllocColorImage(
1143 dpy
, pica
, &c
, i
, j
);
1145 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1151 * The Yin Yang gradient style and the following code are:
1152 * Copyright 1999 Sir Boris. (email to sir_boris@bigfoot.com may be
1153 * read by his groom but is not guaranteed to elicit a response)
1154 * No restrictions are placed on this code, as long as the copyright
1155 * notice is preserved.
1159 register int r
= t_width
* t_height
/ 4;
1160 for (i
= 0; i
< t_width
; i
++) {
1161 for (j
= 0; j
< t_height
; j
++) {
1163 (double)((2 * i
- t_width
) * t_height
) /
1166 (double)((t_height
- 2 * j
) * t_width
) /
1168 register double rad
= sqrt(x
* x
+ y
* y
);
1169 /* angle ranges from -pi/2 to +pi/2 */
1170 register double angle
;
1173 angle
= atan(y
/ x
);
1175 angle
= (y
< 0) ? - M_PI_2
: M_PI_2
;
1177 /* extend to -pi/2 to 3pi/2 */
1180 /* warp the angle within the yinyang circle */
1182 angle
-= acos(rad
/ r
);
1184 /* move range from -pi/2:3*pi/2 to 0:2*pi */
1186 angle
+= M_PI
* 2.0;
1187 /* normalize to gradient */
1188 c
= xcs
[(int)(angle
* M_1_PI
* 0.5 * ncolors
)];
1191 PictureAllocColorImage(
1192 dpy
, pica
, &c
, i
, j
);
1194 XPutPixel(fim
->im
, i
, j
, c
.pixel
);
1200 /* placeholder function, just fills the pixmap with the first
1202 memset(fim
->im
->data
, 0, fim
->im
->bytes_per_line
* t_height
);
1203 XAddPixel(fim
->im
, xcs
[0].pixel
);
1209 if (d_pixels
!= NULL
&& d_npixels
!= NULL
)
1211 PictureCloseImageColorAllocator(
1212 dpy
, pica
, d_npixels
, d_pixels
, 0);
1216 /* possible color leak */
1220 /* set the gc style */
1221 xgcv
.function
= GXcopy
;
1222 xgcv
.plane_mask
= AllPlanes
;
1223 xgcv
.fill_style
= FillSolid
;
1224 xgcv
.clip_mask
= None
;
1225 XChangeGC(dpy
, gc
, GCFunction
|GCPlaneMask
|GCFillStyle
|GCClipMask
,
1229 XSetClipRectangles(dpy
, gc
, 0, 0, rclip
, 1, Unsorted
);
1231 /* copy the image to the server */
1232 FPutFImage(dpy
, target
, gc
, fim
, 0, 0, t_x
, t_y
, t_width
, t_height
);
1235 XSetClipMask(dpy
, gc
, None
);
1237 FDestroyFImage(dpy
, fim
);
1242 /* Create a pixmap from a gradient specifier, width and height are hints
1243 * that are only used for gradients that can be tiled e.g. H or V types
1244 * types are HVDBSCRY for Horizontal, Vertical, Diagonal, Back-diagonal, Square,
1245 * Circular, Radar and Yin/Yang respectively (in order of bloatiness)
1247 Pixmap
CreateGradientPixmapFromString(
1248 Display
*dpy
, Drawable d
, GC gc
, int type
, char *action
,
1249 int *width_return
, int *height_return
,
1250 Pixel
**pixels_return
, int *nalloc_pixels
, int dither
)
1252 Pixel
*d_pixels
= NULL
;
1258 Pixmap pixmap
= None
;
1260 /* set return pixels to NULL in case of premature return */
1262 *pixels_return
= NULL
;
1266 /* translate the gradient string into an array of colors etc */
1267 if (!(ncolors
= ParseGradient(action
, NULL
, &colors
, &perc
, &nsegs
))) {
1268 fprintf(stderr
, "Can't parse gradient: '%s'\n", action
);
1271 /* grab the colors */
1272 xcs
= AllocAllGradientColors(
1273 colors
, perc
, nsegs
, ncolors
, dither
);
1279 /* grok the size to create from the type */
1280 type
= toupper(type
);
1282 if (CalculateGradientDimensions(
1283 dpy
, d
, ncolors
, type
, dither
, width_return
, height_return
))
1285 pixmap
= CreateGradientPixmap(
1286 dpy
, d
, gc
, type
, *width_return
, *height_return
,
1287 ncolors
, xcs
, dither
, &d_pixels
, &d_npixels
,
1288 None
, 0, 0, 0, 0, NULL
);
1291 /* if the caller has not asked for the pixels there is probably a leak
1293 if (PUseDynamicColors
)
1295 if (!(pixels_return
&& nalloc_pixels
))
1297 /* if the caller has not asked for the pixels there is
1298 * probably a leak */
1300 "CreateGradient: potential color leak, losing track"
1302 if (d_pixels
!= NULL
)
1314 pixels
= (Pixel
*)safemalloc(
1315 ncolors
* sizeof(Pixel
));
1316 for(i
=0; i
<ncolors
; i
++)
1318 pixels
[i
] = xcs
[i
].pixel
;
1320 *pixels_return
= pixels
;
1321 *nalloc_pixels
= ncolors
;
1325 *pixels_return
= d_pixels
;
1326 *nalloc_pixels
= d_npixels
;
1330 else if (d_pixels
!= NULL
)
1332 /* should not happen */
1343 * Draws a little Triangle pattern within a window
1346 void DrawTrianglePattern(
1347 Display
*dpy
, Drawable d
, GC ReliefGC
, GC ShadowGC
, GC FillGC
,
1348 int x
, int y
, int width
, int height
, int bw
, char orientation
,
1349 Bool draw_relief
, Bool do_fill
, Bool is_pressed
)
1354 const char point
[3];
1357 { { 1, 0, 0 }, { 1, 1, 0 } }, /* up */
1358 { { 1, 0, 1 }, { 1, 0, 0 } }, /* down */
1359 { { 1, 0, 0 }, { 1, 1, 0 } }, /* left */
1360 { { 1, 0, 1 }, { 1, 1, 0 } } /* right */
1371 /* remove border width from target area */
1376 if (width
< 1 || height
< 1)
1380 orientation
= tolower(orientation
);
1381 switch (orientation
)
1386 short_side
= height
;
1387 type
= (orientation
== 'd');
1393 type
= (orientation
== 'r') + 2;
1396 /* unknowm orientation */
1400 /* assure the base side has an odd length */
1401 if ((long_side
& 0x1) == 0)
1403 /* reduce base length if short sides don't fit */
1404 if (short_side
< long_side
/ 2 + 1)
1405 long_side
= 2 * short_side
- 1;
1407 short_side
= long_side
/ 2 + 1;
1409 if (orientation
== 'u' || orientation
== 'd')
1411 t_width
= long_side
;
1412 t_height
= short_side
;
1416 t_width
= short_side
;
1417 t_height
= long_side
;
1419 /* find proper x/y coordinate */
1420 x
+= (width
- t_width
) / 2;
1421 y
+= (height
- t_height
) / 2;
1422 /* decrement width and height for convenience of calculation */
1426 /* get the list of points to draw */
1427 switch (orientation
)
1431 t_height
= -t_height
;
1433 points
[1].x
= x
+ t_width
/ 2;
1434 points
[1].y
= y
+ t_height
;
1435 points
[2].x
= x
+ t_width
;
1442 points
[1].x
= x
+ t_width
;
1443 points
[1].y
= y
+ t_height
/ 2;
1445 points
[2].y
= y
+ t_height
;
1455 /* solid triangle */
1457 dpy
, d
, FillGC
, points
, 3, Convex
, CoordModeOrigin
);
1461 /* relief triangle */
1462 for (i
= 0; i
< 3; i
++)
1464 temp_gc
= (is_pressed
^ hi
[type
].line
[i
]) ?
1465 ReliefGC
: ShadowGC
;
1467 dpy
, d
, temp_gc
, points
[i
].x
, points
[i
].y
,
1468 points
[i
+1].x
, points
[i
+1].y
);
1470 for (i
= 0; i
< 3; i
++)
1472 temp_gc
= (is_pressed
^ hi
[type
].point
[i
]) ?
1473 ReliefGC
: ShadowGC
;
1474 XDrawPoint(dpy
, d
, temp_gc
, points
[i
].x
, points
[i
].y
);
1481 GC
fvwmlib_XCreateGC(
1482 Display
*display
, Drawable drawable
, unsigned long valuemask
,
1493 f
= values
->graphics_exposures
;
1494 if (!(valuemask
& GCGraphicsExposures
))
1496 valuemask
|= GCGraphicsExposures
;
1497 values
->graphics_exposures
= 0;
1499 gc
= XCreateGC(display
, drawable
, valuemask
, values
);
1500 values
->graphics_exposures
= f
;