2 #include "general-support.h"
3 #include "cairo-support.h"
5 /***********************************************
8 * Get HSB values from RGB values.
10 * Modified from Smooth but originated in GTK+
11 ***********************************************/
13 ge_hsb_from_color (const CairoColor
*color
,
18 gdouble min
, max
, delta
;
19 gdouble red
, green
, blue
;
28 min
= MIN(green
, blue
);
32 max
= MAX(green
, blue
);
36 *brightness
= (max
+ min
) / 2;
38 if (fabs(max
- min
) < 0.0001)
45 if (*brightness
<= 0.5)
46 *saturation
= (max
- min
) / (max
+ min
);
48 *saturation
= (max
- min
) / (2 - max
- min
);
53 *hue
= (green
- blue
) / delta
;
54 else if (green
== max
)
55 *hue
= 2 + (blue
- red
) / delta
;
57 *hue
= 4 + (red
- green
) / delta
;
65 /***********************************************
68 * Get RGB values from HSB values.
70 * Modified from Smooth but originated in GTK+
71 ***********************************************/
72 #define MODULA(number, divisor) (((gint)number % divisor) + (number - (gint)number))
74 ge_color_from_hsb (gdouble hue
,
80 gdouble hue_shift
[3], color_shift
[3];
85 if (brightness
<= 0.5)
86 m2
= brightness
* (1 + saturation
);
88 m2
= brightness
+ saturation
- brightness
* saturation
;
90 m1
= 2 * brightness
- m2
;
92 hue_shift
[0] = hue
+ 120;
94 hue_shift
[2] = hue
- 120;
96 color_shift
[0] = color_shift
[1] = color_shift
[2] = brightness
;
98 i
= (saturation
== 0)?3:0;
105 m3
= MODULA(m3
, 360);
107 m3
= 360 - MODULA(ABS(m3
), 360);
110 color_shift
[i
] = m1
+ (m2
- m1
) * m3
/ 60;
114 color_shift
[i
] = m1
+ (m2
- m1
) * (240 - m3
) / 60;
119 color
->r
= color_shift
[0];
120 color
->g
= color_shift
[1];
121 color
->b
= color_shift
[2];
126 ge_gdk_color_to_cairo (const GdkColor
*c
, CairoColor
*cc
)
130 g_return_if_fail (c
&& cc
);
132 r
= c
->red
/ 65535.0;
133 g
= c
->green
/ 65535.0;
134 b
= c
->blue
/ 65535.0;
143 ge_cairo_color_to_gtk (const CairoColor
*cc
, GdkColor
*c
)
147 g_return_if_fail (c
&& cc
);
159 ge_gtk_style_to_cairo_color_cube (GtkStyle
* style
, CairoColorCube
*cube
)
163 g_return_if_fail (style
&& cube
);
165 for (i
= 0; i
< 5; i
++)
167 ge_gdk_color_to_cairo (&style
->bg
[i
], &cube
->bg
[i
]);
168 ge_gdk_color_to_cairo (&style
->fg
[i
], &cube
->fg
[i
]);
170 ge_gdk_color_to_cairo (&style
->dark
[i
], &cube
->dark
[i
]);
171 ge_gdk_color_to_cairo (&style
->light
[i
], &cube
->light
[i
]);
172 ge_gdk_color_to_cairo (&style
->mid
[i
], &cube
->mid
[i
]);
174 ge_gdk_color_to_cairo (&style
->base
[i
], &cube
->base
[i
]);
175 ge_gdk_color_to_cairo (&style
->text
[i
], &cube
->text
[i
]);
176 ge_gdk_color_to_cairo (&style
->text_aa
[i
], &cube
->text_aa
[i
]);
179 cube
->black
.r
= cube
->black
.g
= cube
->black
.b
= 0;
182 cube
->white
.r
= cube
->white
.g
= cube
->white
.b
= 1;
187 ge_shade_color(const CairoColor
*base
, gdouble shade_ratio
, CairoColor
*composite
)
190 gdouble saturation
= 0;
191 gdouble brightness
= 0;
193 g_return_if_fail (base
&& composite
);
195 ge_hsb_from_color (base
, &hue
, &saturation
, &brightness
);
197 brightness
= MIN(brightness
*shade_ratio
, 1.0);
198 brightness
= MAX(brightness
, 0.0);
200 saturation
= MIN(saturation
*shade_ratio
, 1.0);
201 saturation
= MAX(saturation
, 0.0);
203 ge_color_from_hsb (hue
, saturation
, brightness
, composite
);
204 composite
->a
= base
->a
;
208 ge_saturate_color (const CairoColor
*base
, gdouble saturate_level
, CairoColor
*composite
)
211 gdouble saturation
= 0;
212 gdouble brightness
= 0;
214 g_return_if_fail (base
&& composite
);
216 ge_hsb_from_color (base
, &hue
, &saturation
, &brightness
);
218 saturation
= MIN(saturation
*saturate_level
, 1.0);
219 saturation
= MAX(saturation
, 0.0);
221 ge_color_from_hsb (hue
, saturation
, brightness
, composite
);
222 composite
->a
= base
->a
;
226 ge_mix_color (const CairoColor
*color1
, const CairoColor
*color2
,
227 gdouble mix_factor
, CairoColor
*composite
)
229 g_return_if_fail (color1
&& color2
&& composite
);
231 composite
->r
= color1
->r
* (1-mix_factor
) + color2
->r
* mix_factor
;
232 composite
->g
= color1
->g
* (1-mix_factor
) + color2
->g
* mix_factor
;
233 composite
->b
= color1
->b
* (1-mix_factor
) + color2
->b
* mix_factor
;
238 ge_gdk_drawable_to_cairo (GdkDrawable
*window
, GdkRectangle
*area
)
242 g_return_val_if_fail (window
!= NULL
, NULL
);
244 cr
= (cairo_t
*) gdk_cairo_create (window
);
245 cairo_set_line_width (cr
, 1.0);
246 cairo_set_line_cap (cr
, CAIRO_LINE_CAP_SQUARE
);
247 cairo_set_line_join (cr
, CAIRO_LINE_JOIN_MITER
);
251 cairo_rectangle (cr
, area
->x
, area
->y
, area
->width
, area
->height
);
252 cairo_clip_preserve (cr
);
260 ge_cairo_set_color (cairo_t
*cr
, const CairoColor
*color
)
262 g_return_if_fail (cr
&& color
);
264 cairo_set_source_rgba (cr
, color
->r
, color
->g
, color
->b
, color
->a
);
268 ge_cairo_set_gdk_color_with_alpha (cairo_t
*cr
, const GdkColor
*color
, gdouble alpha
)
270 g_return_if_fail (cr
&& color
);
272 cairo_set_source_rgba (cr
, color
->red
/ 65535.0,
273 color
->green
/ 65535.0,
274 color
->blue
/ 65535.0,
279 ge_cairo_pattern_add_color_stop_color (cairo_pattern_t
*pattern
,
281 const CairoColor
*color
)
283 g_return_if_fail (pattern
&& color
);
285 cairo_pattern_add_color_stop_rgba (pattern
, offset
, color
->r
, color
->g
, color
->b
, color
->a
);
289 ge_cairo_pattern_add_color_stop_shade(cairo_pattern_t
*pattern
,
291 const CairoColor
*color
,
296 g_return_if_fail (pattern
&& color
&& (shade
>= 0) && (shade
<= 3));
302 ge_shade_color(color
, shade
, &shaded
);
305 ge_cairo_pattern_add_color_stop_color(pattern
, offset
, &shaded
);
308 /* This function will draw a rounded corner at position x,y. If the radius
309 * is very small (or negative) it will instead just do a line_to.
310 * ge_cairo_rounded_corner assumes clockwise drawing. */
312 ge_cairo_rounded_corner (cairo_t
*cr
,
320 cairo_line_to (cr
, x
, y
);
326 cairo_line_to (cr
, x
, y
);
328 case CR_CORNER_TOPLEFT
:
329 cairo_arc (cr
, x
+ radius
, y
+ radius
, radius
, G_PI
, G_PI
* 3/2);
331 case CR_CORNER_TOPRIGHT
:
332 cairo_arc (cr
, x
- radius
, y
+ radius
, radius
, G_PI
* 3/2, G_PI
* 2);
334 case CR_CORNER_BOTTOMRIGHT
:
335 cairo_arc (cr
, x
- radius
, y
- radius
, radius
, 0, G_PI
* 1/2);
337 case CR_CORNER_BOTTOMLEFT
:
338 cairo_arc (cr
, x
+ radius
, y
- radius
, radius
, G_PI
* 1/2, G_PI
);
342 /* A bitfield and not a sane value ... */
343 g_assert_not_reached ();
344 cairo_line_to (cr
, x
, y
);
351 ge_cairo_rounded_rectangle (cairo_t
*cr
,
352 double x
, double y
, double w
, double h
,
353 double radius
, CairoCorners corners
)
355 g_return_if_fail (cr
!= NULL
);
357 if (radius
< 0.0001 || corners
== CR_CORNER_NONE
)
359 cairo_rectangle (cr
, x
, y
, w
, h
);
363 if ((corners
== CR_CORNER_ALL
) && (radius
> w
/ 2.0 || radius
> h
/ 2.0))
364 g_warning ("Radius is too large for width/height in ge_rounded_rectangle.\n");
365 else if (radius
> w
|| radius
> h
) /* This isn't perfect. Assumes that only one corner is set. */
366 g_warning ("Radius is too large for width/height in ge_rounded_rectangle.\n");
369 if (corners
& CR_CORNER_TOPLEFT
)
370 cairo_move_to (cr
, x
+radius
, y
);
372 cairo_move_to (cr
, x
, y
);
374 if (corners
& CR_CORNER_TOPRIGHT
)
375 cairo_arc (cr
, x
+w
-radius
, y
+radius
, radius
, G_PI
* 1.5, G_PI
* 2);
377 cairo_line_to (cr
, x
+w
, y
);
379 if (corners
& CR_CORNER_BOTTOMRIGHT
)
380 cairo_arc (cr
, x
+w
-radius
, y
+h
-radius
, radius
, 0, G_PI
* 0.5);
382 cairo_line_to (cr
, x
+w
, y
+h
);
384 if (corners
& CR_CORNER_BOTTOMLEFT
)
385 cairo_arc (cr
, x
+radius
, y
+h
-radius
, radius
, G_PI
* 0.5, G_PI
);
387 cairo_line_to (cr
, x
, y
+h
);
389 if (corners
& CR_CORNER_TOPLEFT
)
390 cairo_arc (cr
, x
+radius
, y
+radius
, radius
, G_PI
, G_PI
* 1.5);
392 cairo_line_to (cr
, x
, y
);
396 /* ge_cairo_stroke_rectangle.
398 * A simple function to stroke the rectangle { x, y, w, h}.
399 * (This function only exists because of a cairo performance bug that
400 * has been fixed and it may be a good idea to get rid of it again.)
403 ge_cairo_stroke_rectangle (cairo_t
*cr
, double x
, double y
, double w
, double h
)
405 cairo_rectangle (cr
, x
, y
, w
, h
);
409 /***********************************************
410 * ge_cairo_simple_border -
412 * A simple routine to draw thin squared
413 * borders with a topleft and bottomright color.
415 * It originated in Smooth-Engine.
416 ***********************************************/
418 ge_cairo_simple_border (cairo_t
*cr
,
419 const CairoColor
* tl
, const CairoColor
* br
,
420 gint x
, gint y
, gint width
, gint height
,
421 gboolean topleft_overlap
)
423 gboolean solid_color
;
425 g_return_if_fail (cr
!= NULL
);
426 g_return_if_fail (tl
!= NULL
);
427 g_return_if_fail (br
!= NULL
);
430 solid_color
= (tl
== br
) || ((tl
->r
== br
->r
) && (tl
->g
== br
->g
) && (tl
->b
== br
->b
) && (tl
->a
== br
->a
));
432 topleft_overlap
&= !solid_color
;
436 cairo_set_line_width (cr
, 1);
440 ge_cairo_set_color(cr
, br
);
442 cairo_move_to(cr
, x
+ 0.5, y
+ height
- 0.5);
443 cairo_line_to(cr
, x
+ width
- 0.5, y
+ height
- 0.5);
444 cairo_line_to(cr
, x
+ width
- 0.5, y
+ 0.5);
449 ge_cairo_set_color(cr
, tl
);
451 cairo_move_to(cr
, x
+ 0.5, y
+ height
- 0.5);
452 cairo_line_to(cr
, x
+ 0.5, y
+ 0.5);
453 cairo_line_to(cr
, x
+ width
- 0.5, y
+ 0.5);
455 if (!topleft_overlap
)
460 ge_cairo_set_color(cr
, br
);
463 cairo_move_to(cr
, x
+ 0.5, y
+ height
- 0.5);
464 cairo_line_to(cr
, x
+ width
- 0.5, y
+ height
- 0.5);
465 cairo_line_to(cr
, x
+ width
- 0.5, y
+ 0.5);
473 void ge_cairo_polygon (cairo_t
*cr
,
474 const CairoColor
*color
,
482 ge_cairo_set_color(cr
, color
);
483 cairo_move_to(cr
, points
[0].x
, points
[0].y
);
485 for (i
= 1; i
< npoints
; i
++)
487 if (!((points
[i
].x
== points
[i
+ 1].x
) &&
488 (points
[i
].y
== points
[i
+ 1].y
)))
490 cairo_line_to(cr
, points
[i
].x
, points
[i
].y
);
494 if ((points
[npoints
-1].x
!= points
[0].y
) ||
495 (points
[npoints
-1].y
!= points
[0].y
))
497 cairo_line_to(cr
, points
[0].x
, points
[0].y
);
505 void ge_cairo_line (cairo_t
*cr
,
506 const CairoColor
*color
,
514 ge_cairo_set_color(cr
, color
);
515 cairo_set_line_width (cr
, 1);
517 cairo_move_to(cr
, x1
+ 0.5, y1
+ 0.5);
518 cairo_line_to(cr
, x2
+ 0.5, y2
+ 0.5);
526 ge_cairo_mirror (cairo_t
*cr
,
533 cairo_matrix_t matrix
;
535 cairo_matrix_init_identity (&matrix
);
537 cairo_translate (cr
, *x
, *y
);
541 if (mirror
& CR_MIRROR_HORIZONTAL
)
543 cairo_matrix_scale (&matrix
, -1, 1);
546 if (mirror
& CR_MIRROR_VERTICAL
)
548 cairo_matrix_scale (&matrix
, 1, -1);
552 cairo_transform (cr
, &matrix
);
556 ge_cairo_exchange_axis (cairo_t
*cr
,
563 cairo_matrix_t matrix
;
565 cairo_translate (cr
, *x
, *y
);
566 cairo_matrix_init (&matrix
, 0, 1, 1, 0, 0, 0);
568 cairo_transform (cr
, &matrix
);
570 /* swap width/height */
579 /***********************************************
580 * ge_cairo_pattern_fill -
582 * Fill an area with some pattern
583 * Scaling or tiling if needed
584 ***********************************************/
586 ge_cairo_pattern_fill(cairo_t
*canvas
,
587 CairoPattern
*pattern
,
593 cairo_matrix_t original_matrix
, current_matrix
;
595 if (pattern
->operator == CAIRO_OPERATOR_DEST
)
600 cairo_pattern_get_matrix(pattern
->handle
, &original_matrix
);
601 current_matrix
= original_matrix
;
603 if (pattern
->scale
!= GE_DIRECTION_NONE
)
605 gdouble scale_x
= 1.0;
606 gdouble scale_y
= 1.0;
608 if ((pattern
->scale
== GE_DIRECTION_VERTICAL
) || (pattern
->scale
== GE_DIRECTION_BOTH
))
613 if ((pattern
->scale
== GE_DIRECTION_HORIZONTAL
) || (pattern
->scale
== GE_DIRECTION_BOTH
))
615 scale_y
= 1.0/height
;
618 cairo_matrix_scale(¤t_matrix
, scale_x
, scale_y
);
621 if (pattern
->translate
!= GE_DIRECTION_NONE
)
623 gdouble translate_x
= 0;
624 gdouble translate_y
= 0;
626 if ((pattern
->translate
== GE_DIRECTION_VERTICAL
) || (pattern
->translate
== GE_DIRECTION_BOTH
))
631 if ((pattern
->translate
== GE_DIRECTION_HORIZONTAL
) || (pattern
->translate
== GE_DIRECTION_BOTH
))
636 cairo_matrix_translate(¤t_matrix
, translate_x
, translate_y
);
639 cairo_pattern_set_matrix(pattern
->handle
, ¤t_matrix
);
643 cairo_set_source(canvas
, pattern
->handle
);
644 cairo_set_operator(canvas
, pattern
->operator);
645 cairo_rectangle(canvas
, x
, y
, width
, height
);
649 cairo_restore(canvas
);
651 cairo_pattern_set_matrix(pattern
->handle
, &original_matrix
);
654 /***********************************************
655 * ge_cairo_color_pattern -
657 * Create A Solid Color Pattern
658 ***********************************************/
660 ge_cairo_color_pattern(CairoColor
*base
)
662 CairoPattern
* result
= g_new0(CairoPattern
, 1);
664 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
665 result
->type
= CAIRO_PATTERN_TYPE_SOLID
;
668 result
->scale
= GE_DIRECTION_NONE
;
669 result
->translate
= GE_DIRECTION_NONE
;
671 result
->handle
= cairo_pattern_create_rgba(base
->r
,
676 result
->operator = CAIRO_OPERATOR_SOURCE
;
681 /***********************************************
682 * ge_cairo_pixbuf_pattern -
684 * Create A Tiled Pixbuf Pattern
685 ***********************************************/
687 ge_cairo_pixbuf_pattern(GdkPixbuf
*pixbuf
)
689 CairoPattern
* result
= g_new0(CairoPattern
, 1);
692 cairo_surface_t
* surface
;
695 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
696 result
->type
= CAIRO_PATTERN_TYPE_SURFACE
;
699 result
->scale
= GE_DIRECTION_NONE
;
700 result
->translate
= GE_DIRECTION_BOTH
;
702 width
= gdk_pixbuf_get_width(pixbuf
);
703 height
= gdk_pixbuf_get_height(pixbuf
);
705 surface
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32
, width
, height
);
707 canvas
= cairo_create(surface
);
709 gdk_cairo_set_source_pixbuf (canvas
, pixbuf
, 0, 0);
710 cairo_rectangle (canvas
, 0, 0, width
, height
);
712 cairo_destroy(canvas
);
714 result
->handle
= cairo_pattern_create_for_surface (surface
);
715 cairo_surface_destroy(surface
);
717 cairo_pattern_set_extend (result
->handle
, CAIRO_EXTEND_REPEAT
);
719 result
->operator = CAIRO_OPERATOR_SOURCE
;
724 /***********************************************
725 * ge_cairo_pixmap_pattern -
727 * Create A Tiled Pixmap Pattern
728 ***********************************************/
730 ge_cairo_pixmap_pattern(GdkPixmap
*pixmap
)
732 CairoPattern
* result
= NULL
;
737 gdk_drawable_get_size (GDK_DRAWABLE (pixmap
), &width
, &height
);
739 pixbuf
= gdk_pixbuf_get_from_drawable(NULL
, GDK_DRAWABLE (pixmap
),
740 gdk_drawable_get_colormap(GDK_DRAWABLE (pixmap
)),
741 0, 0, 0, 0, width
, height
);
743 result
= ge_cairo_pixbuf_pattern(pixbuf
);
745 g_object_unref (pixbuf
);
750 /***********************************************
751 * ge_cairo_linear_shade_gradient_pattern -
753 * Create A Linear Shade Gradient Pattern
754 * Aka Smooth Shade Gradient, from/to gradient
755 * With End points defined as shades of the
757 ***********************************************/
759 ge_cairo_linear_shade_gradient_pattern(CairoColor
*base
,
764 CairoPattern
* result
= g_new0(CairoPattern
, 1);
766 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
767 result
->type
= CAIRO_PATTERN_TYPE_LINEAR
;
772 result
->scale
= GE_DIRECTION_VERTICAL
;
774 result
->handle
= cairo_pattern_create_linear(0, 0, 1, 0);
778 result
->scale
= GE_DIRECTION_HORIZONTAL
;
780 result
->handle
= cairo_pattern_create_linear(0, 0, 0, 1);
783 result
->translate
= GE_DIRECTION_BOTH
;
784 result
->operator = CAIRO_OPERATOR_SOURCE
;
786 ge_cairo_pattern_add_color_stop_shade(result
->handle
, 0, base
, shade1
);
787 ge_cairo_pattern_add_color_stop_shade(result
->handle
, 1, base
, shade2
);
793 ge_cairo_pattern_destroy(CairoPattern
*pattern
)
798 cairo_pattern_destroy(pattern
->handle
);
804 /* The following function will be called by GTK+ when the module
805 * is loaded and checks to see if we are compatible with the
806 * version of GTK+ that loads us.
808 GE_EXPORT
const gchar
* g_module_check_init (GModule
*module
);
810 g_module_check_init (GModule
*module
)
814 return gtk_check_version (GTK_MAJOR_VERSION
,
816 GTK_MICRO_VERSION
- GTK_INTERFACE_AGE
);