Update to clearlooks from gtk-engines-2.16.0
[ardour.git] / libs / clearlooks / cairo-support.c
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
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
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
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
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 
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
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         if (shade_ratio == 1.0)
196         {
197                 composite->r = base->r;
198                 composite->g = base->g;
199                 composite->b = base->b;
200                 composite->a = base->a;
201                 
202                 return;
203         }
204
205         ge_hsb_from_color (base, &hue, &saturation, &brightness);
206
207         brightness = MIN(brightness*shade_ratio, 1.0);
208         brightness = MAX(brightness, 0.0);
209
210         saturation = MIN(saturation*shade_ratio, 1.0);
211         saturation = MAX(saturation, 0.0);
212
213         ge_color_from_hsb (hue, saturation, brightness, composite);
214         composite->a = base->a; 
215 }
216
217 void
218 ge_saturate_color (const CairoColor *base, gdouble saturate_level, CairoColor *composite)
219 {
220         gdouble hue = 0;
221         gdouble saturation = 0;
222         gdouble brightness = 0;
223
224         g_return_if_fail (base && composite);
225
226         ge_hsb_from_color (base, &hue, &saturation, &brightness);
227
228         saturation = MIN(saturation*saturate_level, 1.0);
229         saturation = MAX(saturation, 0.0);
230
231         ge_color_from_hsb (hue, saturation, brightness, composite);
232         composite->a = base->a; 
233 }
234
235 void
236 ge_mix_color (const CairoColor *color1, const CairoColor *color2,
237               gdouble mix_factor, CairoColor *composite)
238 {
239         g_return_if_fail (color1 && color2 && composite);
240
241         composite->r = color1->r * (1-mix_factor) + color2->r * mix_factor;
242         composite->g = color1->g * (1-mix_factor) + color2->g * mix_factor;
243         composite->b = color1->b * (1-mix_factor) + color2->b * mix_factor;
244         composite->a = 1.0;
245 }
246
247 cairo_t * 
248 ge_gdk_drawable_to_cairo (GdkDrawable  *window, GdkRectangle *area)
249 {
250         cairo_t *cr;
251
252         g_return_val_if_fail (window != NULL, NULL);
253
254         cr = (cairo_t*) gdk_cairo_create (window);
255         cairo_set_line_width (cr, 1.0);
256         cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
257         cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
258
259         if (area)
260         {
261                 cairo_rectangle (cr, area->x, area->y, area->width, area->height);
262                 cairo_clip_preserve (cr);
263                 cairo_new_path (cr);
264         }
265
266         return cr;
267 }
268
269 void 
270 ge_cairo_set_color (cairo_t *cr, const CairoColor *color)
271 {
272         g_return_if_fail (cr && color);
273
274         cairo_set_source_rgba (cr, color->r, color->g, color->b, color->a);     
275 }
276
277 void
278 ge_cairo_set_gdk_color_with_alpha (cairo_t *cr, const GdkColor *color, gdouble alpha)
279 {
280         g_return_if_fail (cr && color);
281
282         cairo_set_source_rgba (cr, color->red / 65535.0,
283                                    color->green / 65535.0,
284                                    color->blue / 65535.0,
285                                    alpha);
286 }
287
288 void 
289 ge_cairo_pattern_add_color_stop_color (cairo_pattern_t *pattern, 
290                                        gfloat offset, 
291                                        const CairoColor *color)
292 {
293         g_return_if_fail (pattern && color);
294
295         cairo_pattern_add_color_stop_rgba (pattern, offset, color->r, color->g, color->b, color->a);    
296 }
297
298 void
299 ge_cairo_pattern_add_color_stop_shade (cairo_pattern_t *pattern, 
300                                        gdouble offset, 
301                                        const CairoColor *color, 
302                                        gdouble shade)
303 {
304         CairoColor shaded;
305
306         g_return_if_fail (pattern && color && (shade >= 0) && (shade <= 3));
307
308         shaded = *color;
309
310         if (shade != 1)
311         {
312                 ge_shade_color(color, shade, &shaded);
313         }
314
315         ge_cairo_pattern_add_color_stop_color(pattern, offset, &shaded);
316 }
317
318 /* 
319  * This function will draw a rounded corner at position x,y. If the radius
320  * is very small (or negative) it will instead just do a line_to.
321  * ge_cairo_rounded_corner assumes clockwise drawing.
322  */
323 void
324 ge_cairo_rounded_corner (cairo_t      *cr,
325                          double        x,
326                          double        y,
327                          double        radius,
328                          CairoCorners  corner)
329 {
330         if (radius < 0.0001)
331         {
332                 cairo_line_to (cr, x, y);
333         }
334         else
335         {
336                 switch (corner)
337                 {
338                         case CR_CORNER_NONE:
339                                 cairo_line_to (cr, x, y);
340                                 break;
341                         case CR_CORNER_TOPLEFT:
342                                 cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI * 3/2);
343                                 break;
344                         case CR_CORNER_TOPRIGHT:
345                                 cairo_arc (cr, x - radius, y + radius, radius, G_PI * 3/2, G_PI * 2);
346                                 break;
347                         case CR_CORNER_BOTTOMRIGHT:
348                                 cairo_arc (cr, x - radius, y - radius, radius, 0, G_PI * 1/2);
349                                 break;
350                         case CR_CORNER_BOTTOMLEFT:
351                                 cairo_arc (cr, x + radius, y - radius, radius, G_PI * 1/2, G_PI);
352                                 break;
353
354                         default:
355                                 /* A bitfield and not a sane value ... */
356                                 g_assert_not_reached ();
357                                 cairo_line_to (cr, x, y);
358                                 return;
359                 }
360         }
361 }
362
363 void
364 ge_cairo_rounded_rectangle (cairo_t *cr,
365                                  double x, double y, double w, double h,
366                                  double radius, CairoCorners corners)
367 {
368         g_return_if_fail (cr != NULL);
369
370         if (radius < 0.0001 || corners == CR_CORNER_NONE)
371         {
372                 cairo_rectangle (cr, x, y, w, h);
373                 return;
374         }
375 #ifdef DEVELOPMENT
376         if ((corners == CR_CORNER_ALL) && (radius > w / 2.0 || radius > h / 2.0))
377                 g_warning ("Radius is too large for width/height in ge_rounded_rectangle.\n");
378         else if (radius > w || radius > h) /* This isn't perfect. Assumes that only one corner is set. */
379                 g_warning ("Radius is too large for width/height in ge_rounded_rectangle.\n");
380 #endif
381
382         if (corners & CR_CORNER_TOPLEFT)
383                 cairo_move_to (cr, x+radius, y);
384         else
385                 cairo_move_to (cr, x, y);
386         
387         if (corners & CR_CORNER_TOPRIGHT)
388                 cairo_arc (cr, x+w-radius, y+radius, radius, G_PI * 1.5, G_PI * 2);
389         else
390                 cairo_line_to (cr, x+w, y);
391         
392         if (corners & CR_CORNER_BOTTOMRIGHT)
393                 cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, G_PI * 0.5);
394         else
395                 cairo_line_to (cr, x+w, y+h);
396         
397         if (corners & CR_CORNER_BOTTOMLEFT)
398                 cairo_arc (cr, x+radius,   y+h-radius, radius, G_PI * 0.5, G_PI);
399         else
400                 cairo_line_to (cr, x, y+h);
401         
402         if (corners & CR_CORNER_TOPLEFT)
403                 cairo_arc (cr, x+radius,   y+radius,   radius, G_PI, G_PI * 1.5);
404         else
405                 cairo_line_to (cr, x, y);
406 }
407
408
409 /* ge_cairo_stroke_rectangle.
410  *
411  *   A simple function to stroke the rectangle { x, y, w, h}.
412  *   (This function only exists because of a cairo performance bug that
413  *   has been fixed and it may be a good idea to get rid of it again.)
414  */
415 void
416 ge_cairo_stroke_rectangle (cairo_t *cr, double x, double y, double w, double h)
417 {
418         cairo_rectangle (cr, x, y, w, h);
419         cairo_stroke (cr);
420 }
421
422 void
423 ge_cairo_inner_rectangle (cairo_t *cr,
424                           double x, double y,
425                           double width, double height)
426 {
427         double line_width = cairo_get_line_width (cr);
428
429         cairo_rectangle (cr, x + line_width / 2.0,
430                              y + line_width / 2.0,
431                              width - line_width,
432                              height - line_width);
433 }
434
435 void
436 ge_cairo_inner_rounded_rectangle (cairo_t *cr,
437                                   double x, double y,
438                                   double width, double height,
439                                   double radius, CairoCorners corners)
440 {
441         double line_width = cairo_get_line_width (cr);
442
443         ge_cairo_rounded_rectangle (cr,
444                                     x + line_width / 2.0,
445                                     y + line_width / 2.0,
446                                     width - line_width,
447                                     height - line_width,
448                                     radius, corners);
449 }
450
451 /***********************************************
452  * ge_cairo_simple_border -
453  *  
454  *   A simple routine to draw thin squared
455  *   borders with a topleft and bottomright color.
456  *   
457  *   It originated in Smooth-Engine.
458  ***********************************************/
459 void
460 ge_cairo_simple_border (cairo_t *cr,
461                         const CairoColor * tl, const CairoColor * br,
462                         gint x, gint y, gint width, gint height, 
463                         gboolean topleft_overlap)
464 {
465         gboolean solid_color;
466
467         g_return_if_fail (cr != NULL);
468         g_return_if_fail (tl != NULL);
469         g_return_if_fail (br != NULL);
470         
471
472         solid_color = (tl == br) || ((tl->r == br->r) && (tl->g == br->g) && (tl->b == br->b) && (tl->a == br->a));
473
474         topleft_overlap &= !solid_color;
475
476         cairo_save(cr);
477
478         cairo_set_line_width (cr, 1);
479
480         if (topleft_overlap)
481         {
482                 ge_cairo_set_color(cr, br);     
483
484                 cairo_move_to(cr, x + 0.5, y + height - 0.5);
485                 cairo_line_to(cr, x + width - 0.5, y + height - 0.5);
486                 cairo_line_to(cr, x + width - 0.5, y + 0.5);
487                 
488                 cairo_stroke (cr);
489         }
490
491         ge_cairo_set_color(cr, tl);     
492
493         cairo_move_to(cr, x + 0.5, y + height - 0.5);
494         cairo_line_to(cr, x + 0.5, y + 0.5);
495         cairo_line_to(cr, x + width - 0.5, y + 0.5);
496
497         if (!topleft_overlap)
498         {
499                 if (!solid_color)
500                 {
501                         cairo_stroke(cr);
502                         ge_cairo_set_color(cr, br);     
503                 }
504
505                 cairo_move_to(cr, x + 0.5, y + height - 0.5);
506                 cairo_line_to(cr, x + width - 0.5, y + height - 0.5);
507                 cairo_line_to(cr, x + width - 0.5, y + 0.5);
508         }
509
510         cairo_stroke(cr);
511
512         cairo_restore(cr);
513 }
514
515 void ge_cairo_polygon (cairo_t *cr,
516                        const CairoColor *color,
517                        GdkPoint *points,
518                        gint npoints)
519 {
520         int i = 0;
521
522         cairo_save(cr);
523
524         ge_cairo_set_color(cr, color);  
525         cairo_move_to(cr, points[0].x, points[0].y);
526
527         for (i = 1; i < npoints; i++)
528         {
529                 if (!((points[i].x == points[i + 1].x) &&
530                     (points[i].y == points[i + 1].y))) 
531                 {
532                         cairo_line_to(cr, points[i].x, points[i].y);
533                 }
534         }
535         
536         if ((points[npoints-1].x != points[0].y) ||
537                 (points[npoints-1].y != points[0].y))
538         {
539                 cairo_line_to(cr, points[0].x, points[0].y);
540         }
541
542         cairo_fill(cr);
543
544         cairo_restore(cr);
545 }
546
547 void ge_cairo_line (cairo_t *cr,
548                     const CairoColor *color,
549                     gint x1,
550                     gint y1,
551                     gint x2,
552                     gint y2)
553 {
554         cairo_save(cr);
555
556         ge_cairo_set_color(cr, color);  
557         cairo_set_line_width (cr, 1);
558
559         cairo_move_to(cr, x1 + 0.5, y1 + 0.5);
560         cairo_line_to(cr, x2 + 0.5, y2 + 0.5);
561
562         cairo_stroke(cr);
563
564         cairo_restore(cr);
565 }
566
567 void
568 ge_cairo_mirror (cairo_t     *cr,
569                  CairoMirror  mirror,
570                  gint        *x,
571                  gint        *y,
572                  gint        *width,
573                  gint        *height)
574 {
575         cairo_matrix_t matrix;
576         
577         cairo_matrix_init_identity (&matrix);
578         
579         cairo_translate (cr, *x, *y);
580         *x = 0;
581         *y = 0;
582         
583         if (mirror & CR_MIRROR_HORIZONTAL)
584         {
585                 cairo_matrix_scale (&matrix, -1, 1);
586                 *x = -*width;
587         }
588         if (mirror & CR_MIRROR_VERTICAL)
589         {
590                 cairo_matrix_scale (&matrix, 1, -1);
591                 *y = -*height;
592         }
593
594         cairo_transform (cr, &matrix);
595 }
596
597 void
598 ge_cairo_exchange_axis (cairo_t  *cr,
599                         gint     *x,
600                         gint     *y,
601                         gint     *width,
602                         gint     *height)
603 {
604         gint tmp;
605         cairo_matrix_t matrix;
606
607         cairo_translate (cr, *x, *y);
608         cairo_matrix_init (&matrix, 0, 1, 1, 0, 0, 0);
609
610         cairo_transform (cr, &matrix);
611         
612         /* swap width/height */
613         tmp = *width;
614         *x = 0;
615         *y = 0;
616         *width = *height;
617         *height = tmp;
618 }
619
620
621 /***********************************************
622  * ge_cairo_pattern_fill -
623  *  
624  *   Fill an area with some pattern
625  *   Scaling or tiling if needed
626  ***********************************************/
627 void 
628 ge_cairo_pattern_fill(cairo_t *canvas,
629                       CairoPattern *pattern,
630                       gint x,
631                       gint y,
632                       gint width,
633                       gint height)
634 {
635         cairo_matrix_t original_matrix, current_matrix;
636
637         if (pattern->operator == CAIRO_OPERATOR_DEST)
638                 return;
639         
640         if (width <= 0 || height <= 0)
641                 return;
642
643         cairo_pattern_get_matrix(pattern->handle, &original_matrix);
644         current_matrix = original_matrix;
645
646         if (pattern->scale != GE_DIRECTION_NONE)
647         {
648                 gdouble scale_x = 1.0;
649                 gdouble scale_y = 1.0;
650
651                 if ((pattern->scale == GE_DIRECTION_VERTICAL) || (pattern->scale == GE_DIRECTION_BOTH))
652                 {
653                         scale_x = 1.0/width;
654                 }
655
656                 if ((pattern->scale == GE_DIRECTION_HORIZONTAL) || (pattern->scale == GE_DIRECTION_BOTH))
657                 {
658                         scale_y = 1.0/height;
659                 }
660
661                 cairo_matrix_scale(&current_matrix, scale_x, scale_y);
662         }
663
664         if (pattern->translate != GE_DIRECTION_NONE)
665         {
666                 gdouble translate_x = 0;
667                 gdouble translate_y = 0;
668
669                 if ((pattern->translate == GE_DIRECTION_VERTICAL) || (pattern->translate == GE_DIRECTION_BOTH))
670                 {
671                         translate_x = 0.0-x;
672                 }
673
674                 if ((pattern->translate == GE_DIRECTION_HORIZONTAL) || (pattern->translate == GE_DIRECTION_BOTH))
675                 {
676                         translate_y = 0.0-y;
677                 }
678
679                 cairo_matrix_translate(&current_matrix, translate_x, translate_y);
680         }
681
682         cairo_pattern_set_matrix(pattern->handle, &current_matrix);
683
684         cairo_save(canvas);
685
686         cairo_set_source(canvas, pattern->handle);
687         cairo_set_operator(canvas, pattern->operator);
688         cairo_rectangle(canvas, x, y, width, height);
689
690         cairo_fill (canvas);
691
692         cairo_restore(canvas);
693
694         cairo_pattern_set_matrix(pattern->handle, &original_matrix);
695 }
696
697 /***********************************************
698  * ge_cairo_color_pattern -
699  *  
700  *   Create A Solid Color Pattern
701  ***********************************************/
702 CairoPattern*
703 ge_cairo_color_pattern(CairoColor *base)
704 {
705         CairoPattern * result = g_new0(CairoPattern, 1);
706
707         #if  ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
708                 result->type = CAIRO_PATTERN_TYPE_SOLID;
709         #endif
710
711         result->scale = GE_DIRECTION_NONE;
712         result->translate = GE_DIRECTION_NONE;
713
714         result->handle = cairo_pattern_create_rgba(base->r,
715                                                    base->g,
716                                                    base->b, 
717                                                    base->a);
718
719         result->operator = CAIRO_OPERATOR_SOURCE;
720         
721         return result;
722 }
723
724 /***********************************************
725  * ge_cairo_pixbuf_pattern -
726  *  
727  *   Create A Tiled Pixbuf Pattern
728  ***********************************************/
729 CairoPattern*
730 ge_cairo_pixbuf_pattern(GdkPixbuf *pixbuf)
731 {
732         CairoPattern * result = g_new0(CairoPattern, 1);
733
734         cairo_t *canvas;
735         cairo_surface_t * surface;
736         gint width, height;
737
738         #if ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
739                 result->type = CAIRO_PATTERN_TYPE_SURFACE;
740         #endif
741
742         result->scale = GE_DIRECTION_NONE;
743         result->translate = GE_DIRECTION_BOTH;
744
745         width = gdk_pixbuf_get_width(pixbuf);
746         height = gdk_pixbuf_get_height(pixbuf);
747         
748         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
749
750         canvas = cairo_create(surface);
751
752         gdk_cairo_set_source_pixbuf (canvas, pixbuf, 0, 0);
753         cairo_rectangle (canvas, 0, 0, width, height);
754         cairo_fill (canvas);
755         cairo_destroy(canvas);
756
757         result->handle = cairo_pattern_create_for_surface (surface);
758         cairo_surface_destroy(surface);
759
760         cairo_pattern_set_extend (result->handle, CAIRO_EXTEND_REPEAT);
761
762         result->operator = CAIRO_OPERATOR_SOURCE;
763
764         return result;
765 }
766
767 /***********************************************
768  * ge_cairo_pixmap_pattern -
769  *  
770  *   Create A Tiled Pixmap Pattern
771  ***********************************************/
772 CairoPattern*
773 ge_cairo_pixmap_pattern(GdkPixmap *pixmap)
774 {       
775         CairoPattern * result = NULL;
776
777         GdkPixbuf * pixbuf;
778         gint width, height;
779
780         gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
781
782         pixbuf = gdk_pixbuf_get_from_drawable(NULL, GDK_DRAWABLE (pixmap), 
783                  gdk_drawable_get_colormap(GDK_DRAWABLE (pixmap)), 
784                  0, 0, 0, 0, width, height);
785
786         result = ge_cairo_pixbuf_pattern(pixbuf);
787         
788         g_object_unref (pixbuf);
789
790         return result;
791 }
792
793 /***********************************************
794  * ge_cairo_linear_shade_gradient_pattern - 
795  *  
796  *   Create A Linear Shade Gradient Pattern
797  *   Aka Smooth Shade Gradient, from/to gradient
798  *   With End points defined as shades of the
799  *   base color
800  ***********************************************/
801 CairoPattern *
802 ge_cairo_linear_shade_gradient_pattern(CairoColor *base, 
803                                        gdouble shade1, 
804                                        gdouble shade2, 
805                                        gboolean vertical)
806 {
807         CairoPattern * result = g_new0(CairoPattern, 1);
808         
809         #if  ((CAIRO_VERSION_MAJOR < 1) || ((CAIRO_VERSION_MAJOR == 1) && (CAIRO_VERSION_MINOR < 2)))
810                 result->type = CAIRO_PATTERN_TYPE_LINEAR;
811         #endif
812
813         if (vertical)
814         {
815                 result->scale = GE_DIRECTION_VERTICAL;
816
817                 result->handle = cairo_pattern_create_linear(0, 0, 1, 0);
818         }
819         else
820         {
821                 result->scale = GE_DIRECTION_HORIZONTAL;
822
823                 result->handle = cairo_pattern_create_linear(0, 0, 0, 1);
824         }
825
826         result->translate = GE_DIRECTION_BOTH;
827         result->operator = CAIRO_OPERATOR_SOURCE;
828
829         ge_cairo_pattern_add_color_stop_shade(result->handle, 0, base, shade1);
830         ge_cairo_pattern_add_color_stop_shade(result->handle, 1, base, shade2);
831
832         return result;
833 }
834
835 void
836 ge_cairo_pattern_destroy(CairoPattern *pattern)
837 {
838         if (pattern)
839         {
840                 if (pattern->handle)
841                         cairo_pattern_destroy(pattern->handle);
842                 
843                 g_free(pattern);
844         }
845 }
846
847 /* 
848  * The following function will be called by GTK+ when the module
849  * is loaded and checks to see if we are compatible with the
850  * version of GTK+ that loads us.
851  */
852 GE_EXPORT const gchar* g_module_check_init (GModule *module);
853 const gchar*
854 g_module_check_init (GModule *module)
855 {
856         return gtk_check_version (GTK_MAJOR_VERSION,
857                                   GTK_MINOR_VERSION,
858                                   GTK_MICRO_VERSION - GTK_INTERFACE_AGE);
859 }