1 #include <math.h>
2 #include "general-support.h"
3 #include "cairo-support.h"
4
5 /***********************************************
6 * ge_hsb_from_color -
7 *
8 * Get HSB values from RGB values.
9 *
10 * Modified from Smooth but originated in GTK+
11 ***********************************************/
12 void
ge_hsb_from_color(const CairoColor * color,gdouble * hue,gdouble * saturation,gdouble * brightness)13 ge_hsb_from_color (const CairoColor *color,
14 gdouble *hue,
15 gdouble *saturation,
16 gdouble *brightness)
17 {
18 gdouble min, max, delta;
19 gdouble red, green, blue;
20
21 red = color->r;
22 green = color->g;
23 blue = color->b;
24
25 if (red > green)
26 {
27 max = MAX(red, blue);
28 min = MIN(green, blue);
29 }
30 else
31 {
32 max = MAX(green, blue);
33 min = MIN(red, blue);
34 }
35
36 *brightness = (max + min) / 2;
37
38 if (fabs(max - min) < 0.0001)
39 {
40 *hue = 0;
41 *saturation = 0;
42 }
43 else
44 {
45 if (*brightness <= 0.5)
46 *saturation = (max - min) / (max + min);
47 else
48 *saturation = (max - min) / (2 - max - min);
49
50 delta = max -min;
51
52 if (red == max)
53 *hue = (green - blue) / delta;
54 else if (green == max)
55 *hue = 2 + (blue - red) / delta;
56 else if (blue == max)
57 *hue = 4 + (red - green) / delta;
58
59 *hue *= 60;
60 if (*hue < 0.0)
61 *hue += 360;
62 }
63 }
64
65 /***********************************************
66 * ge_color_from_hsb -
67 *
68 * Get RGB values from HSB values.
69 *
70 * Modified from Smooth but originated in GTK+
71 ***********************************************/
72 #define MODULA(number, divisor) (((gint)number % divisor) + (number - (gint)number))
73 void
ge_color_from_hsb(gdouble hue,gdouble saturation,gdouble brightness,CairoColor * color)74 ge_color_from_hsb (gdouble hue,
75 gdouble saturation,
76 gdouble brightness,
77 CairoColor *color)
78 {
79 gint i;
80 gdouble hue_shift[3], color_shift[3];
81 gdouble m1, m2, m3;
82
83 if (!color) return;
84
85 if (brightness <= 0.5)
86 m2 = brightness * (1 + saturation);
87 else
88 m2 = brightness + saturation - brightness * saturation;
89
90 m1 = 2 * brightness - m2;
91
92 hue_shift[0] = hue + 120;
93 hue_shift[1] = hue;
94 hue_shift[2] = hue - 120;
95
96 color_shift[0] = color_shift[1] = color_shift[2] = brightness;
97
98 i = (saturation == 0)?3:0;
99
100 for (; i < 3; i++)
101 {
102 m3 = hue_shift[i];
103
104 if (m3 > 360)
105 m3 = MODULA(m3, 360);
106 else if (m3 < 0)
107 m3 = 360 - MODULA(ABS(m3), 360);
108
109 if (m3 < 60)
110 color_shift[i] = m1 + (m2 - m1) * m3 / 60;
111 else if (m3 < 180)
112 color_shift[i] = m2;
113 else if (m3 < 240)
114 color_shift[i] = m1 + (m2 - m1) * (240 - m3) / 60;
115 else
116 color_shift[i] = m1;
117 }
118
119 color->r = color_shift[0];
120 color->g = color_shift[1];
121 color->b = color_shift[2];
122 color->a = 1.0;
123 }
124
125 void
ge_gdk_color_to_cairo(const GdkColor * c,CairoColor * cc)126 ge_gdk_color_to_cairo (const GdkColor *c, CairoColor *cc)
127 {
128 gdouble r, g, b;
129
130 g_return_if_fail (c && cc);
131
132 r = c->red / 65535.0;
133 g = c->green / 65535.0;
134 b = c->blue / 65535.0;
135
136 cc->r = r;
137 cc->g = g;
138 cc->b = b;
139 cc->a = 1.0;
140 }
141
142 void
ge_cairo_color_to_gtk(const CairoColor * cc,GdkColor * c)143 ge_cairo_color_to_gtk (const CairoColor *cc, GdkColor *c)
144 {
145 gdouble r, g, b;
146
147 g_return_if_fail (c && cc);
148
149 r = cc->r * 65535.0;
150 g = cc->g * 65535.0;
151 b = cc->b * 65535.0;
152
153 c->red = r;
154 c->green = g;
155 c->blue = b;
156 }
157
158 void
ge_gtk_style_to_cairo_color_cube(GtkStyle * style,CairoColorCube * cube)159 ge_gtk_style_to_cairo_color_cube (GtkStyle * style, CairoColorCube *cube)
160 {
161 int i;
162
163 g_return_if_fail (style && cube);
164
165 for (i = 0; i < 5; i++)
166 {
167 ge_gdk_color_to_cairo (&style->bg[i], &cube->bg[i]);
168 ge_gdk_color_to_cairo (&style->fg[i], &cube->fg[i]);
169
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]);
173
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]);
177 }
178
179 cube->black.r = cube->black.g = cube->black.b = 0;
180 cube->black.a = 1;
181
182 cube->white.r = cube->white.g = cube->white.b = 1;
183 cube->white.a = 1;
184 }
185
186 void
ge_shade_color(const CairoColor * base,gdouble shade_ratio,CairoColor * composite)187 ge_shade_color(const CairoColor *base, gdouble shade_ratio, CairoColor *composite)
188 {
189 gdouble hue = 0;
190 gdouble saturation = 0;
191 gdouble brightness = 0;
192
193 g_return_if_fail (base && composite);
194
195 ge_hsb_from_color (base, &hue, &saturation, &brightness);
196
197 brightness = MIN(brightness*shade_ratio, 1.0);
198 brightness = MAX(brightness, 0.0);
199
200 saturation = MIN(saturation*shade_ratio, 1.0);
201 saturation = MAX(saturation, 0.0);
202
203 ge_color_from_hsb (hue, saturation, brightness, composite);
204 composite->a = base->a;
205 }
206
207 void
ge_saturate_color(const CairoColor * base,gdouble saturate_level,CairoColor * composite)208 ge_saturate_color (const CairoColor *base, gdouble saturate_level, CairoColor *composite)
209 {
210 gdouble hue = 0;
211 gdouble saturation = 0;
212 gdouble brightness = 0;
213
214 g_return_if_fail (base && composite);
215
216 ge_hsb_from_color (base, &hue, &saturation, &brightness);
217
218 saturation = MIN(saturation*saturate_level, 1.0);
219 saturation = MAX(saturation, 0.0);
220
221 ge_color_from_hsb (hue, saturation, brightness, composite);
222 composite->a = base->a;
223 }
224
225 void
ge_mix_color(const CairoColor * color1,const CairoColor * color2,gdouble mix_factor,CairoColor * composite)226 ge_mix_color (const CairoColor *color1, const CairoColor *color2,
227 gdouble mix_factor, CairoColor *composite)
228 {
229 g_return_if_fail (color1 && color2 && composite);
230
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;
234 composite->a = 1.0;
235 }
236
237 cairo_t *
ge_gdk_drawable_to_cairo(GdkDrawable * window,GdkRectangle * area)238 ge_gdk_drawable_to_cairo (GdkDrawable *window, GdkRectangle *area)
239 {
240 cairo_t *cr;
241
242 g_return_val_if_fail (window != NULL, NULL);
243
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);
248
249 if (area)
250 {
251 cairo_rectangle (cr, area->x, area->y, area->width, area->height);
252 cairo_clip_preserve (cr);
253 cairo_new_path (cr);
254 }
255
256 return cr;
257 }
258
259 void
ge_cairo_set_color(cairo_t * cr,const CairoColor * color)260 ge_cairo_set_color (cairo_t *cr, const CairoColor *color)
261 {
262 g_return_if_fail (cr && color);
263
264 cairo_set_source_rgba (cr, color->r, color->g, color->b, color->a);
265 }
266
267 void
ge_cairo_set_gdk_color_with_alpha(cairo_t * cr,const GdkColor * color,gdouble alpha)268 ge_cairo_set_gdk_color_with_alpha (cairo_t *cr, const GdkColor *color, gdouble alpha)
269 {
270 g_return_if_fail (cr && color);
271
272 cairo_set_source_rgba (cr, color->red / 65535.0,
273 color->green / 65535.0,
274 color->blue / 65535.0,
275 alpha);
276 }
277
278 void
ge_cairo_pattern_add_color_stop_color(cairo_pattern_t * pattern,gfloat offset,const CairoColor * color)279 ge_cairo_pattern_add_color_stop_color (cairo_pattern_t *pattern,
280 gfloat offset,
281 const CairoColor *color)
282 {
283 g_return_if_fail (pattern && color);
284
285 cairo_pattern_add_color_stop_rgba (pattern, offset, color->r, color->g, color->b, color->a);
286 }
287
288 void
ge_cairo_pattern_add_color_stop_shade(cairo_pattern_t * pattern,gdouble offset,const CairoColor * color,gdouble shade)289 ge_cairo_pattern_add_color_stop_shade(cairo_pattern_t *pattern,
290 gdouble offset,
291 const CairoColor *color,
292 gdouble shade)
293 {
294 CairoColor shaded;
295
296 g_return_if_fail (pattern && color && (shade >= 0) && (shade <= 3));
297
298 shaded = *color;
299
300 if (shade != 1)
301 {
302 ge_shade_color(color, shade, &shaded);
303 }
304
305 ge_cairo_pattern_add_color_stop_color(pattern, offset, &shaded);
306 }
307
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. */
311 void
ge_cairo_rounded_corner(cairo_t * cr,double x,double y,double radius,CairoCorners corner)312 ge_cairo_rounded_corner (cairo_t *cr,
313 double x,
314 double y,
315 double radius,
316 CairoCorners corner)
317 {
318 if (radius < 0.0001)
319 {
320 cairo_line_to (cr, x, y);
321 }
322 else
323 {
324 switch (corner) {
325 case CR_CORNER_NONE:
326 cairo_line_to (cr, x, y);
327 break;
328 case CR_CORNER_TOPLEFT:
329 cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI * 3/2);
330 break;
331 case CR_CORNER_TOPRIGHT:
332 cairo_arc (cr, x - radius, y + radius, radius, G_PI * 3/2, G_PI * 2);
333 break;
334 case CR_CORNER_BOTTOMRIGHT:
335 cairo_arc (cr, x - radius, y - radius, radius, 0, G_PI * 1/2);
336 break;
337 case CR_CORNER_BOTTOMLEFT:
338 cairo_arc (cr, x + radius, y - radius, radius, G_PI * 1/2, G_PI);
339 break;
340
341 default:
342 /* A bitfield and not a sane value ... */
343 g_assert_not_reached ();
344 cairo_line_to (cr, x, y);
345 return;
346 }
347 }
348 }
349
350 void
ge_cairo_rounded_rectangle(cairo_t * cr,double x,double y,double w,double h,double radius,CairoCorners corners)351 ge_cairo_rounded_rectangle (cairo_t *cr,
352 double x, double y, double w, double h,
353 double radius, CairoCorners corners)
354 {
355 g_return_if_fail (cr != NULL);
356
357 if (radius < 0.0001 || corners == CR_CORNER_NONE)
358 {
359 cairo_rectangle (cr, x, y, w, h);
360 return;
361 }
362 #ifdef DEVELOPMENT
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");
367 #endif
368
369 if (corners & CR_CORNER_TOPLEFT)
370 cairo_move_to (cr, x+radius, y);
371 else
372 cairo_move_to (cr, x, y);
373
374 if (corners & CR_CORNER_TOPRIGHT)
375 cairo_arc (cr, x+w-radius, y+radius, radius, G_PI * 1.5, G_PI * 2);
376 else
377 cairo_line_to (cr, x+w, y);
378
379 if (corners & CR_CORNER_BOTTOMRIGHT)
380 cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, G_PI * 0.5);
381 else
382 cairo_line_to (cr, x+w, y+h);
383
384 if (corners & CR_CORNER_BOTTOMLEFT)
385 cairo_arc (cr, x+radius, y+h-radius, radius, G_PI * 0.5, G_PI);
386 else
387 cairo_line_to (cr, x, y+h);
388
389 if (corners & CR_CORNER_TOPLEFT)
390 cairo_arc (cr, x+radius, y+radius, radius, G_PI, G_PI * 1.5);
391 else
392 cairo_line_to (cr, x, y);
393 }
394
395
396 /* ge_cairo_stroke_rectangle.
397 *
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.)
401 */
402 void
ge_cairo_stroke_rectangle(cairo_t * cr,double x,double y,double w,double h)403 ge_cairo_stroke_rectangle (cairo_t *cr, double x, double y, double w, double h)
404 {
405 cairo_rectangle (cr, x, y, w, h);
406 cairo_stroke (cr);
407 }
408
409 /***********************************************
410 * ge_cairo_simple_border -
411 *
412 * A simple routine to draw thin squared
413 * borders with a topleft and bottomright color.
414 *
415 * It originated in Smooth-Engine.
416 ***********************************************/
417 void
ge_cairo_simple_border(cairo_t * cr,const CairoColor * tl,const CairoColor * br,gint x,gint y,gint width,gint height,gboolean topleft_overlap)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)
422 {
423 gboolean solid_color;
424
425 g_return_if_fail (cr != NULL);
426 g_return_if_fail (tl != NULL);
427 g_return_if_fail (br != NULL);
428
429
430 solid_color = (tl == br) || ((tl->r == br->r) && (tl->g == br->g) && (tl->b == br->b) && (tl->a == br->a));
431
432 topleft_overlap &= !solid_color;
433
434 cairo_save(cr);
435
436 cairo_set_line_width (cr, 1);
437
438 if (topleft_overlap)
439 {
440 ge_cairo_set_color(cr, br);
441
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);
445
446 cairo_stroke (cr);
447 }
448
449 ge_cairo_set_color(cr, tl);
450
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);
454
455 if (!topleft_overlap)
456 {
457 if (!solid_color)
458 {
459 cairo_stroke(cr);
460 ge_cairo_set_color(cr, br);
461 }
462
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);
466 }
467
468 cairo_stroke(cr);
469
470 cairo_restore(cr);
471 }
472
ge_cairo_polygon(cairo_t * cr,const CairoColor * color,GdkPoint * points,gint npoints)473 void ge_cairo_polygon (cairo_t *cr,
474 const CairoColor *color,
475 GdkPoint *points,
476 gint npoints)
477 {
478 int i = 0;
479
480 cairo_save(cr);
481
482 ge_cairo_set_color(cr, color);
483 cairo_move_to(cr, points[0].x, points[0].y);
484
485 for (i = 1; i < npoints; i++)
486 {
487 if (!((points[i].x == points[i + 1].x) &&
488 (points[i].y == points[i + 1].y)))
489 {
490 cairo_line_to(cr, points[i].x, points[i].y);
491 }
492 }
493
494 if ((points[npoints-1].x != points[0].x) ||
495 (points[npoints-1].y != points[0].y))
496 {
497 cairo_line_to(cr, points[0].x, points[0].y);
498 }
499
500 cairo_fill(cr);
501
502 cairo_restore(cr);
503 }
504
ge_cairo_line(cairo_t * cr,const CairoColor * color,gint x1,gint y1,gint x2,gint y2)505 void ge_cairo_line (cairo_t *cr,
506 const CairoColor *color,
507 gint x1,
508 gint y1,
509 gint x2,
510 gint y2)
511 {
512 cairo_save(cr);
513
514 ge_cairo_set_color(cr, color);
515 cairo_set_line_width (cr, 1);
516
517 cairo_move_to(cr, x1 + 0.5, y1 + 0.5);
518 cairo_line_to(cr, x2 + 0.5, y2 + 0.5);
519
520 cairo_stroke(cr);
521
522 cairo_restore(cr);
523 }
524
525 void
ge_cairo_mirror(cairo_t * cr,CairoMirror mirror,gint * x,gint * y,gint * width,gint * height)526 ge_cairo_mirror (cairo_t *cr,
527 CairoMirror mirror,
528 gint *x,
529 gint *y,
530 gint *width,
531 gint *height)
532 {
533 cairo_matrix_t matrix;
534
535 cairo_matrix_init_identity (&matrix);
536
537 cairo_translate (cr, *x, *y);
538 *x = 0;
539 *y = 0;
540
541 if (mirror & CR_MIRROR_HORIZONTAL)
542 {
543 cairo_matrix_scale (&matrix, -1, 1);
544 *x = -*width;
545 }
546 if (mirror & CR_MIRROR_VERTICAL)
547 {
548 cairo_matrix_scale (&matrix, 1, -1);
549 *y = -*height;
550 }
551
552 cairo_transform (cr, &matrix);
553 }
554
555 void
ge_cairo_exchange_axis(cairo_t * cr,gint * x,gint * y,gint * width,gint * height)556 ge_cairo_exchange_axis (cairo_t *cr,
557 gint *x,
558 gint *y,
559 gint *width,
560 gint *height)
561 {
562 gint tmp;
563 cairo_matrix_t matrix;
564
565 cairo_translate (cr, *x, *y);
566 cairo_matrix_init (&matrix, 0, 1, 1, 0, 0, 0);
567
568 cairo_transform (cr, &matrix);
569
570 /* swap width/height */
571 tmp = *width;
572 *x = 0;
573 *y = 0;
574 *width = *height;
575 *height = tmp;
576 }
577
578
579 /***********************************************
580 * ge_cairo_pattern_fill -
581 *
582 * Fill an area with some pattern
583 * Scaling or tiling if needed
584 ***********************************************/
585 void
ge_cairo_pattern_fill(cairo_t * canvas,CairoPattern * pattern,gint x,gint y,gint width,gint height)586 ge_cairo_pattern_fill(cairo_t *canvas,
587 CairoPattern *pattern,
588 gint x,
589 gint y,
590 gint width,
591 gint height)
592 {
593 cairo_matrix_t original_matrix, current_matrix;
594
595 if (pattern->operator == CAIRO_OPERATOR_DEST)
596 {
597 return;
598 }
599
600 cairo_pattern_get_matrix(pattern->handle, &original_matrix);
601 current_matrix = original_matrix;
602
603 if (pattern->scale != GE_DIRECTION_NONE)
604 {
605 gdouble scale_x = 1.0;
606 gdouble scale_y = 1.0;
607
608 if ((pattern->scale == GE_DIRECTION_VERTICAL) || (pattern->scale == GE_DIRECTION_BOTH))
609 {
610 scale_x = 1.0/width;
611 }
612
613 if ((pattern->scale == GE_DIRECTION_HORIZONTAL) || (pattern->scale == GE_DIRECTION_BOTH))
614 {
615 scale_y = 1.0/height;
616 }
617
618 cairo_matrix_scale(¤t_matrix, scale_x, scale_y);
619 }
620
621 if (pattern->translate != GE_DIRECTION_NONE)
622 {
623 gdouble translate_x = 0;
624 gdouble translate_y = 0;
625
626 if ((pattern->translate == GE_DIRECTION_VERTICAL) || (pattern->translate == GE_DIRECTION_BOTH))
627 {
628 translate_x = 0.0-x;
629 }
630
631 if ((pattern->translate == GE_DIRECTION_HORIZONTAL) || (pattern->translate == GE_DIRECTION_BOTH))
632 {
633 translate_y = 0.0-y;
634 }
635
636 cairo_matrix_translate(¤t_matrix, translate_x, translate_y);
637 }
638
639 cairo_pattern_set_matrix(pattern->handle, ¤t_matrix);
640
641 cairo_save(canvas);
642
643 cairo_set_source(canvas, pattern->handle);
644 cairo_set_operator(canvas, pattern->operator);
645 cairo_rectangle(canvas, x, y, width, height);
646
647 cairo_fill (canvas);
648
649 cairo_restore(canvas);
650
651 cairo_pattern_set_matrix(pattern->handle, &original_matrix);
652 }
653
654 /***********************************************
655 * ge_cairo_color_pattern -
656 *
657 * Create A Solid Color Pattern
658 ***********************************************/
659 CairoPattern*
ge_cairo_color_pattern(CairoColor * base)660 ge_cairo_color_pattern(CairoColor *base)
661 {
662 CairoPattern * result = g_new0(CairoPattern, 1);
663
664 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
665 result->type = CAIRO_PATTERN_TYPE_SOLID;
666 #endif
667
668 result->scale = GE_DIRECTION_NONE;
669 result->translate = GE_DIRECTION_NONE;
670
671 result->handle = cairo_pattern_create_rgba(base->r,
672 base->g,
673 base->b,
674 base->a);
675
676 result->operator = CAIRO_OPERATOR_SOURCE;
677
678 return result;
679 }
680
681 /***********************************************
682 * ge_cairo_pixbuf_pattern -
683 *
684 * Create A Tiled Pixbuf Pattern
685 ***********************************************/
686 CairoPattern*
ge_cairo_pixbuf_pattern(GdkPixbuf * pixbuf)687 ge_cairo_pixbuf_pattern(GdkPixbuf *pixbuf)
688 {
689 CairoPattern * result = g_new0(CairoPattern, 1);
690
691 cairo_t *canvas;
692 cairo_surface_t * surface;
693 gint width, height;
694
695 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
696 result->type = CAIRO_PATTERN_TYPE_SURFACE;
697 #endif
698
699 result->scale = GE_DIRECTION_NONE;
700 result->translate = GE_DIRECTION_BOTH;
701
702 width = gdk_pixbuf_get_width(pixbuf);
703 height = gdk_pixbuf_get_height(pixbuf);
704
705 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
706
707 canvas = cairo_create(surface);
708
709 gdk_cairo_set_source_pixbuf (canvas, pixbuf, 0, 0);
710 cairo_rectangle (canvas, 0, 0, width, height);
711 cairo_fill (canvas);
712 cairo_destroy(canvas);
713
714 result->handle = cairo_pattern_create_for_surface (surface);
715 cairo_surface_destroy(surface);
716
717 cairo_pattern_set_extend (result->handle, CAIRO_EXTEND_REPEAT);
718
719 result->operator = CAIRO_OPERATOR_SOURCE;
720
721 return result;
722 }
723
724 /***********************************************
725 * ge_cairo_pixmap_pattern -
726 *
727 * Create A Tiled Pixmap Pattern
728 ***********************************************/
729 CairoPattern*
ge_cairo_pixmap_pattern(GdkPixmap * pixmap)730 ge_cairo_pixmap_pattern(GdkPixmap *pixmap)
731 {
732 CairoPattern * result = NULL;
733
734 GdkPixbuf * pixbuf;
735 gint width, height;
736
737 gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
738
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);
742
743 result = ge_cairo_pixbuf_pattern(pixbuf);
744
745 g_object_unref (pixbuf);
746
747 return result;
748 }
749
750 /***********************************************
751 * ge_cairo_linear_shade_gradient_pattern -
752 *
753 * Create A Linear Shade Gradient Pattern
754 * Aka Smooth Shade Gradient, from/to gradient
755 * With End points defined as shades of the
756 * base color
757 ***********************************************/
758 CairoPattern *
ge_cairo_linear_shade_gradient_pattern(CairoColor * base,gdouble shade1,gdouble shade2,gboolean vertical)759 ge_cairo_linear_shade_gradient_pattern(CairoColor *base,
760 gdouble shade1,
761 gdouble shade2,
762 gboolean vertical)
763 {
764 CairoPattern * result = g_new0(CairoPattern, 1);
765
766 #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
767 result->type = CAIRO_PATTERN_TYPE_LINEAR;
768 #endif
769
770 if (vertical)
771 {
772 result->scale = GE_DIRECTION_VERTICAL;
773
774 result->handle = cairo_pattern_create_linear(0, 0, 1, 0);
775 }
776 else
777 {
778 result->scale = GE_DIRECTION_HORIZONTAL;
779
780 result->handle = cairo_pattern_create_linear(0, 0, 0, 1);
781 }
782
783 result->translate = GE_DIRECTION_BOTH;
784 result->operator = CAIRO_OPERATOR_SOURCE;
785
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);
788
789 return result;
790 }
791
792 void
ge_cairo_pattern_destroy(CairoPattern * pattern)793 ge_cairo_pattern_destroy(CairoPattern *pattern)
794 {
795 if (pattern)
796 {
797 if (pattern->handle)
798 cairo_pattern_destroy(pattern->handle);
799
800 g_free(pattern);
801 }
802 }
803
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.
807 */
808 GE_EXPORT const gchar* g_module_check_init (GModule *module);
809 const gchar*
g_module_check_init(GModule * module)810 g_module_check_init (GModule *module)
811 {
812 (void) module;
813
814 return gtk_check_version (GTK_MAJOR_VERSION,
815 GTK_MINOR_VERSION,
816 GTK_MICRO_VERSION - GTK_INTERFACE_AGE);
817 }
818