summaryrefslogtreecommitdiffstats
path: root/tdegtk
diff options
context:
space:
mode:
Diffstat (limited to 'tdegtk')
-rw-r--r--tdegtk/Makefile.am31
-rw-r--r--tdegtk/exponential-blur.c288
-rw-r--r--tdegtk/exponential-blur.h37
-rw-r--r--tdegtk/gtkroundedbox.c421
-rw-r--r--tdegtk/gtkroundedboxprivate.h88
-rw-r--r--tdegtk/raico-blur.c173
-rw-r--r--tdegtk/raico-blur.h67
-rw-r--r--tdegtk/tdegtk-cairo-support.c1418
-rw-r--r--tdegtk/tdegtk-cairo-support.h85
-rw-r--r--tdegtk/tdegtk-draw.c1062
-rw-r--r--tdegtk/tdegtk-draw.h36
-rw-r--r--tdegtk/tdegtk-engine.c525
-rw-r--r--tdegtk/tdegtk-engine.h61
-rw-r--r--tdegtk/tdegtk-support.c89
-rw-r--r--tdegtk/tdegtk-support.h51
-rw-r--r--tdegtk/tdegtk-theme.c51
-rw-r--r--tdegtk/tdegtk-types.h133
-rw-r--r--tdegtk/tdegtk.h33
18 files changed, 4649 insertions, 0 deletions
diff --git a/tdegtk/Makefile.am b/tdegtk/Makefile.am
new file mode 100644
index 0000000..7bf792b
--- /dev/null
+++ b/tdegtk/Makefile.am
@@ -0,0 +1,31 @@
+source_h = \
+ $(srcdir)/tdegtk.h \
+ $(srcdir)/exponential-blur.h \
+ $(srcdir)/gtkroundedboxprivate.h \
+ $(srcdir)/raico-blur.h \
+ $(srcdir)/tdegtk-cairo-support.h \
+ $(srcdir)/tdegtk-draw.h \
+ $(srcdir)/tdegtk-engine.h \
+ $(srcdir)/tdegtk-support.h \
+ $(srcdir)/tdegtk-types.h
+
+source_c = \
+ $(srcdir)/exponential-blur.c \
+ $(srcdir)/gtkroundedbox.c \
+ $(srcdir)/raico-blur.c \
+ $(srcdir)/tdegtk-cairo-support.c \
+ $(srcdir)/tdegtk-draw.c \
+ $(srcdir)/tdegtk-engine.c \
+ $(srcdir)/tdegtk-support.c \
+ $(srcdir)/tdegtk-theme.c
+
+enginedir = $(libdir)/gtk-3.0/$(GTK_VERSION)/theming-engines
+engine_LTLIBRARIES = libtdegtk.la
+
+libtdegtk_la_SOURCES = $(source_h) $(source_c)
+
+libtdegtk_la_CFLAGS = $(TDEGTK_CFLAGS)
+
+libtdegtk_la_LIBADD = $(TDEGTK_LIBADD)
+
+libtdegtk_la_LDFLAGS = $(TDEGTK_LDFLAGS)
diff --git a/tdegtk/exponential-blur.c b/tdegtk/exponential-blur.c
new file mode 100644
index 0000000..95515c5
--- /dev/null
+++ b/tdegtk/exponential-blur.c
@@ -0,0 +1,288 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2009 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Mirco "MacSlow" Mueller <[email protected]>
+ *
+ * Notes:
+ * based on exponential-blur algorithm by Jani Huhtanen
+ *
+ */
+
+/* FIXME: not working yet, unfinished */
+
+#include <math.h>
+
+#include "exponential-blur.h"
+
+static inline void
+_blurinner (guchar* pixel,
+ gint *zR,
+ gint *zG,
+ gint *zB,
+ gint *zA,
+ gint alpha,
+ gint aprec,
+ gint zprec);
+
+static inline void
+_blurrow (guchar* pixels,
+ gint width,
+ gint height,
+ gint channels,
+ gint line,
+ gint alpha,
+ gint aprec,
+ gint zprec);
+
+static inline void
+_blurcol (guchar* pixels,
+ gint width,
+ gint height,
+ gint channels,
+ gint col,
+ gint alpha,
+ gint aprec,
+ gint zprec);
+
+void
+_expblur (guchar* pixels,
+ gint width,
+ gint height,
+ gint channels,
+ gint radius,
+ gint aprec,
+ gint zprec);
+
+void
+surface_exponential_blur (cairo_surface_t* surface,
+ guint radius)
+{
+ guchar* pixels;
+ guint width;
+ guint height;
+ cairo_format_t format;
+
+ /* sanity checks are done in raico-blur.c */
+
+ /* before we mess with the surface execute any pending drawing */
+ cairo_surface_flush (surface);
+
+ pixels = cairo_image_surface_get_data (surface);
+ width = cairo_image_surface_get_width (surface);
+ height = cairo_image_surface_get_height (surface);
+ format = cairo_image_surface_get_format (surface);
+
+ switch (format)
+ {
+ case CAIRO_FORMAT_ARGB32:
+ _expblur (pixels, width, height, 4, radius, 16, 7);
+ break;
+ case CAIRO_FORMAT_RGB24:
+ _expblur (pixels, width, height, 3, radius, 16, 7);
+ break;
+ case CAIRO_FORMAT_A8:
+ _expblur (pixels, width, height, 1, radius, 16, 7);
+ break;
+ default:
+ break;
+ }
+
+ /* inform cairo we altered the surfaces contents */
+ cairo_surface_mark_dirty (surface);
+}
+
+/*
+ * pixels image-data
+ * width image-width
+ * height image-height
+ * channels image-channels
+ *
+ * in-place blur of image 'img' with kernel of approximate radius 'radius'
+ *
+ * blurs with two sided exponential impulse response
+ *
+ * aprec = precision of alpha parameter in fixed-point format 0.aprec
+ *
+ * zprec = precision of state parameters zR,zG,zB and zA in fp format 8.zprec
+ */
+void
+_expblur (guchar* pixels,
+ gint width,
+ gint height,
+ gint channels,
+ gint radius,
+ gint aprec,
+ gint zprec)
+{
+ gint alpha;
+ gint row = 0;
+ gint col = 0;
+
+ if (radius < 1)
+ return;
+
+ /* calculate the alpha such that 90% of
+ * the kernel is within the radius.
+ * (Kernel extends to infinity) */
+ alpha = (gint) ((1 << aprec) * (1.0f - expf (-2.3f / (radius + 1.f))));
+
+ for (; row < height; row++)
+ _blurrow (pixels,
+ width,
+ height,
+ channels,
+ row,
+ alpha,
+ aprec,
+ zprec);
+
+ for(; col < width; col++)
+ _blurcol (pixels,
+ width,
+ height,
+ channels,
+ col,
+ alpha,
+ aprec,
+ zprec);
+
+ return;
+}
+
+static inline void
+_blurinner (guchar* pixel,
+ gint *zR,
+ gint *zG,
+ gint *zB,
+ gint *zA,
+ gint alpha,
+ gint aprec,
+ gint zprec)
+{
+ gint R;
+ gint G;
+ gint B;
+ guchar A;
+
+ R = *pixel;
+ G = *(pixel + 1);
+ B = *(pixel + 2);
+ A = *(pixel + 3);
+
+ *zR += (alpha * ((R << zprec) - *zR)) >> aprec;
+ *zG += (alpha * ((G << zprec) - *zG)) >> aprec;
+ *zB += (alpha * ((B << zprec) - *zB)) >> aprec;
+ *zA += (alpha * ((A << zprec) - *zA)) >> aprec;
+
+ *pixel = *zR >> zprec;
+ *(pixel + 1) = *zG >> zprec;
+ *(pixel + 2) = *zB >> zprec;
+ *(pixel + 3) = *zA >> zprec;
+}
+
+static inline void
+_blurrow (guchar* pixels,
+ gint width,
+ gint height,
+ gint channels,
+ gint line,
+ gint alpha,
+ gint aprec,
+ gint zprec)
+{
+ gint zR;
+ gint zG;
+ gint zB;
+ gint zA;
+ gint index;
+ guchar* scanline;
+
+ scanline = &(pixels[line * width * channels]);
+
+ zR = *scanline << zprec;
+ zG = *(scanline + 1) << zprec;
+ zB = *(scanline + 2) << zprec;
+ zA = *(scanline + 3) << zprec;
+
+ for (index = 0; index < width; index ++)
+ _blurinner (&scanline[index * channels],
+ &zR,
+ &zG,
+ &zB,
+ &zA,
+ alpha,
+ aprec,
+ zprec);
+
+ for (index = width - 2; index >= 0; index--)
+ _blurinner (&scanline[index * channels],
+ &zR,
+ &zG,
+ &zB,
+ &zA,
+ alpha,
+ aprec,
+ zprec);
+}
+
+static inline void
+_blurcol (guchar* pixels,
+ gint width,
+ gint height,
+ gint channels,
+ gint x,
+ gint alpha,
+ gint aprec,
+ gint zprec)
+{
+ gint zR;
+ gint zG;
+ gint zB;
+ gint zA;
+ gint index;
+ guchar* ptr;
+
+ ptr = pixels;
+
+ ptr += x * channels;
+
+ zR = *((guchar*) ptr ) << zprec;
+ zG = *((guchar*) ptr + 1) << zprec;
+ zB = *((guchar*) ptr + 2) << zprec;
+ zA = *((guchar*) ptr + 3) << zprec;
+
+ for (index = width; index < (height - 1) * width; index += width)
+ _blurinner ((guchar*) &ptr[index * channels],
+ &zR,
+ &zG,
+ &zB,
+ &zA,
+ alpha,
+ aprec,
+ zprec);
+
+ for (index = (height - 2) * width; index >= 0; index -= width)
+ _blurinner ((guchar*) &ptr[index * channels],
+ &zR,
+ &zG,
+ &zB,
+ &zA,
+ alpha,
+ aprec,
+ zprec);
+}
diff --git a/tdegtk/exponential-blur.h b/tdegtk/exponential-blur.h
new file mode 100644
index 0000000..5d9cfa3
--- /dev/null
+++ b/tdegtk/exponential-blur.h
@@ -0,0 +1,37 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2009 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Mirco "MacSlow" Mueller <[email protected]>
+ *
+ * Notes:
+ * based on exponential-blur algorithm by Jani Huhtanen
+ *
+ */
+
+#ifndef _EXPONENTIAL_BLUR_H
+#define _EXPONENTIAL_BLUR_H
+
+#include <cairo.h>
+#include <glib.h>
+
+void
+surface_exponential_blur (cairo_surface_t* surface,
+ guint radius);
+
+#endif // _EXPONENTIAL_BLUR_H
+
diff --git a/tdegtk/gtkroundedbox.c b/tdegtk/gtkroundedbox.c
new file mode 100644
index 0000000..7c5740f
--- /dev/null
+++ b/tdegtk/gtkroundedbox.c
@@ -0,0 +1,421 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2011 Benjamin Otte <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <cairo.h>
+
+#include "gtkroundedboxprivate.h"
+
+/**
+ * _gtk_rounded_box_init_rect:
+ * @box: box to initialize
+ * @x: x coordinate of box
+ * @y: y coordinate of box
+ * @width: width of box
+ * @height: height of box
+ *
+ * Initializes the given @box to represent the given rectangle.
+ **/
+void
+_gtk_rounded_box_init_rect (GtkRoundedBox *box,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ box->box.x = x;
+ box->box.y = y;
+ box->box.width = width;
+ box->box.height = height;
+ memset (&box->border_radius, 0, sizeof (GtkCssBorderRadius));
+}
+
+/* clamp border radius, following CSS specs */
+static void
+gtk_rounded_box_clamp_border_radius (GtkRoundedBox *box)
+{
+ gdouble factor = 1.0;
+
+ /* left */
+ if (box->border_radius.top_left.vertical + box->border_radius.bottom_left.vertical > 0 &&
+ box->border_radius.top_left.vertical + box->border_radius.bottom_left.vertical > box->box.height)
+ factor = MIN (factor, box->box.height / (box->border_radius.top_left.vertical +
+ box->border_radius.bottom_left.vertical));
+
+ /* top */
+ if (box->border_radius.top_left.horizontal + box->border_radius.top_right.horizontal > 0 &&
+ box->border_radius.top_left.horizontal + box->border_radius.top_right.horizontal > box->box.width)
+ factor = MIN (factor, box->box.width / (box->border_radius.top_left.horizontal +
+ box->border_radius.top_right.horizontal));
+
+ /* right */
+ if (box->border_radius.top_right.vertical + box->border_radius.bottom_right.horizontal > 0 &&
+ box->border_radius.top_right.vertical + box->border_radius.bottom_right.horizontal > box->box.height)
+ factor = MIN (factor, box->box.height / (box->border_radius.top_right.vertical +
+ box->border_radius.bottom_right.horizontal));
+
+ /* bottom */
+ if (box->border_radius.bottom_right.horizontal + box->border_radius.bottom_left.horizontal > 0 &&
+ box->border_radius.bottom_right.horizontal + box->border_radius.bottom_left.horizontal > box->box.width)
+ factor = MIN (factor, box->box.width / (box->border_radius.bottom_right.horizontal +
+ box->border_radius.bottom_left.horizontal));
+
+ /* scale border radius */
+ box->border_radius.top_left.horizontal *= factor;
+ box->border_radius.top_left.vertical *= factor;
+ box->border_radius.top_right.horizontal *= factor;
+ box->border_radius.top_right.vertical *= factor;
+ box->border_radius.bottom_right.horizontal *= factor;
+ box->border_radius.bottom_right.vertical *= factor;
+ box->border_radius.bottom_left.horizontal *= factor;
+ box->border_radius.bottom_left.vertical *= factor;
+}
+
+void
+_gtk_rounded_box_apply_border_radius (GtkRoundedBox *box,
+ GtkThemingEngine *engine,
+ GtkStateFlags state,
+ GtkJunctionSides junction)
+{
+ GtkCssBorderCornerRadius *top_left_radius, *top_right_radius;
+ GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius;
+
+ gtk_theming_engine_get (engine, state,
+ /* Can't use border-radius as it's an int for
+ * backwards compat */
+ "border-top-left-radius", &top_left_radius,
+ "border-top-right-radius", &top_right_radius,
+ "border-bottom-right-radius", &bottom_right_radius,
+ "border-bottom-left-radius", &bottom_left_radius,
+ NULL);
+
+ if (top_left_radius && (junction & GTK_JUNCTION_CORNER_TOPLEFT) == 0)
+ box->border_radius.top_left = *top_left_radius;
+ if (top_right_radius && (junction & GTK_JUNCTION_CORNER_TOPRIGHT) == 0)
+ box->border_radius.top_right = *top_right_radius;
+ if (bottom_right_radius && (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT) == 0)
+ box->border_radius.bottom_right = *bottom_right_radius;
+ if (bottom_left_radius && (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT) == 0)
+ box->border_radius.bottom_left = *bottom_left_radius;
+
+ gtk_rounded_box_clamp_border_radius (box);
+
+ g_free (top_left_radius);
+ g_free (top_right_radius);
+ g_free (bottom_right_radius);
+ g_free (bottom_left_radius);
+}
+
+static void
+gtk_css_border_radius_grow (GtkCssBorderCornerRadius *corner,
+ gdouble horizontal,
+ gdouble vertical)
+{
+ corner->horizontal += horizontal;
+ corner->vertical += vertical;
+
+ if (corner->horizontal <= 0 || corner->vertical <= 0)
+ {
+ corner->horizontal = 0;
+ corner->vertical = 0;
+ }
+}
+
+void
+_gtk_rounded_box_grow (GtkRoundedBox *box,
+ gdouble top,
+ gdouble right,
+ gdouble bottom,
+ gdouble left)
+{
+ if (box->box.width + left + right < 0)
+ {
+ box->box.x -= left * box->box.width / (left + right);
+ box->box.width = 0;
+ }
+ else
+ {
+ box->box.x -= left;
+ box->box.width += left + right;
+ }
+
+ if (box->box.height + bottom + right < 0)
+ {
+ box->box.y -= top * box->box.height / (top + bottom);
+ box->box.height = 0;
+ }
+ else
+ {
+ box->box.y -= top;
+ box->box.height += top + bottom;
+ }
+
+ gtk_css_border_radius_grow (&box->border_radius.top_left, left, top);
+ gtk_css_border_radius_grow (&box->border_radius.top_right, right, bottom);
+ gtk_css_border_radius_grow (&box->border_radius.bottom_right, right, top);
+ gtk_css_border_radius_grow (&box->border_radius.bottom_left, left, bottom);
+}
+
+void
+_gtk_rounded_box_shrink (GtkRoundedBox *box,
+ gdouble top,
+ gdouble right,
+ gdouble bottom,
+ gdouble left)
+{
+ _gtk_rounded_box_grow (box, -top, -right, -bottom, -left);
+}
+
+void
+_gtk_rounded_box_move (GtkRoundedBox *box,
+ gdouble dx,
+ gdouble dy)
+{
+ box->box.x += dx;
+ box->box.y += dy;
+}
+
+static void
+_cairo_ellipsis (cairo_t *cr,
+ gdouble xc,
+ gdouble yc,
+ gdouble xradius,
+ gdouble yradius,
+ gdouble angle1,
+ gdouble angle2)
+{
+ if (xradius <= 0.0 || yradius <= 0.0)
+ {
+ cairo_line_to (cr, xc, yc);
+ return;
+ }
+
+ cairo_save (cr);
+ cairo_translate (cr, xc, yc);
+ cairo_scale (cr, xradius, yradius);
+ cairo_arc (cr, 0, 0, 1.0, angle1, angle2);
+ cairo_restore (cr);
+}
+
+static void
+_cairo_ellipsis_negative (cairo_t *cr,
+ gdouble xc,
+ gdouble yc,
+ gdouble xradius,
+ gdouble yradius,
+ gdouble angle1,
+ gdouble angle2)
+{
+ if (xradius <= 0.0 || yradius <= 0.0)
+ {
+ cairo_line_to (cr, xc, yc);
+ return;
+ }
+
+ cairo_save (cr);
+ cairo_translate (cr, xc, yc);
+ cairo_scale (cr, xradius, yradius);
+ cairo_arc_negative (cr, 0, 0, 1.0, angle1, angle2);
+ cairo_restore (cr);
+}
+
+void
+_gtk_rounded_box_path (const GtkRoundedBox *box,
+ cairo_t *cr)
+{
+ cairo_new_sub_path (cr);
+
+ _cairo_ellipsis (cr,
+ box->box.x + box->border_radius.top_left.horizontal,
+ box->box.y + box->border_radius.top_left.vertical,
+ box->border_radius.top_left.horizontal,
+ box->border_radius.top_left.vertical,
+ G_PI, 3 * G_PI / 2);
+ _cairo_ellipsis (cr,
+ box->box.x + box->box.width - box->border_radius.top_right.horizontal,
+ box->box.y + box->border_radius.top_right.vertical,
+ box->border_radius.top_right.horizontal,
+ box->border_radius.top_right.vertical,
+ - G_PI / 2, 0);
+ _cairo_ellipsis (cr,
+ box->box.x + box->box.width - box->border_radius.bottom_right.horizontal,
+ box->box.y + box->box.height - box->border_radius.bottom_right.vertical,
+ box->border_radius.bottom_right.horizontal,
+ box->border_radius.bottom_right.vertical,
+ 0, G_PI / 2);
+ _cairo_ellipsis (cr,
+ box->box.x + box->border_radius.bottom_left.horizontal,
+ box->box.y + box->box.height - box->border_radius.bottom_left.vertical,
+ box->border_radius.bottom_left.horizontal,
+ box->border_radius.bottom_left.vertical,
+ G_PI / 2, G_PI);
+}
+
+void
+_gtk_rounded_box_path_top (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr)
+{
+ cairo_new_sub_path (cr);
+
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->border_radius.top_left.horizontal,
+ outer->box.y + outer->border_radius.top_left.vertical,
+ outer->border_radius.top_left.horizontal,
+ outer->border_radius.top_left.vertical,
+ 5 * G_PI / 4, 3 * G_PI / 2);
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->box.width - outer->border_radius.top_right.horizontal,
+ outer->box.y + outer->border_radius.top_right.vertical,
+ outer->border_radius.top_right.horizontal,
+ outer->border_radius.top_right.vertical,
+ - G_PI / 2, -G_PI / 4);
+
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->box.width - inner->border_radius.top_right.horizontal,
+ inner->box.y + inner->border_radius.top_right.vertical,
+ inner->border_radius.top_right.horizontal,
+ inner->border_radius.top_right.vertical,
+ -G_PI / 4, - G_PI / 2);
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->border_radius.top_left.horizontal,
+ inner->box.y + inner->border_radius.top_left.vertical,
+ inner->border_radius.top_left.horizontal,
+ inner->border_radius.top_left.vertical,
+ 3 * G_PI / 2, 5 * G_PI / 4);
+
+ cairo_close_path (cr);
+}
+
+void
+_gtk_rounded_box_path_right (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr)
+{
+ cairo_new_sub_path (cr);
+
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->box.width - outer->border_radius.top_right.horizontal,
+ outer->box.y + outer->border_radius.top_right.vertical,
+ outer->border_radius.top_right.horizontal,
+ outer->border_radius.top_right.vertical,
+ - G_PI / 4, 0);
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->box.width - outer->border_radius.bottom_right.horizontal,
+ outer->box.y + outer->box.height - outer->border_radius.bottom_right.vertical,
+ outer->border_radius.bottom_right.horizontal,
+ outer->border_radius.bottom_right.vertical,
+ 0, G_PI / 4);
+
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->box.width - inner->border_radius.bottom_right.horizontal,
+ inner->box.y + inner->box.height - inner->border_radius.bottom_right.vertical,
+ inner->border_radius.bottom_right.horizontal,
+ inner->border_radius.bottom_right.vertical,
+ G_PI / 4, 0);
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->box.width - inner->border_radius.top_right.horizontal,
+ inner->box.y + inner->border_radius.top_right.vertical,
+ inner->border_radius.top_right.horizontal,
+ inner->border_radius.top_right.vertical,
+ 0, - G_PI / 4);
+
+ cairo_close_path (cr);
+}
+
+void
+_gtk_rounded_box_path_bottom (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr)
+{
+ cairo_new_sub_path (cr);
+
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->box.width - outer->border_radius.bottom_right.horizontal,
+ outer->box.y + outer->box.height - outer->border_radius.bottom_right.vertical,
+ outer->border_radius.bottom_right.horizontal,
+ outer->border_radius.bottom_right.vertical,
+ G_PI / 4, G_PI / 2);
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->border_radius.bottom_left.horizontal,
+ outer->box.y + outer->box.height - outer->border_radius.bottom_left.vertical,
+ outer->border_radius.bottom_left.horizontal,
+ outer->border_radius.bottom_left.vertical,
+ G_PI / 2, 3 * G_PI / 4);
+
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->border_radius.bottom_left.horizontal,
+ inner->box.y + inner->box.height - inner->border_radius.bottom_left.vertical,
+ inner->border_radius.bottom_left.horizontal,
+ inner->border_radius.bottom_left.vertical,
+ 3 * G_PI / 4, G_PI / 2);
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->box.width - inner->border_radius.bottom_right.horizontal,
+ inner->box.y + inner->box.height - inner->border_radius.bottom_right.vertical,
+ inner->border_radius.bottom_right.horizontal,
+ inner->border_radius.bottom_right.vertical,
+ G_PI / 2, G_PI / 4);
+
+ cairo_close_path (cr);
+}
+
+void
+_gtk_rounded_box_path_left (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr)
+{
+ cairo_new_sub_path (cr);
+
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->border_radius.bottom_left.horizontal,
+ outer->box.y + outer->box.height - outer->border_radius.bottom_left.vertical,
+ outer->border_radius.bottom_left.horizontal,
+ outer->border_radius.bottom_left.vertical,
+ 3 * G_PI / 4, G_PI);
+ _cairo_ellipsis (cr,
+ outer->box.x + outer->border_radius.top_left.horizontal,
+ outer->box.y + outer->border_radius.top_left.vertical,
+ outer->border_radius.top_left.horizontal,
+ outer->border_radius.top_left.vertical,
+ G_PI, 5 * G_PI / 4);
+
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->border_radius.top_left.horizontal,
+ inner->box.y + inner->border_radius.top_left.vertical,
+ inner->border_radius.top_left.horizontal,
+ inner->border_radius.top_left.vertical,
+ 5 * G_PI / 4, G_PI);
+ _cairo_ellipsis_negative (cr,
+ inner->box.x + inner->border_radius.bottom_left.horizontal,
+ inner->box.y + inner->box.height - inner->border_radius.bottom_left.vertical,
+ inner->border_radius.bottom_left.horizontal,
+ inner->border_radius.bottom_left.vertical,
+ G_PI, 3 * G_PI / 4);
+
+ cairo_close_path (cr);
+}
+
+void
+_gtk_rounded_box_clip_path (const GtkRoundedBox *box,
+ cairo_t *cr)
+{
+ cairo_rectangle (cr,
+ box->box.x, box->box.y,
+ box->box.width, box->box.height);
+}
diff --git a/tdegtk/gtkroundedboxprivate.h b/tdegtk/gtkroundedboxprivate.h
new file mode 100644
index 0000000..be84832
--- /dev/null
+++ b/tdegtk/gtkroundedboxprivate.h
@@ -0,0 +1,88 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2011 Benjamin Otte <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_ROUNDED_BOX_PRIVATE_H__
+#define __GTK_ROUNDED_BOX_PRIVATE_H__
+
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+#include "tdegtk-types.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GtkRoundedBox GtkRoundedBox;
+
+struct _GtkRoundedBox {
+ cairo_rectangle_t box;
+ GtkCssBorderRadius border_radius;
+};
+
+void _gtk_rounded_box_init_rect (GtkRoundedBox *box,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height);
+
+void _gtk_rounded_box_apply_border_radius (GtkRoundedBox *box,
+ GtkThemingEngine *engine,
+ GtkStateFlags state,
+ GtkJunctionSides junction);
+
+void _gtk_rounded_box_grow (GtkRoundedBox *box,
+ gdouble top,
+ gdouble right,
+ gdouble bottom,
+ gdouble left);
+
+void _gtk_rounded_box_shrink (GtkRoundedBox *box,
+ gdouble top,
+ gdouble right,
+ gdouble bottom,
+ gdouble left);
+
+void _gtk_rounded_box_move (GtkRoundedBox *box,
+ gdouble dx,
+ gdouble dy);
+
+void _gtk_rounded_box_path (const GtkRoundedBox *box,
+ cairo_t *cr);
+
+void _gtk_rounded_box_path_top (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr);
+
+void _gtk_rounded_box_path_right (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr);
+
+void _gtk_rounded_box_path_bottom (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr);
+
+void _gtk_rounded_box_path_left (const GtkRoundedBox *outer,
+ const GtkRoundedBox *inner,
+ cairo_t *cr);
+
+void _gtk_rounded_box_clip_path (const GtkRoundedBox *box,
+ cairo_t *cr);
+
+G_END_DECLS
+
+#endif /* __GTK_ROUNDED_BOX_PRIVATE_H__ */
diff --git a/tdegtk/raico-blur.c b/tdegtk/raico-blur.c
new file mode 100644
index 0000000..3330ae2
--- /dev/null
+++ b/tdegtk/raico-blur.c
@@ -0,0 +1,173 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2009 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Mirco "MacSlow" Mueller <[email protected]>
+ *
+ */
+
+#include "exponential-blur.h"
+#include "raico-blur.h"
+
+struct _raico_blur_private_t
+{
+ raico_blur_quality_t quality; /* low, medium, high */
+ guint radius; /* blur-radius */
+};
+
+raico_blur_t*
+raico_blur_create (void)
+{
+ raico_blur_t* blur = NULL;
+ raico_blur_private_t* priv = NULL;
+
+ blur = g_new0 (raico_blur_t, 1);
+ if (!blur)
+ {
+ g_debug ("raico_blur_create(): could not allocate blur struct");
+ return NULL;
+ }
+
+ priv = g_new0 (raico_blur_private_t, 1);
+ if (!priv)
+ {
+ g_debug ("raico_blur_create(): could not allocate priv struct");
+ g_free ((gpointer) blur);
+ return NULL;
+ }
+
+ priv->quality = RAICO_BLUR_QUALITY_LOW;
+
+ priv->radius = 0;
+
+ blur->priv = priv;
+
+ return blur;
+}
+
+raico_blur_quality_t
+raico_blur_get_quality (raico_blur_t* blur)
+{
+ g_assert (blur != NULL);
+
+ return blur->priv->quality;
+}
+
+void
+raico_blur_set_quality (raico_blur_t* blur,
+ raico_blur_quality_t quality)
+{
+ if (!blur)
+ {
+ g_debug ("raico_blur_set_quality(): NULL blur-pointer passed");
+ return;
+ }
+
+ blur->priv->quality = quality;
+}
+
+guint
+raico_blur_get_radius (raico_blur_t* blur)
+{
+ g_assert (blur != NULL);
+
+ return blur->priv->radius;
+}
+
+void
+raico_blur_set_radius (raico_blur_t* blur,
+ guint radius)
+{
+ if (!blur)
+ {
+ g_debug ("raico_blur_set_radius(): NULL blur-pointer passed");
+ return;
+ }
+
+ blur->priv->radius = radius;
+}
+
+void
+raico_blur_apply (raico_blur_t* blur,
+ cairo_surface_t* surface)
+{
+ cairo_format_t format;
+
+ /* sanity checks */
+ if (!blur)
+ {
+ g_debug ("raico_blur_apply(): NULL blur-pointer passed");
+ return;
+ }
+
+ if (!surface)
+ {
+ g_debug ("raico_blur_apply(): NULL surface-pointer passed");
+ return;
+ }
+
+ if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
+ {
+ g_debug ("raico_blur_apply(): invalid surface status");
+ return;
+ }
+
+ if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE)
+ {
+ g_debug ("raico_blur_apply(): non-image surface passed");
+ return;
+ }
+
+ format = cairo_image_surface_get_format (surface);
+ if (format != CAIRO_FORMAT_A8 &&
+ format != CAIRO_FORMAT_RGB24 &&
+ format != CAIRO_FORMAT_ARGB32)
+ {
+ g_debug ("raico_blur_apply(): unsupported image-format");
+ return;
+ }
+
+ /* stupid, but you never know */
+ if (blur->priv->radius == 0)
+ return;
+
+ /* now do the real work */
+ switch (blur->priv->quality)
+ {
+ default:
+ case RAICO_BLUR_QUALITY_HIGH:
+ case RAICO_BLUR_QUALITY_MEDIUM:
+ /* Not implemented yet */
+ //surface_gaussian_blur (surface, blur->priv->radius);
+ case RAICO_BLUR_QUALITY_LOW:
+ surface_exponential_blur (surface, blur->priv->radius);
+ break;
+ }
+}
+
+void
+raico_blur_destroy (raico_blur_t* blur)
+{
+ if (!blur)
+ {
+ g_debug ("raico_blur_destroy(): invalid blur-pointer passed");
+ return;
+ }
+
+ g_free ((gpointer) blur->priv);
+ g_free ((gpointer) blur);
+}
diff --git a/tdegtk/raico-blur.h b/tdegtk/raico-blur.h
new file mode 100644
index 0000000..1d562b9
--- /dev/null
+++ b/tdegtk/raico-blur.h
@@ -0,0 +1,67 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2009 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Mirco "MacSlow" Mueller <[email protected]>
+ *
+ */
+
+#ifndef _RAICO_BLUR_H
+#define _RAICO_BLUR_H
+
+#include <cairo.h>
+#include <glib.h>
+
+typedef enum _raico_blur_quality_t
+{
+ RAICO_BLUR_QUALITY_LOW = 0, /* low quality, but fast, maybe interactive */
+ RAICO_BLUR_QUALITY_MEDIUM, /* compromise between speed and quality */
+ RAICO_BLUR_QUALITY_HIGH /* quality before speed */
+} raico_blur_quality_t;
+
+typedef struct _raico_blur_private_t raico_blur_private_t;
+
+typedef struct _raico_blur_t
+{
+ raico_blur_private_t* priv;
+} raico_blur_t;
+
+raico_blur_t*
+raico_blur_create (void);
+
+raico_blur_quality_t
+raico_blur_get_quality (raico_blur_t* blur);
+
+void
+raico_blur_set_quality (raico_blur_t* blur,
+ raico_blur_quality_t quality);
+
+guint
+raico_blur_get_radius (raico_blur_t* blur);
+
+void
+raico_blur_set_radius (raico_blur_t* blur,
+ guint radius);
+
+void
+raico_blur_apply (raico_blur_t* blur,
+ cairo_surface_t* surface);
+
+void
+raico_blur_destroy (raico_blur_t* blur);
+
+#endif /* _RAICO_BLUR_H */
diff --git a/tdegtk/tdegtk-cairo-support.c b/tdegtk/tdegtk-cairo-support.c
new file mode 100644
index 0000000..8b3a1d5
--- /dev/null
+++ b/tdegtk/tdegtk-cairo-support.c
@@ -0,0 +1,1418 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#include <cairo.h>
+#include <gtk/gtk.h>
+
+#include "gtkroundedboxprivate.h"
+#include "raico-blur.h"
+#include "tdegtk-cairo-support.h"
+#include "tdegtk-support.h"
+#include "tdegtk-types.h"
+
+/* apply default color */
+static void
+apply_default_color (GdkRGBA *colors[4],
+ GdkRGBA *default_color)
+{
+ gint i;
+
+ for (i = 0; i < 4; i++)
+ if (tdegtk_gdk_rgba_is_default (colors[i]))
+ *colors[i] = *default_color;
+}
+
+/* set the border sides to 0 using hidden_side */
+static void
+hide_border_sides (GtkBorder *border,
+ guint hidden_side)
+{
+ if (hidden_side & SIDE_TOP)
+ border->top = 0;
+ if (hidden_side & SIDE_RIGHT)
+ border->right = 0;
+ if (hidden_side & SIDE_BOTTOM)
+ border->bottom = 0;
+ if (hidden_side & SIDE_LEFT)
+ border->left = 0;
+}
+
+/* shrink coordinate using GtkBorder */
+static void
+shrink_with_border (GtkBorder *border,
+ gdouble *x,
+ gdouble *y,
+ gdouble *width,
+ gdouble *height)
+{
+ *x += border->left;
+ *y += border->top;
+ *width -= border->left + border->right;
+ *height -= border->top + border->bottom;
+}
+
+/* draw the background */
+static void
+draw_background (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GdkRGBA bg_color;
+ GtkBorder border;
+ GtkRoundedBox border_box;
+ GtkStateFlags state;
+ cairo_pattern_t *bg_pat;
+ gdouble progress;
+ gboolean running;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "background-image", &bg_pat,
+ NULL);
+ gtk_theming_engine_get_background_color (engine, state, &bg_color);
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ hide_border_sides (&border, hidden_side);
+
+ running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress);
+
+ cairo_save (cr);
+
+ cairo_translate (cr, x, y);
+
+ /* clear cr if we can draw directly on the background */
+ if (gtk_theming_engine_has_class (engine, "background"))
+ {
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ }
+
+ if (running)
+ {
+ GdkRGBA other_bg;
+ GtkStateFlags other_state;
+ cairo_pattern_t *new_pat = NULL;
+ cairo_pattern_t *other_pat;
+
+ if (state & GTK_STATE_FLAG_PRELIGHT)
+ {
+ other_state = state & ~(GTK_STATE_FLAG_PRELIGHT);
+
+ /* useful math function to use for a pulse loop animation could be
+ * progress = 1 - MAX (1 - fabs ((progress - 0.5)*2), 0);
+ * but we need to handle the not-running case (once animation finished),
+ * otherwise the last frame will be the PRELIGHT at full opacity. */
+ progress = 1 - progress;
+ }
+ else
+ other_state = state | GTK_STATE_FLAG_PRELIGHT;
+
+ gtk_theming_engine_get (engine, other_state,
+ "background-image", &other_pat,
+ NULL);
+ gtk_theming_engine_get_background_color (engine, other_state, &other_bg);
+
+ if (bg_pat && other_pat)
+ {
+ /* two patterns */
+ cairo_pattern_type_t type, other_type;
+ gint n0, n1;
+
+ cairo_pattern_get_color_stop_count (bg_pat, &n0);
+ cairo_pattern_get_color_stop_count (other_pat, &n1);
+ type = cairo_pattern_get_type (bg_pat);
+ other_type = cairo_pattern_get_type (other_pat);
+
+ if (type == other_type && n0 == n1)
+ {
+ /* two similar patterns, blend them point by point */
+ gdouble offset0, red0, green0, blue0, alpha0;
+ gdouble offset1, red1, green1, blue1, alpha1;
+ gdouble x00, x01, y00, y01, x10, x11, y10, y11;
+ gdouble r00, r01, r10, r11;
+ gint i;
+
+ if (type == CAIRO_PATTERN_TYPE_LINEAR)
+ {
+ cairo_pattern_get_linear_points (bg_pat, &x00, &y00, &x01, &y01);
+ cairo_pattern_get_linear_points (other_pat, &x10, &y10, &x11, &y11);
+
+ new_pat = cairo_pattern_create_linear (x00 + (x10 - x00) * progress,
+ y00 + (y10 - y00) * progress,
+ x01 + (x11 - x01) * progress,
+ y01 + (y11 - y01) * progress);
+ }
+ else
+ {
+ cairo_pattern_get_radial_circles (bg_pat, &x00, &y00, &r00, &x01, &y01, &r01);
+ cairo_pattern_get_radial_circles (other_pat, &x10, &y10, &r10, &x11, &y11, &r11);
+
+ new_pat = cairo_pattern_create_radial (x00 + (x10 - x00) * progress,
+ y00 + (y10 - y00) * progress,
+ r00 + (r10 - r00) * progress,
+ x01 + (x11 - x01) * progress,
+ y01 + (y11 - y01) * progress,
+ r01 + (r11 - r01) * progress);
+ }
+
+ cairo_pattern_set_filter (new_pat, CAIRO_FILTER_FAST);
+ i = 0;
+
+ while (i < n0 && i < n1)
+ {
+ cairo_pattern_get_color_stop_rgba (bg_pat, i,
+ &offset0,
+ &red0, &green0, &blue0,
+ &alpha0);
+ cairo_pattern_get_color_stop_rgba (other_pat, i,
+ &offset1,
+ &red1, &green1, &blue1,
+ &alpha1);
+ cairo_pattern_add_color_stop_rgba (new_pat,
+ offset0 + ((offset1 - offset0) * progress),
+ red0 + ((red1 - red0) * progress),
+ green0 + ((green1 - green0) * progress),
+ blue0 + ((blue1 - blue0) * progress),
+ alpha0 + ((alpha1 - alpha0) * progress));
+ i++;
+ }
+ }
+ else
+ {
+ /* two different patterns, paint them with alpha */
+ cairo_save (cr);
+
+ cairo_reset_clip (cr);
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_clip (cr);
+
+ cairo_push_group (cr);
+
+ cairo_scale (cr, width, height);
+
+ cairo_set_source (cr, other_pat);
+ cairo_paint_with_alpha (cr, progress);
+
+ cairo_set_source (cr, bg_pat);
+ cairo_paint_with_alpha (cr, 1.0 - progress);
+
+ new_pat = cairo_pop_group (cr);
+
+ cairo_restore (cr);
+ }
+ }
+ else if (bg_pat || other_pat)
+ {
+ /* only one pattern, blend it with a color */
+ const GdkRGBA *c;
+ cairo_pattern_t *p;
+ gdouble x0, y0, x1, y1, r0, r1;
+ gint n, i;
+
+ if (bg_pat)
+ {
+ p = bg_pat;
+ c = &other_bg;
+ progress = 1 - progress;
+ }
+ else
+ {
+ p = other_pat;
+ c = &bg_color;
+ }
+
+ if (cairo_pattern_get_type (p) == CAIRO_PATTERN_TYPE_LINEAR)
+ {
+ cairo_pattern_get_linear_points (p, &x0, &y0, &x1, &y1);
+ new_pat = cairo_pattern_create_linear (x0, y0, x1, y1);
+ }
+ else
+ {
+ cairo_pattern_get_radial_circles (p, &x0, &y0, &r0, &x1, &y1, &r1);
+ new_pat = cairo_pattern_create_radial (x0, y0, r0, x1, y1, r1);
+ }
+
+ cairo_pattern_get_color_stop_count (p, &n);
+
+ for (i = 0; i < n; i++)
+ {
+ gdouble red1, green1, blue1, alpha1;
+ gdouble offset;
+
+ cairo_pattern_get_color_stop_rgba (p, i,
+ &offset,
+ &red1, &green1, &blue1,
+ &alpha1);
+ cairo_pattern_add_color_stop_rgba (new_pat, offset,
+ c->red + ((red1 - c->red) * progress),
+ c->green + ((green1 - c->green) * progress),
+ c->blue + ((blue1 - c->blue) * progress),
+ c->alpha + ((alpha1 - c->alpha) * progress));
+ }
+ }
+ else
+ {
+ /* just colors, create a new pattern blending them */
+ new_pat = cairo_pattern_create_rgba (CLAMP (bg_color.red + ((other_bg.red - bg_color.red) * progress), 0, 1),
+ CLAMP (bg_color.green + ((other_bg.green - bg_color.green) * progress), 0, 1),
+ CLAMP (bg_color.blue + ((other_bg.blue - bg_color.blue) * progress), 0, 1),
+ CLAMP (bg_color.alpha + ((other_bg.alpha - bg_color.alpha) * progress), 0, 1));
+ }
+
+ if (new_pat)
+ {
+ /* replace pattern to use */
+ cairo_pattern_destroy (bg_pat);
+ bg_pat = new_pat;
+ }
+
+ if (other_pat)
+ cairo_pattern_destroy (other_pat);
+ }
+
+ /* create the path to fill */
+ _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
+ _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
+ _gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
+ _gtk_rounded_box_path (&border_box, cr);
+
+ if (bg_pat)
+ {
+ /* pattern */
+ cairo_scale (cr, width, height);
+ cairo_set_source (cr, bg_pat);
+ cairo_scale (cr, 1.0 / width, 1.0 / height);
+ }
+ else
+ /* one color */
+ gdk_cairo_set_source_rgba (cr, &bg_color);
+
+ cairo_fill (cr);
+
+ if (bg_pat)
+ cairo_pattern_destroy (bg_pat);
+
+ cairo_restore (cr);
+}
+
+/* draw the inner glow */
+static void
+draw_glow (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GdkRGBA *glow_color;
+ GtkBorder border;
+ GtkRoundedBox border_box, padding_box;
+ GtkStateFlags state;
+ cairo_t *cr_surface;
+ cairo_surface_t *surface;
+ gint bradius = 0;
+ raico_blur_t* blur = NULL;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-glow-radius", &bradius,
+ "-tdegtk-glow-color", &glow_color,
+ NULL);
+
+ if (bradius <= 0)
+ goto end_draw_glow;
+
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ hide_border_sides (&border, hidden_side);
+
+ cairo_save (cr);
+
+ cairo_translate (cr, x, y);
+
+ /* create the path to clip */
+ _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
+ _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
+ _gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
+ _gtk_rounded_box_path (&border_box, cr);
+
+ cairo_clip (cr);
+
+ /* create the surface to blur */
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ width + bradius * 2,
+ height + bradius * 2);
+ cr_surface = cairo_create (surface);
+
+ /* create the path on the surface to blur */
+ _gtk_rounded_box_move (&border_box, bradius, bradius);
+ padding_box = border_box;
+ _gtk_rounded_box_shrink (&padding_box, border.top * 2, border.right * 2, border.bottom * 2, border.left * 2);
+
+ cairo_set_fill_rule (cr_surface, CAIRO_FILL_RULE_EVEN_ODD);
+
+ gdk_cairo_set_source_rgba (cr_surface, glow_color);
+
+ _gtk_rounded_box_path (&border_box, cr_surface);
+ _gtk_rounded_box_path (&padding_box, cr_surface);
+ cairo_fill (cr_surface);
+
+ /* create and apply raico blur */
+ blur = raico_blur_create ();
+ raico_blur_set_radius (blur, bradius);
+ raico_blur_apply (blur, surface);
+
+ /* paint the blurred surface to cr */
+ cairo_set_source_surface (cr, surface, - bradius, - bradius);
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+
+ cairo_surface_destroy (surface);
+ cairo_destroy (cr_surface);
+
+end_draw_glow:
+ gdk_rgba_free (glow_color);
+}
+
+/* draw a repeated texture */
+static void
+draw_texture (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GtkStateFlags state;
+ GValue value = { 0, };
+ cairo_pattern_t *texture = NULL;
+ cairo_surface_t *surface = NULL;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get_property (engine, "-tdegtk-background-texture", state, &value);
+
+ if (!G_VALUE_HOLDS_BOXED (&value))
+ return;
+
+ texture = g_value_dup_boxed (&value);
+ g_value_unset (&value);
+
+ if (texture != NULL)
+ cairo_pattern_get_surface (texture, &surface);
+
+ if (surface != NULL)
+ {
+ GtkBorder border;
+ GtkRoundedBox border_box;
+ cairo_pattern_t *pat;
+
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ hide_border_sides (&border, hidden_side);
+
+ cairo_save (cr);
+
+ cairo_translate (cr, x, y);
+
+ /* create the path to fill */
+ _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
+ _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
+ _gtk_rounded_box_shrink (&border_box, border.top, border.right, border.bottom, border.left);
+ _gtk_rounded_box_path (&border_box, cr);
+
+ pat = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT);
+ cairo_set_source (cr, pat);
+
+ cairo_fill (cr);
+
+ cairo_restore (cr);
+
+ cairo_pattern_destroy (pat);
+ }
+
+ if (texture != NULL)
+ cairo_pattern_destroy (texture);
+}
+
+void
+tdegtk_cairo_draw_background (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GtkBorder *outer_border;
+ GtkStateFlags state;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-outer-stroke-width", &outer_border,
+ NULL);
+
+ hide_border_sides (outer_border, hidden_side);
+
+ shrink_with_border (outer_border, &x, &y, &width, &height);
+
+ /* first layer, background */
+ draw_background (engine, cr,
+ x, y,
+ width, height,
+ hidden_side, junction);
+
+ /* second layer, glow */
+ draw_glow (engine, cr,
+ x, y,
+ width, height,
+ hidden_side, junction);
+
+ /* third layer, texture */
+ draw_texture (engine, cr,
+ x, y,
+ width, height,
+ hidden_side, junction);
+
+ gtk_border_free (outer_border);
+}
+
+/* shade a color */
+static void
+color_shade (const GdkRGBA *color,
+ gdouble factor,
+ GdkRGBA *color_return)
+{
+ GtkSymbolicColor *literal, *shade;
+
+ literal = gtk_symbolic_color_new_literal (color);
+ shade = gtk_symbolic_color_new_shade (literal, factor);
+ gtk_symbolic_color_unref (literal);
+
+ gtk_symbolic_color_resolve (shade, NULL, color_return);
+ gtk_symbolic_color_unref (shade);
+}
+
+/* draw the border */
+static void
+draw_border (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GdkRGBA *colors[4];
+ GtkBorder border;
+ GtkBorderStyle border_style;
+ GtkRoundedBox border_box, padding_box;
+ GtkStateFlags state;
+ cairo_pattern_t *border_pat;
+ gboolean running;
+ gdouble progress;
+ static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
+ guint i, j;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "border-style", &border_style,
+ "border-top-color", &colors[0],
+ "border-right-color", &colors[1],
+ "border-bottom-color", &colors[2],
+ "border-left-color", &colors[3],
+ "-tdegtk-border-gradient", &border_pat,
+ NULL);
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ hide_border_sides (&border, hidden_side);
+
+ running = gtk_theming_engine_state_is_running (engine, GTK_STATE_PRELIGHT, &progress);
+
+ cairo_save (cr);
+
+ cairo_translate (cr, x, y);
+
+ if (running)
+ {
+ GtkStateFlags other_state;
+ cairo_pattern_t *new_pat = NULL;
+ cairo_pattern_t *other_pat;
+
+ if (state & GTK_STATE_FLAG_PRELIGHT)
+ {
+ other_state = state & ~(GTK_STATE_FLAG_PRELIGHT);
+ progress = 1 - progress;
+ }
+ else
+ other_state = state | GTK_STATE_FLAG_PRELIGHT;
+
+ gtk_theming_engine_get (engine, other_state,
+ "-tdegtk-border-gradient", &other_pat,
+ NULL);
+
+ if (border_pat && other_pat)
+ {
+ /* two patterns */
+ cairo_pattern_type_t type, other_type;
+ gint n0, n1;
+
+ cairo_pattern_get_color_stop_count (border_pat, &n0);
+ cairo_pattern_get_color_stop_count (other_pat, &n1);
+ type = cairo_pattern_get_type (border_pat);
+ other_type = cairo_pattern_get_type (other_pat);
+
+ if (type == other_type && n0 == n1)
+ {
+ /* two similar patterns, blend them point by point */
+ gdouble offset0, red0, green0, blue0, alpha0;
+ gdouble offset1, red1, green1, blue1, alpha1;
+ gdouble x00, x01, y00, y01, x10, x11, y10, y11;
+ gdouble r00, r01, r10, r11;
+ gint i;
+
+ if (type == CAIRO_PATTERN_TYPE_LINEAR)
+ {
+ cairo_pattern_get_linear_points (border_pat, &x00, &y00, &x01, &y01);
+ cairo_pattern_get_linear_points (other_pat, &x10, &y10, &x11, &y11);
+
+ new_pat = cairo_pattern_create_linear (x00 + (x10 - x00) * progress,
+ y00 + (y10 - y00) * progress,
+ x01 + (x11 - x01) * progress,
+ y01 + (y11 - y01) * progress);
+ }
+ else
+ {
+ cairo_pattern_get_radial_circles (border_pat, &x00, &y00, &r00, &x01, &y01, &r01);
+ cairo_pattern_get_radial_circles (other_pat, &x10, &y10, &r10, &x11, &y11, &r11);
+
+ new_pat = cairo_pattern_create_radial (x00 + (x10 - x00) * progress,
+ y00 + (y10 - y00) * progress,
+ r00 + (r10 - r00) * progress,
+ x01 + (x11 - x01) * progress,
+ y01 + (y11 - y01) * progress,
+ r01 + (r11 - r01) * progress);
+ }
+
+ cairo_pattern_set_filter (new_pat, CAIRO_FILTER_FAST);
+ i = 0;
+
+ while (i < n0 && i < n1)
+ {
+ cairo_pattern_get_color_stop_rgba (border_pat, i,
+ &offset0,
+ &red0, &green0, &blue0,
+ &alpha0);
+ cairo_pattern_get_color_stop_rgba (other_pat, i,
+ &offset1,
+ &red1, &green1, &blue1,
+ &alpha1);
+ cairo_pattern_add_color_stop_rgba (new_pat,
+ offset0 + ((offset1 - offset0) * progress),
+ red0 + ((red1 - red0) * progress),
+ green0 + ((green1 - green0) * progress),
+ blue0 + ((blue1 - blue0) * progress),
+ alpha0 + ((alpha1 - alpha0) * progress));
+ i++;
+ }
+ }
+ else
+ {
+ /* two different patterns, paint them with alpha */
+ cairo_save (cr);
+
+ cairo_reset_clip (cr);
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_clip (cr);
+
+ cairo_push_group (cr);
+
+ cairo_scale (cr, width, height);
+
+ cairo_set_source (cr, other_pat);
+ cairo_paint_with_alpha (cr, progress);
+
+ cairo_set_source (cr, border_pat);
+ cairo_paint_with_alpha (cr, 1.0 - progress);
+
+ new_pat = cairo_pop_group (cr);
+
+ cairo_restore (cr);
+ }
+ }
+ else if (border_pat || other_pat)
+ {
+ /* one pattern, blend it with a color */
+ const GdkRGBA *c;
+ cairo_pattern_t *p;
+ gdouble x0, y0, x1, y1, r0, r1;
+ gint n, i;
+
+ if (border_pat)
+ {
+ GdkRGBA other_color;
+
+ gtk_theming_engine_get_border_color (engine, other_state, &other_color);
+
+ p = border_pat;
+ c = &other_color;
+ progress = 1 - progress;
+ }
+ else
+ {
+ GdkRGBA border_color;
+
+ gtk_theming_engine_get_border_color (engine, state, &border_color);
+
+ p = other_pat;
+ c = &border_color;
+ }
+
+ if (cairo_pattern_get_type (p) == CAIRO_PATTERN_TYPE_LINEAR)
+ {
+ cairo_pattern_get_linear_points (p, &x0, &y0, &x1, &y1);
+ new_pat = cairo_pattern_create_linear (x0, y0, x1, y1);
+ }
+ else
+ {
+ cairo_pattern_get_radial_circles (p, &x0, &y0, &r0, &x1, &y1, &r1);
+ new_pat = cairo_pattern_create_radial (x0, y0, r0, x1, y1, r1);
+ }
+
+ cairo_pattern_get_color_stop_count (p, &n);
+
+ for (i = 0; i < n; i++)
+ {
+ gdouble red1, green1, blue1, alpha1;
+ gdouble offset;
+
+ cairo_pattern_get_color_stop_rgba (p, i,
+ &offset,
+ &red1, &green1, &blue1,
+ &alpha1);
+ cairo_pattern_add_color_stop_rgba (new_pat, offset,
+ c->red + ((red1 - c->red) * progress),
+ c->green + ((green1 - c->green) * progress),
+ c->blue + ((blue1 - c->blue) * progress),
+ c->alpha + ((alpha1 - c->alpha) * progress));
+ }
+ }
+ else
+ {
+ /* just colors, create new colors blending them */
+ GdkRGBA *other_colors[4];
+
+ gtk_theming_engine_get (engine, other_state,
+ "border-top-color", &other_colors[0],
+ "border-right-color", &other_colors[1],
+ "border-bottom-color", &other_colors[2],
+ "border-left-color", &other_colors[3],
+ NULL);
+
+ for (i = 0; i < 4; i++)
+ {
+ colors[i]->red = CLAMP (colors[i]->red + ((other_colors[i]->red - colors[i]->red) * progress), 0, 1);
+ colors[i]->green = CLAMP (colors[i]->green + ((other_colors[i]->green - colors[i]->green) * progress), 0, 1);
+ colors[i]->blue = CLAMP (colors[i]->blue + ((other_colors[i]->blue - colors[i]->blue) * progress), 0, 1);
+ colors[i]->alpha = CLAMP (colors[i]->alpha + ((other_colors[i]->alpha - colors[i]->alpha) * progress), 0, 1);
+ gdk_rgba_free (other_colors[i]);
+ }
+ }
+
+ if (new_pat)
+ {
+ /* replace pattern to use */
+ cairo_pattern_destroy (border_pat);
+ border_pat = new_pat;
+ }
+
+ if (other_pat)
+ cairo_pattern_destroy (other_pat);
+ }
+
+ switch (border_style)
+ {
+ default:
+ g_assert_not_reached ();
+ case GTK_BORDER_STYLE_NONE:
+ case GTK_BORDER_STYLE_SOLID:
+ break;
+ case GTK_BORDER_STYLE_INSET:
+ color_shade (colors[1], 1.8, colors[1]);
+ color_shade (colors[2], 1.8, colors[2]);
+ break;
+ case GTK_BORDER_STYLE_OUTSET:
+ color_shade (colors[0], 1.8, colors[0]);
+ color_shade (colors[3], 1.8, colors[3]);
+ break;
+ }
+
+ /* create the path to fill */
+ _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
+ _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
+ padding_box = border_box;
+ _gtk_rounded_box_shrink (&padding_box, border.top, border.right, border.bottom, border.left);
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+
+ switch (border_style)
+ {
+ default:
+ g_assert_not_reached ();
+ case GTK_BORDER_STYLE_NONE:
+ break;
+ case GTK_BORDER_STYLE_SOLID:
+ case GTK_BORDER_STYLE_INSET:
+ case GTK_BORDER_STYLE_OUTSET:
+
+ if (border_pat)
+ {
+ /* pattern */
+ cairo_scale (cr, width, height);
+ cairo_set_source (cr, border_pat);
+ cairo_scale (cr, 1.0 / width, 1.0 / height);
+
+ _gtk_rounded_box_path (&border_box, cr);
+ _gtk_rounded_box_path (&padding_box, cr);
+ cairo_fill (cr);
+ }
+ else if (gdk_rgba_equal (colors[0], colors[1]) &&
+ gdk_rgba_equal (colors[0], colors[2]) &&
+ gdk_rgba_equal (colors[0], colors[3]))
+ {
+ /* one color */
+ gdk_cairo_set_source_rgba (cr, colors[0]);
+
+ _gtk_rounded_box_path (&border_box, cr);
+ _gtk_rounded_box_path (&padding_box, cr);
+ cairo_fill (cr);
+ }
+ else
+ {
+ for (i = 0; i < 4; i++)
+ {
+ /* different colors */
+ if (hidden_side & current_side[i])
+ continue;
+
+ for (j = 0; j < 4; j++)
+ {
+ if (hidden_side & current_side[j])
+ continue;
+
+ if (i == j ||
+ gdk_rgba_equal (colors[i], colors[j]))
+ {
+ /* we were already painted when i == j */
+ if (i > j)
+ break;
+
+ if (j == 0)
+ _gtk_rounded_box_path_top (&border_box, &padding_box, cr);
+ else if (j == 1)
+ _gtk_rounded_box_path_right (&border_box, &padding_box, cr);
+ else if (j == 2)
+ _gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
+ else if (j == 3)
+ _gtk_rounded_box_path_left (&border_box, &padding_box, cr);
+ }
+ }
+ /* we were already painted when i == j */
+ if (i > j)
+ continue;
+
+ gdk_cairo_set_source_rgba (cr, colors[i]);
+
+ cairo_fill (cr);
+ }
+ }
+ break;
+ }
+
+ cairo_restore (cr);
+
+ if (border_pat)
+ cairo_pattern_destroy (border_pat);
+
+ for (i = 0; i < 4; i++)
+ gdk_rgba_free (colors[i]);
+}
+
+/* draw the inner stroke */
+static void
+draw_inner_stroke (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GdkRGBA *colors[4];
+ GdkRGBA *inner_stroke_color;
+ GtkBorder *inner_border;
+ GtkRoundedBox border_box, padding_box;
+ GtkStateFlags state;
+ cairo_pattern_t *inner_stroke_pat;
+ static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
+ guint i, j;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-inner-stroke-color", &inner_stroke_color,
+ "-tdegtk-inner-stroke-top-color", &colors[0],
+ "-tdegtk-inner-stroke-right-color", &colors[1],
+ "-tdegtk-inner-stroke-bottom-color", &colors[2],
+ "-tdegtk-inner-stroke-left-color", &colors[3],
+ "-tdegtk-inner-stroke-gradient", &inner_stroke_pat,
+ "-tdegtk-inner-stroke-width", &inner_border,
+ NULL);
+
+ hide_border_sides (inner_border, hidden_side);
+
+ if (tdegtk_gtk_border_is_zero (inner_border))
+ goto end_draw_inner_stroke;
+
+ apply_default_color (colors, inner_stroke_color);
+
+ cairo_save (cr);
+
+ cairo_translate (cr, x, y);
+
+ /* create the path to fill */
+ _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
+ _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
+ padding_box = border_box;
+ _gtk_rounded_box_shrink (&padding_box, inner_border->top,
+ inner_border->right,
+ inner_border->bottom,
+ inner_border->left);
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+
+ if (inner_stroke_pat)
+ {
+ /* pattern */
+ cairo_scale (cr, width, height);
+ cairo_set_source (cr, inner_stroke_pat);
+ cairo_scale (cr, 1.0 / width, 1.0 / height);
+
+ _gtk_rounded_box_path (&border_box, cr);
+ _gtk_rounded_box_path (&padding_box, cr);
+ cairo_fill (cr);
+ }
+ else if (gdk_rgba_equal (colors[0], colors[1]) &&
+ gdk_rgba_equal (colors[0], colors[2]) &&
+ gdk_rgba_equal (colors[0], colors[3]))
+ {
+ /* one color */
+ gdk_cairo_set_source_rgba (cr, colors[0]);
+
+ _gtk_rounded_box_path (&border_box, cr);
+ _gtk_rounded_box_path (&padding_box, cr);
+ cairo_fill (cr);
+ }
+ else
+ {
+ /* different colors */
+ for (i = 0; i < 4; i++)
+ {
+ if (hidden_side & current_side[i])
+ continue;
+
+ for (j = 0; j < 4; j++)
+ {
+ if (hidden_side & current_side[j])
+ continue;
+
+ if (i == j ||
+ gdk_rgba_equal (colors[i], colors[j]))
+ {
+ /* we were already painted when i == j */
+ if (i > j)
+ break;
+
+ if (j == 0)
+ _gtk_rounded_box_path_top (&border_box, &padding_box, cr);
+ else if (j == 1)
+ _gtk_rounded_box_path_right (&border_box, &padding_box, cr);
+ else if (j == 2)
+ _gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
+ else if (j == 3)
+ _gtk_rounded_box_path_left (&border_box, &padding_box, cr);
+ }
+ }
+ /* we were already painted when i == j */
+ if (i > j)
+ continue;
+
+ gdk_cairo_set_source_rgba (cr, colors[i]);
+
+ cairo_fill (cr);
+ }
+ }
+
+ cairo_restore (cr);
+
+end_draw_inner_stroke:
+ gtk_border_free (inner_border);
+
+ if (inner_stroke_pat != NULL)
+ cairo_pattern_destroy (inner_stroke_pat);
+
+ gdk_rgba_free (inner_stroke_color);
+
+ for (i = 0; i < 4; i++)
+ gdk_rgba_free (colors[i]);
+}
+
+/* draw the outer stroke */
+static void
+draw_outer_stroke (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GdkRGBA *outer_stroke_color;
+ GdkRGBA *colors[4];
+ GtkBorder *outer_border;
+ GtkRoundedBox border_box, padding_box;
+ GtkStateFlags state;
+ cairo_pattern_t *outer_stroke_pat;
+ static const guint current_side[4] = { SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM, SIDE_LEFT };
+ guint i, j;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-outer-stroke-color", &outer_stroke_color,
+ "-tdegtk-outer-stroke-top-color", &colors[0],
+ "-tdegtk-outer-stroke-right-color", &colors[1],
+ "-tdegtk-outer-stroke-bottom-color", &colors[2],
+ "-tdegtk-outer-stroke-left-color", &colors[3],
+ "-tdegtk-outer-stroke-gradient", &outer_stroke_pat,
+ "-tdegtk-outer-stroke-width", &outer_border,
+ NULL);
+
+ hide_border_sides (outer_border, hidden_side);
+
+ if (tdegtk_gtk_border_is_zero (outer_border))
+ goto end_draw_outer_stroke;
+
+ apply_default_color (colors, outer_stroke_color);
+
+ cairo_save (cr);
+
+ cairo_translate (cr, x, y);
+
+ /* create the path to fill */
+ _gtk_rounded_box_init_rect (&border_box, 0, 0, width, height);
+ _gtk_rounded_box_apply_border_radius (&border_box, engine, state, junction);
+ padding_box = border_box;
+ _gtk_rounded_box_shrink (&padding_box, outer_border->top,
+ outer_border->right,
+ outer_border->bottom,
+ outer_border->left);
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+
+ if (outer_stroke_pat)
+ {
+ /* pattern */
+ cairo_scale (cr, width, height);
+ cairo_set_source (cr, outer_stroke_pat);
+ cairo_scale (cr, 1.0 / width, 1.0 / height);
+
+ _gtk_rounded_box_path (&border_box, cr);
+ _gtk_rounded_box_path (&padding_box, cr);
+ cairo_fill (cr);
+ }
+ else if (gdk_rgba_equal (colors[0], colors[1]) &&
+ gdk_rgba_equal (colors[0], colors[2]) &&
+ gdk_rgba_equal (colors[0], colors[3]))
+ {
+ /* one color */
+ gdk_cairo_set_source_rgba (cr, colors[0]);
+
+ _gtk_rounded_box_path (&border_box, cr);
+ _gtk_rounded_box_path (&padding_box, cr);
+ cairo_fill (cr);
+ }
+ else
+ {
+ /* different colors */
+ for (i = 0; i < 4; i++)
+ {
+ if (hidden_side & current_side[i])
+ continue;
+
+ for (j = 0; j < 4; j++)
+ {
+ if (hidden_side & current_side[j])
+ continue;
+
+ if (i == j ||
+ gdk_rgba_equal (colors[i], colors[j]))
+ {
+ /* we were already painted when i == j */
+ if (i > j)
+ break;
+
+ if (j == 0)
+ _gtk_rounded_box_path_top (&border_box, &padding_box, cr);
+ else if (j == 1)
+ _gtk_rounded_box_path_right (&border_box, &padding_box, cr);
+ else if (j == 2)
+ _gtk_rounded_box_path_bottom (&border_box, &padding_box, cr);
+ else if (j == 3)
+ _gtk_rounded_box_path_left (&border_box, &padding_box, cr);
+ }
+ }
+ /* we were already painted when i == j */
+ if (i > j)
+ continue;
+
+ gdk_cairo_set_source_rgba (cr, colors[i]);
+
+ cairo_fill (cr);
+ }
+ }
+
+ cairo_restore (cr);
+
+end_draw_outer_stroke:
+ gtk_border_free (outer_border);
+
+ if (outer_stroke_pat != NULL)
+ cairo_pattern_destroy (outer_stroke_pat);
+
+ gdk_rgba_free (outer_stroke_color);
+
+ for (i = 0; i < 4; i++)
+ gdk_rgba_free (colors[i]);
+}
+
+void
+tdegtk_cairo_draw_frame (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction)
+{
+ GtkBorder border;
+ GtkBorder *outer_border;
+ GtkStateFlags state;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-outer-stroke-width", &outer_border,
+ NULL);
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ hide_border_sides (&border, hidden_side);
+ hide_border_sides (outer_border, hidden_side);
+
+ if (!tdegtk_gtk_border_is_zero (outer_border))
+ {
+ /* first layer, outer stroke */
+ draw_outer_stroke (engine, cr,
+ x, y,
+ width, height,
+ hidden_side, junction);
+
+ shrink_with_border (outer_border, &x, &y, &width, &height);
+ }
+
+ /* second layer, inner stroke */
+ draw_inner_stroke (engine, cr,
+ x + border.left, y + border.top,
+ width - (border.left + border.right), height - (border.top + border.bottom),
+ hidden_side, junction);
+
+ /* third layer, border */
+ draw_border (engine, cr,
+ x, y,
+ width, height,
+ hidden_side, junction);
+
+ gtk_border_free (outer_border);
+}
+
+gboolean
+tdegtk_cairo_draw_from_texture (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ GtkStateFlags state;
+ GValue value = { 0, };
+ cairo_pattern_t *texture = NULL;
+ cairo_surface_t *surface = NULL;
+ gboolean retval = FALSE;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get_property (engine, "background-image", state, &value);
+
+ if (!G_VALUE_HOLDS_BOXED (&value))
+ return FALSE;
+
+ texture = g_value_dup_boxed (&value);
+ g_value_unset (&value);
+
+ if (texture != NULL)
+ cairo_pattern_get_surface (texture, &surface);
+
+ if (surface != NULL)
+ {
+ cairo_save (cr);
+
+ cairo_scale (cr, width / cairo_image_surface_get_width (surface),
+ height / cairo_image_surface_get_height (surface));
+ cairo_set_source_surface (cr, surface, x, y);
+
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+
+ retval = TRUE;
+ }
+
+ if (texture != NULL)
+ cairo_pattern_destroy (texture);
+
+ return retval;
+}
+
+void
+tdegtk_cairo_round_rect (cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ gint radius,
+ guint sides,
+ GtkJunctionSides junction)
+{
+ radius = CLAMP (radius, 0, MIN (width / 2, height / 2));
+
+ if (sides & SIDE_RIGHT)
+ {
+ if (radius == 0 ||
+ (junction & GTK_JUNCTION_CORNER_TOPRIGHT))
+ cairo_move_to (cr, x + width, y);
+ else
+ {
+ cairo_new_sub_path (cr);
+
+ cairo_arc (cr, x + width - radius, y + radius, radius, - G_PI / 4, 0);
+ }
+
+ if (radius == 0 ||
+ (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
+ cairo_line_to (cr, x + width, y + height);
+ else
+ cairo_arc (cr, x + width - radius, y + height - radius, radius, 0, G_PI / 4);
+ }
+
+ if (sides & SIDE_BOTTOM)
+ {
+ if (radius != 0 &&
+ ! (junction & GTK_JUNCTION_CORNER_BOTTOMRIGHT))
+ {
+ if ((sides & SIDE_RIGHT) == 0)
+ cairo_new_sub_path (cr);
+
+ cairo_arc (cr, x + width - radius, y + height - radius, radius, G_PI / 4, G_PI / 2);
+ }
+ else if ((sides & SIDE_RIGHT) == 0)
+ cairo_move_to (cr, x + width, y + height);
+
+ if (radius == 0 ||
+ (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
+ cairo_line_to (cr, x, y + height);
+ else
+ cairo_arc (cr, x + radius, y + height - radius, radius, G_PI / 2, 3 * (G_PI / 4));
+ }
+ else
+ cairo_move_to (cr, x, y + height);
+
+ if (sides & SIDE_LEFT)
+ {
+ if (radius != 0 &&
+ ! (junction & GTK_JUNCTION_CORNER_BOTTOMLEFT))
+ {
+ if ((sides & SIDE_BOTTOM) == 0)
+ cairo_new_sub_path (cr);
+
+ cairo_arc (cr, x + radius, y + height - radius, radius, 3 * (G_PI / 4), G_PI);
+ }
+ else if ((sides & SIDE_BOTTOM) == 0)
+ cairo_move_to (cr, x, y + height);
+
+ if (radius == 0 ||
+ (junction & GTK_JUNCTION_CORNER_TOPLEFT))
+ cairo_line_to (cr, x, y);
+ else
+ cairo_arc (cr, x + radius, y + radius, radius, G_PI, G_PI + G_PI / 4);
+ }
+
+ if (sides & SIDE_TOP)
+ {
+ if (radius != 0 &&
+ ! (junction & GTK_JUNCTION_CORNER_TOPLEFT))
+ {
+ if ((sides & SIDE_LEFT) == 0)
+ cairo_new_sub_path (cr);
+
+ cairo_arc (cr, x + radius, y + radius, radius, 5 * (G_PI / 4), 3 * (G_PI / 2));
+ }
+ else if ((sides & SIDE_LEFT) == 0)
+ cairo_move_to (cr, x, y);
+
+ if (radius == 0 ||
+ (junction & GTK_JUNCTION_CORNER_TOPRIGHT))
+ cairo_line_to (cr, x + width, y);
+ else
+ cairo_arc (cr, x + width - radius, y + radius, radius, 3 * (G_PI / 2), - G_PI / 4);
+ }
+}
+
+void
+tdegtk_cairo_round_rect_inner (cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ gint radius,
+ guint sides,
+ GtkJunctionSides junction)
+{
+ gdouble line_width;
+
+ line_width = cairo_get_line_width (cr);
+
+ /* center the rounded rectangle using line_width */
+ tdegtk_cairo_round_rect (cr, x + line_width / 2.0,
+ y + line_width / 2.0,
+ width - line_width,
+ height - line_width,
+ radius, sides, junction);
+}
+
+void
+tdegtk_cairo_set_source_border (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble width,
+ gdouble height)
+{
+ GdkRGBA border_color;
+ GtkBorderStyle border_style;
+ GtkStateFlags state;
+ cairo_pattern_t *border_pat;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "border-style", &border_style,
+ "-tdegtk-border-gradient", &border_pat,
+ NULL);
+ gtk_theming_engine_get_border_color (engine, state, &border_color);
+
+ if (border_pat)
+ {
+ /* pattern */
+ cairo_scale (cr, width, height);
+ cairo_set_source (cr, border_pat);
+ cairo_scale (cr, 1.0 / width, 1.0 / height);
+ }
+ else
+ /* one color */
+ gdk_cairo_set_source_rgba (cr, &border_color);
+
+ if (border_pat != NULL)
+ cairo_pattern_destroy (border_pat);
+}
+
+void
+tdegtk_cairo_set_source_inner_stroke (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble width,
+ gdouble height)
+{
+ GdkRGBA *inner_stroke_color;
+ GtkStateFlags state;
+ cairo_pattern_t *inner_stroke_pat;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-inner-stroke-color", &inner_stroke_color,
+ "-tdegtk-inner-stroke-gradient", &inner_stroke_pat,
+ NULL);
+
+ if (inner_stroke_pat)
+ {
+ /* pattern */
+ cairo_scale (cr, width, height);
+ cairo_set_source (cr, inner_stroke_pat);
+ cairo_scale (cr, 1.0 / width, 1.0 / height);
+ }
+ else
+ /* one color */
+ gdk_cairo_set_source_rgba (cr, inner_stroke_color);
+
+ if (inner_stroke_pat != NULL)
+ cairo_pattern_destroy (inner_stroke_pat);
+
+ gdk_rgba_free (inner_stroke_color);
+}
diff --git a/tdegtk/tdegtk-cairo-support.h b/tdegtk/tdegtk-cairo-support.h
new file mode 100644
index 0000000..6daf4c5
--- /dev/null
+++ b/tdegtk/tdegtk-cairo-support.h
@@ -0,0 +1,85 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#ifndef TDEGTK_CAIRO_SUPPORT_H
+#define TDEGTK_CAIRO_SUPPORT_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL void tdegtk_cairo_draw_background (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction);
+
+G_GNUC_INTERNAL void tdegtk_cairo_draw_frame (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ guint hidden_side,
+ GtkJunctionSides junction);
+
+G_GNUC_INTERNAL gboolean tdegtk_cairo_draw_from_texture (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height);
+
+G_GNUC_INTERNAL void tdegtk_cairo_round_rect (cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ gint radius,
+ guint hidden_side,
+ GtkJunctionSides junction);
+
+G_GNUC_INTERNAL void tdegtk_cairo_round_rect_inner (cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ gint radius,
+ guint sides,
+ GtkJunctionSides junction);
+
+G_GNUC_INTERNAL void tdegtk_cairo_set_source_border (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble width,
+ gdouble height);
+
+G_GNUC_INTERNAL void tdegtk_cairo_set_source_inner_stroke (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble width,
+ gdouble height);
+
+G_END_DECLS
+
+#endif /* TDEGTK_CAIRO_SUPPORT_H */
diff --git a/tdegtk/tdegtk-draw.c b/tdegtk/tdegtk-draw.c
new file mode 100644
index 0000000..f1fa2df
--- /dev/null
+++ b/tdegtk/tdegtk-draw.c
@@ -0,0 +1,1062 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#include <cairo.h>
+#include <gtk/gtk.h>
+#include <math.h>
+
+#include "tdegtk-cairo-support.h"
+#include "tdegtk-draw.h"
+#include "tdegtk-support.h"
+#include "tdegtk-types.h"
+
+/* draw a texture placed on the centroid */
+static gboolean
+draw_centroid_texture (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ GtkStateFlags state;
+ GValue value = { 0, };
+ cairo_pattern_t *texture = NULL;
+ cairo_surface_t *surface = NULL;
+ gboolean retval = FALSE;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get_property (engine, "-tdegtk-centroid-texture", state, &value);
+
+ if (!G_VALUE_HOLDS_BOXED (&value))
+ return FALSE;
+
+ texture = g_value_dup_boxed (&value);
+ g_value_unset (&value);
+
+ if (texture != NULL)
+ cairo_pattern_get_surface (texture, &surface);
+
+ if (surface != NULL)
+ {
+ cairo_save (cr);
+
+ cairo_set_source_surface (cr, surface, (gint) (x + width / 2 - cairo_image_surface_get_width (surface) / 2),
+ (gint) (y + height / 2 - cairo_image_surface_get_height (surface) / 2));
+ cairo_paint (cr);
+
+ cairo_restore (cr);
+
+ retval = TRUE;
+ }
+
+ if (texture != NULL)
+ cairo_pattern_destroy (texture);
+
+ return retval;
+}
+
+static void
+tdegtk_draw_activity (DRAW_ARGS)
+{
+ /* playground for effects */
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+}
+
+static void
+tdegtk_draw_arrow (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble angle,
+ gdouble x,
+ gdouble y,
+ gdouble size)
+{
+ GtkStateFlags state;
+ GdkRGBA color;
+ gdouble size_reduction = 2;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get_color (engine, state, &color);
+
+ cairo_save (cr);
+
+ /* use floor function to adjust doubles */
+ y = floor (y);
+ x = floor (x);
+ size = floor (size);
+
+ size -= size_reduction;
+
+ cairo_translate (cr, size_reduction / 2, size_reduction / 2);
+ cairo_translate (cr, x + (gint) (size / 2.0) + 0.5, y + (gint) (size / 2.0) + 0.5);
+ cairo_rotate (cr, angle - G_PI_2);
+ cairo_translate (cr, (gint) (size / 4.0), 0);
+
+ /* FIXME this + 1/- 1 is done to fix blurred diagonal lines.
+ * I know it's not nice at all, but it fix a visual bug */
+ cairo_move_to (cr, - (gint) (size / 2.0), - (gint) (size / 2.0));
+ cairo_rel_line_to (cr, (gint) (size / 2.0) + 1, (gint) (size / 2.0));
+ cairo_rel_line_to (cr, - (gint) (size / 2.0) - 1, (gint) (size / 2.0));
+ cairo_close_path (cr);
+
+ cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * 0.75);
+ cairo_fill_preserve (cr);
+
+ gdk_cairo_set_source_rgba (cr, &color);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+}
+
+static void
+tdegtk_draw_cell_background (DRAW_ARGS,
+ GtkRegionFlags flags)
+{
+ GtkJunctionSides junction;
+ guint hidden_side;
+
+ junction = GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT;
+
+ hidden_side = SIDE_RIGHT | SIDE_LEFT;
+
+ if ((flags & GTK_REGION_FIRST) != 0)
+ {
+ junction &= ~(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMLEFT);
+ hidden_side &= ~(SIDE_LEFT);
+ }
+ if ((flags & GTK_REGION_LAST) != 0)
+ {
+ junction &= ~(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMRIGHT);
+ hidden_side &= ~(SIDE_RIGHT);
+ }
+
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ hidden_side, junction);
+}
+
+static void
+tdegtk_draw_cell_frame (DRAW_ARGS,
+ GtkRegionFlags flags)
+{
+ GtkJunctionSides junction;
+ guint hidden_side;
+
+ junction = GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT;
+
+ hidden_side = SIDE_RIGHT | SIDE_LEFT;
+
+ if ((flags & GTK_REGION_FIRST) != 0)
+ {
+ junction &= ~(GTK_JUNCTION_CORNER_TOPLEFT | GTK_JUNCTION_CORNER_BOTTOMLEFT);
+ hidden_side &= ~(SIDE_LEFT);
+ }
+ if ((flags & GTK_REGION_LAST) != 0)
+ {
+ junction &= ~(GTK_JUNCTION_CORNER_TOPRIGHT | GTK_JUNCTION_CORNER_BOTTOMRIGHT);
+ hidden_side &= ~(SIDE_RIGHT);
+ }
+
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ hidden_side, junction);
+}
+
+static void
+tdegtk_draw_check (DRAW_ARGS)
+{
+ GtkStateFlags state;
+ gboolean in_menu;
+ gboolean draw_bullet, inconsistent;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ in_menu = gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_MENUITEM);
+ inconsistent = (state & GTK_STATE_FLAG_INCONSISTENT) != 0;
+ draw_bullet = (state & GTK_STATE_FLAG_ACTIVE) != 0;
+ draw_bullet |= inconsistent;
+
+ if (!in_menu)
+ {
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+ }
+
+ if (draw_bullet)
+ {
+ GdkRGBA *bullet_color;
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-bullet-color", &bullet_color,
+ NULL);
+
+ if (inconsistent)
+ {
+ cairo_save (cr);
+
+ cairo_set_line_width (cr, 2.0);
+ cairo_move_to (cr, 3, height / 2.0);
+ cairo_line_to (cr, width - 3, height / 2.0);
+
+ cairo_restore (cr);
+ }
+ else
+ {
+ cairo_translate (cr, x, y);
+
+ if (in_menu)
+ {
+ cairo_scale (cr, width / 18.0, height / 18.0);
+ cairo_translate (cr, 2.0, 3.0);
+ }
+ else
+ {
+ GdkRGBA *bullet_outline_color;
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-bullet-outline-color", &bullet_outline_color,
+ NULL);
+
+ cairo_scale (cr, width / 18.0, height / 18.0);
+
+ /* thick's outline */
+ cairo_move_to (cr, 5.0, 5.65);
+ cairo_line_to (cr, 8.95, 9.57);
+ cairo_line_to (cr, 16.0, 2.54);
+ cairo_line_to (cr, 16.0, 8.36);
+ cairo_line_to (cr, 10.6, 15.1);
+ cairo_line_to (cr, 7.6, 15.1);
+ cairo_line_to (cr, 2.95, 10.48);
+ cairo_line_to (cr, 2.95, 7.65);
+ cairo_close_path (cr);
+
+ gdk_cairo_set_source_rgba (cr, bullet_outline_color);
+ cairo_fill (cr);
+
+ cairo_translate (cr, 4.0, 2.0);
+
+ gdk_rgba_free (bullet_outline_color);
+ }
+
+ /* thick */
+ cairo_move_to (cr, 0.0, 6.0);
+ cairo_line_to (cr, 0.0, 8.0);
+ cairo_line_to (cr, 4.0, 12.0);
+ cairo_line_to (cr, 6.0, 12.0);
+ cairo_line_to (cr, 15.0, 1.0);
+ cairo_line_to (cr, 15.0, 0.0);
+ cairo_line_to (cr, 14.0, 0.0);
+ cairo_line_to (cr, 5.0, 9.0);
+ cairo_line_to (cr, 1.0, 5.0);
+ cairo_close_path (cr);
+ }
+
+ gdk_cairo_set_source_rgba (cr, bullet_color);
+ cairo_fill (cr);
+
+ gdk_rgba_free (bullet_color);
+ }
+}
+
+static void
+tdegtk_draw_common (DRAW_ARGS)
+{
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+}
+
+static void
+tdegtk_draw_common_background (DRAW_ARGS)
+{
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+}
+
+static void
+tdegtk_draw_common_frame (DRAW_ARGS)
+{
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+}
+
+static void
+tdegtk_draw_expander (DRAW_ARGS)
+{
+ GtkStateFlags state;
+ GdkRGBA color;
+ gint size;
+ gdouble angle = G_PI_2;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get_color (engine, state, &color);
+
+ cairo_save (cr);
+
+ /* use floor function to adjust doubles */
+ size = floor (MIN (width, height));
+
+ x += (gint) (width / 2) - size / 2;
+ y += (gint) (height / 2) - size / 2;
+
+ if ((state & GTK_STATE_FLAG_ACTIVE) == 0)
+ angle = 0;
+
+ cairo_translate (cr, x + size / 2.0 + 0.5, y + size / 2.0 + 0.5);
+ cairo_rotate (cr, angle);
+ cairo_translate (cr, size / 4.0, 0);
+
+ /* FIXME this + 1/- 1 is done to fix blurred diagonal lines.
+ * I know it's not nice at all, but it fix a visual bug */
+ cairo_move_to (cr, - size / 2.0, - size / 2.0);
+ cairo_rel_line_to (cr, size / 2.0 + 1, size / 2.0);
+ cairo_rel_line_to (cr, - size / 2.0 - 1, size / 2.0);
+ cairo_close_path (cr);
+
+ cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * 0.75);
+ cairo_fill_preserve (cr);
+
+ gdk_cairo_set_source_rgba (cr, &color);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+}
+
+static void
+tdegtk_draw_extension (DRAW_ARGS,
+ GtkPositionType gap_side)
+{
+ GtkBorder border;
+ GtkBorder *outer_border;
+ GtkJunctionSides junction = 0;
+ GtkStateFlags state;
+ gboolean has_outer_stroke = FALSE;
+ gdouble bg_offset = 0;
+ guint hidden_side = 0;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-outer-stroke-width", &outer_border,
+ NULL);
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ if (!tdegtk_gtk_border_is_zero (outer_border))
+ has_outer_stroke = TRUE;
+
+ cairo_save (cr);
+
+ /* FIXME doesn't work properly with not homogenuos border-width,
+ * especially between tab and notebook.
+ * I guess the issue comes from the fact draw_background
+ * is looking at border dimensions while we're not,
+ * or we're doing it wrong.
+ * draw_background is looking at SIDE_BOTTOM and
+ * sets border to 0 for this side */
+ switch (gap_side)
+ {
+ case GTK_POS_TOP:
+ junction = GTK_JUNCTION_TOP;
+ hidden_side = SIDE_TOP;
+
+ if (has_outer_stroke)
+ {
+ y -= outer_border->bottom;
+ height += outer_border->bottom;
+ }
+
+ if ((state & GTK_STATE_FLAG_ACTIVE) != 0)
+ bg_offset = border.bottom;
+
+ cairo_translate (cr, x + width, y + height);
+ cairo_rotate (cr, G_PI);
+ break;
+ default:
+ case GTK_POS_BOTTOM:
+ junction = GTK_JUNCTION_BOTTOM;
+ hidden_side = SIDE_BOTTOM;
+
+ if (has_outer_stroke)
+ height += outer_border->top;
+
+ if ((state & GTK_STATE_FLAG_ACTIVE) != 0)
+ bg_offset = border.top;
+
+ cairo_translate (cr, x, y);
+ break;
+ case GTK_POS_LEFT:
+ junction = GTK_JUNCTION_LEFT;
+ hidden_side = SIDE_LEFT;
+
+ if (has_outer_stroke)
+ {
+ x -= outer_border->right;
+ width += outer_border->right;
+ }
+
+ if ((state & GTK_STATE_FLAG_ACTIVE) != 0)
+ bg_offset = border.right;
+
+ cairo_translate (cr, x + width, y);
+ cairo_rotate (cr, G_PI / 2);
+ break;
+ case GTK_POS_RIGHT:
+ junction = GTK_JUNCTION_RIGHT;
+ hidden_side = SIDE_RIGHT;
+
+ if (has_outer_stroke)
+ width += outer_border->left;
+
+ if ((state & GTK_STATE_FLAG_ACTIVE) != 0)
+ bg_offset = border.left;
+
+ cairo_translate (cr, x, y + height);
+ cairo_rotate (cr, - G_PI / 2);
+ break;
+ }
+
+ if (gap_side == GTK_POS_TOP ||
+ gap_side == GTK_POS_BOTTOM)
+ tdegtk_cairo_draw_background (engine, cr, 0, 0, width, height + bg_offset, SIDE_BOTTOM, GTK_JUNCTION_BOTTOM);
+ else
+ tdegtk_cairo_draw_background (engine, cr, 0, 0, height, width + bg_offset, SIDE_BOTTOM, GTK_JUNCTION_BOTTOM);
+ cairo_restore (cr);
+
+ /* FIXME the frame on bottom bar has the wrong gradient,
+ * while should be reflected */
+ tdegtk_cairo_draw_frame (engine, cr, x, y, width, height, hidden_side, junction);
+
+ gtk_border_free (outer_border);
+}
+
+static void
+tdegtk_draw_focus (DRAW_ARGS)
+{
+ GdkRGBA *fill_color, *border_color, *outer_stroke_color;
+ GtkStateFlags state;
+ gint focus_pad, line_width;
+ gint radius;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-focus-border-color", &border_color,
+ "-tdegtk-focus-border-radius", &radius,
+ "-tdegtk-focus-fill-color", &fill_color,
+ "-tdegtk-focus-outer-stroke-color", &outer_stroke_color,
+ NULL);
+ gtk_theming_engine_get_style (engine,
+ "focus-padding", &focus_pad,
+ "focus-line-width", &line_width,
+ NULL);
+
+ x += focus_pad;
+ y += focus_pad;
+ width -= focus_pad * 2;
+ height -= focus_pad * 2;
+
+ cairo_save (cr);
+
+ cairo_set_line_width (cr, line_width);
+
+ /* first layer, background */
+ tdegtk_cairo_round_rect (cr, x, y,
+ width, height,
+ radius, SIDE_ALL, GTK_JUNCTION_NONE);
+ gdk_cairo_set_source_rgba (cr, fill_color);
+ cairo_fill (cr);
+
+ /* second layer, outer stroke */
+ tdegtk_cairo_round_rect_inner (cr, x - line_width, y - line_width,
+ width + line_width * 2, height + line_width * 2,
+ radius + 1, SIDE_ALL, GTK_JUNCTION_NONE);
+ gdk_cairo_set_source_rgba (cr, outer_stroke_color);
+ cairo_stroke (cr);
+
+ /* third layer, border */
+ tdegtk_cairo_round_rect_inner (cr, x, y,
+ width, height,
+ radius, SIDE_ALL, GTK_JUNCTION_NONE);
+ gdk_cairo_set_source_rgba (cr, border_color);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+
+ gdk_rgba_free (border_color);
+ gdk_rgba_free (fill_color);
+ gdk_rgba_free (outer_stroke_color);
+}
+
+static void
+tdegtk_draw_frame_gap (DRAW_ARGS,
+ GtkPositionType gap_side,
+ gdouble xy0_gap,
+ gdouble xy1_gap)
+{
+ GtkBorder border;
+ GtkBorder *outer_border;
+ GtkCssBorderCornerRadius *top_left_radius, *top_right_radius;
+ GtkCssBorderCornerRadius *bottom_left_radius, *bottom_right_radius;
+ GtkCssBorderRadius border_radius = { { 0, }, };
+ GtkJunctionSides junction;
+ GtkStateFlags state;
+ gboolean has_outer_stroke = FALSE;
+ gdouble x0, y0, x1, y1, xc, yc, wc, hc;
+
+ xc = yc = wc = hc = 0;
+
+ junction = gtk_theming_engine_get_junction_sides (engine);
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ /* Can't use border-radius as it's an int for
+ * backwards compat */
+ "border-top-left-radius", &top_left_radius,
+ "border-top-right-radius", &top_right_radius,
+ "border-bottom-right-radius", &bottom_right_radius,
+ "border-bottom-left-radius", &bottom_left_radius,
+ "-tdegtk-outer-stroke-width", &outer_border,
+ NULL);
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ if (!tdegtk_gtk_border_is_zero (outer_border))
+ has_outer_stroke = TRUE;
+
+ if (top_left_radius)
+ border_radius.top_left = *top_left_radius;
+ g_free (top_left_radius);
+ if (top_right_radius)
+ border_radius.top_right = *top_right_radius;
+ g_free (top_right_radius);
+ if (bottom_right_radius)
+ border_radius.bottom_right = *bottom_right_radius;
+ g_free (bottom_right_radius);
+ if (bottom_left_radius)
+ border_radius.bottom_left = *bottom_left_radius;
+ g_free (bottom_left_radius);
+
+ cairo_save (cr);
+
+ switch (gap_side)
+ {
+ case GTK_POS_TOP:
+ xc = x + xy0_gap + border.left;
+ yc = y;
+ wc = MAX (xy1_gap - xy0_gap - (border.left + border.right), 0);
+ hc = border.top * 2;
+
+ if (has_outer_stroke)
+ {
+ xc += outer_border->left;
+ wc = MAX (xy1_gap - xy0_gap - (outer_border->left + outer_border->right) - (border.left + border.right), 0);
+ hc += outer_border->top;
+ }
+
+ if (xy0_gap < border_radius.top_left.horizontal)
+ junction |= GTK_JUNCTION_CORNER_TOPLEFT;
+
+ if (xy1_gap > width - border_radius.top_right.horizontal)
+ junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
+ break;
+ default:
+ case GTK_POS_BOTTOM:
+ xc = x + xy0_gap + border.left;
+ yc = y + height - border.bottom * 2;
+ wc = MAX (xy1_gap - xy0_gap - (border.left + border.right), 0);
+ hc = border.bottom * 2;
+
+ if (has_outer_stroke)
+ {
+ xc += outer_border->left;
+ yc -= outer_border->bottom;
+ wc = MAX (xy1_gap - xy0_gap - (outer_border->left + outer_border->right) - (border.left + border.right), 0);
+ hc += outer_border->bottom;
+ }
+
+ if (xy0_gap < border_radius.bottom_left.horizontal)
+ junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT;
+
+ if (xy1_gap > width - border_radius.bottom_right.horizontal)
+ junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT;
+
+ break;
+ case GTK_POS_LEFT:
+ xc = x;
+ yc = y + xy0_gap + border.top;
+ wc = border.left * 2;
+ hc = MAX (xy1_gap - xy0_gap - (border.top + border.bottom), 0);
+
+ if (has_outer_stroke)
+ {
+ yc += outer_border->top;
+ wc += outer_border->left;
+ hc = MAX (xy1_gap - xy0_gap - (outer_border->top + outer_border->bottom) - (border.top + border.bottom), 0);
+ }
+
+ if (xy0_gap < border_radius.top_left.vertical)
+ junction |= GTK_JUNCTION_CORNER_TOPLEFT;
+
+ if (xy1_gap > height - border_radius.bottom_left.vertical)
+ junction |= GTK_JUNCTION_CORNER_BOTTOMLEFT;
+
+ break;
+ case GTK_POS_RIGHT:
+ xc = x + width - border.right * 2;
+ yc = y + xy0_gap + border.top;
+ wc = border.right * 2;
+ hc = MAX (xy1_gap - xy0_gap - (border.top + border.bottom), 0);
+
+ if (has_outer_stroke)
+ {
+ xc -= outer_border->right;
+ yc += outer_border->top;
+ wc += outer_border->right;
+ hc = MAX (xy1_gap - xy0_gap - (outer_border->top + outer_border->bottom) - (border.top + border.bottom), 0);
+ }
+
+ if (xy0_gap < border_radius.top_right.vertical)
+ junction |= GTK_JUNCTION_CORNER_TOPRIGHT;
+
+ if (xy1_gap > height - border_radius.bottom_right.vertical)
+ junction |= GTK_JUNCTION_CORNER_BOTTOMRIGHT;
+
+ break;
+ }
+
+ /* clip the gap */
+ cairo_clip_extents (cr, &x0, &y0, &x1, &y1);
+ cairo_rectangle (cr, x0, y0, x1 - x0, yc - y0);
+ cairo_rectangle (cr, x0, yc, xc - x0, hc);
+ cairo_rectangle (cr, xc + wc, yc, x1 - (xc + wc), hc);
+ cairo_rectangle (cr, x0, yc + hc, x1 - x0, y1 - (yc + hc));
+ cairo_clip (cr);
+
+ /* draw the frame, gap area will not be drawn */
+ tdegtk_cairo_draw_frame (engine, cr, x, y, width, height, 0, junction);
+
+ cairo_restore (cr);
+
+ gtk_border_free (outer_border);
+}
+
+static void
+tdegtk_draw_grip (DRAW_ARGS)
+{
+ GdkRGBA border_color;
+ GdkRGBA *inner_stroke_color;
+ GtkStateFlags state;
+ gint lx, ly;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-inner-stroke-color", &inner_stroke_color,
+ NULL);
+ gtk_theming_engine_get_border_color (engine, state, &border_color);
+
+ for (ly = 0; ly < 4; ly++)
+ {
+ /* vertically, four rows of dots */
+ for (lx = 0; lx <= ly; lx++)
+ {
+ /* horizontally */
+ int ny = (3.5 - ly) * 3;
+ int nx = lx * 3;
+
+ gdk_cairo_set_source_rgba (cr, inner_stroke_color);
+ cairo_rectangle (cr, x + width - nx - 1, y + height - ny - 1, 2, 2);
+ cairo_fill (cr);
+
+ gdk_cairo_set_source_rgba (cr, &border_color);
+ cairo_rectangle (cr, x + width - nx - 1, y + height - ny - 1, 1, 1);
+ cairo_fill (cr);
+ }
+ }
+
+ gdk_rgba_free (inner_stroke_color);
+}
+
+static void
+tdegtk_draw_handle (DRAW_ARGS)
+{
+ gdouble line_width;
+ gint i, bar_y, num_bars, bar_spacing, bar_width, bar_height;
+
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+
+ if (draw_centroid_texture (engine, cr, x, y, width, height))
+ return;
+
+ tdegtk_get_line_width (engine, &line_width);
+
+ bar_y = 1;
+ num_bars = 3;
+ bar_spacing = 3;
+ bar_width = 3;
+ bar_height = num_bars * bar_spacing * line_width;
+
+ cairo_save (cr);
+
+ cairo_translate (cr, x + (gint) (width / 2), y + (gint) (height / 2));
+
+ if (height > width)
+ cairo_translate (cr, - bar_width / 2 - 0.5, - bar_height / 2 + 0.5);
+ else
+ {
+ cairo_translate (cr, - bar_height / 2 + 0.5, bar_width / 2 + 0.5);
+ cairo_rotate (cr, - G_PI / 2);
+ }
+
+ for (i = 0; i < num_bars; i++)
+ {
+ /* draw bars */
+ cairo_move_to (cr, 0, bar_y);
+ cairo_line_to (cr, bar_width, bar_y);
+ tdegtk_cairo_set_source_border (engine, cr, bar_width, 3);
+ cairo_stroke (cr);
+
+ cairo_move_to (cr, 0, bar_y + line_width);
+ cairo_line_to (cr, bar_width, bar_y + line_width);
+ tdegtk_cairo_set_source_inner_stroke (engine, cr, bar_width, line_width);
+ cairo_stroke (cr);
+
+ bar_y += bar_spacing;
+ }
+
+ cairo_restore (cr);
+}
+
+static void
+tdegtk_draw_line (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x0,
+ gdouble y0,
+ gdouble x1,
+ gdouble y1)
+{
+ /* line endings */
+ if (y0 == y1)
+ {
+ y0 += 0.5;
+ y1 += 0.5;
+ x0 += 0.5;
+ x1 -= 0.5;
+ }
+ else if (x0 == x1)
+ {
+ x0 += 0.5;
+ x1 += 0.5;
+ y0 += 0.5;
+ y1 -= 0.5;
+ }
+
+ cairo_move_to (cr, x0, y0);
+ cairo_line_to (cr, x1, y1);
+ tdegtk_cairo_set_source_border (engine, cr, MAX (x1 - x0, 1), MAX (y1 - y0, 1));
+ cairo_stroke (cr);
+}
+
+static void
+tdegtk_draw_notebook (DRAW_ARGS,
+ GtkPositionType gap_side,
+ gdouble xy0_gap,
+ gdouble xy1_gap)
+{
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+ tdegtk_draw_frame_gap (engine, cr,
+ x, y, width, height,
+ gap_side, xy0_gap, xy1_gap);
+}
+
+static void
+tdegtk_draw_radio (DRAW_ARGS)
+{
+ GtkStateFlags state;
+ gboolean in_menu;
+ gboolean draw_bullet, inconsistent;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ in_menu = gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_MENUITEM);
+ inconsistent = (state & GTK_STATE_FLAG_INCONSISTENT) != 0;
+ draw_bullet = (state & GTK_STATE_FLAG_ACTIVE) != 0;
+ draw_bullet |= inconsistent;
+
+ if (!in_menu)
+ {
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+ }
+
+ if (draw_bullet)
+ {
+ GdkRGBA *bullet_color;
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-bullet-color", &bullet_color,
+ NULL);
+
+ if (inconsistent)
+ {
+ cairo_save (cr);
+
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_width (cr, 2.0);
+
+ cairo_move_to(cr, 5, height / 2.0);
+ cairo_line_to(cr, width - 5, height / 2.0);
+
+ gdk_cairo_set_source_rgba (cr, bullet_color);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+ }
+ else
+ {
+ if (in_menu)
+ cairo_arc (cr, x + width / 2.0, y + height / 2.0,
+ (width + height) / 4.0 - 4, 0, G_PI * 2);
+ else
+ {
+ GdkRGBA *bullet_outline_color;
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-bullet-outline-color", &bullet_outline_color,
+ NULL);
+
+ /* bullet's outline */
+ cairo_arc (cr, x + width / 2.0, y + height / 2.0,
+ (width + height) / 4.0 - 4, 0, G_PI * 2);
+ gdk_cairo_set_source_rgba (cr, bullet_outline_color);
+ cairo_fill (cr);
+
+ cairo_arc (cr, x + width / 2.0, y + height / 2.0,
+ (width + height) / 4.0 - 5, 0, G_PI * 2);
+
+ gdk_rgba_free (bullet_outline_color);
+ }
+
+ /* bullet */
+ gdk_cairo_set_source_rgba (cr, bullet_color);
+ cairo_fill (cr);
+ }
+
+ gdk_rgba_free (bullet_color);
+ }
+}
+
+static void
+tdegtk_draw_separator (DRAW_ARGS)
+{
+ gdouble line_width;
+
+ tdegtk_get_line_width (engine, &line_width);
+
+ if (line_width == 0)
+ return;
+
+ /* FIXME right code should be
+ * if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_VERTICAL))
+ * but doesn't work for separator tool item. */
+ if (width > height)
+ {
+ cairo_move_to (cr, x, y + (gint) (height / 2) + line_width / 2);
+ cairo_line_to (cr, x + width, y + (gint) (height / 2) + line_width / 2);
+ tdegtk_cairo_set_source_inner_stroke (engine, cr, width, line_width);
+ cairo_stroke (cr);
+
+ cairo_move_to (cr, x, y + (gint) (height / 2) - line_width / 2);
+ cairo_line_to (cr, x + width, y + (gint) (height / 2) - line_width / 2);
+ tdegtk_cairo_set_source_border (engine, cr, width, line_width);
+ cairo_stroke (cr);
+ }
+ else
+ {
+ cairo_move_to (cr, x + (gint) (width / 2) + line_width / 2, y);
+ cairo_line_to (cr, x + (gint) (width / 2) + line_width / 2, y + height);
+ tdegtk_cairo_set_source_inner_stroke (engine, cr, line_width, height);
+ cairo_stroke (cr);
+
+ cairo_move_to (cr, x + (gint) (width / 2) - line_width / 2, y);
+ cairo_line_to (cr, x + (gint) (width / 2) - line_width / 2, y + height);
+ tdegtk_cairo_set_source_border (engine, cr, line_width, height);
+ cairo_stroke (cr);
+ }
+}
+
+static void
+tdegtk_draw_slider (DRAW_ARGS,
+ GtkOrientation orientation)
+{
+ /* use orientation, if needed */
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+
+ draw_centroid_texture (engine, cr, x, y, width, height);
+
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ 0, gtk_theming_engine_get_junction_sides (engine));
+}
+
+static void
+tdegtk_draw_spinbutton_background (DRAW_ARGS)
+{
+ GtkBorder border, *outer_border;
+ GtkJunctionSides junction;
+ GtkStateFlags state;
+
+ junction = gtk_theming_engine_get_junction_sides (engine);
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-outer-stroke-width", &outer_border,
+ NULL);
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ cairo_save (cr);
+
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_clip (cr);
+
+ if (!(junction & GTK_JUNCTION_CORNER_TOPRIGHT))
+ {
+ y = ceil (y);
+ height = floor (height);
+ height += border.bottom + outer_border->bottom;
+ }
+ else
+ {
+ y = floor (y);
+ height = ceil (height);
+ y -= outer_border->top;
+ height += outer_border->bottom;
+ }
+
+ tdegtk_cairo_draw_background (engine, cr,
+ x, y, width, height,
+ 0, junction);
+
+ cairo_restore (cr);
+
+ gtk_border_free (outer_border);
+}
+
+static void
+tdegtk_draw_spinbutton_frame (DRAW_ARGS)
+{
+ GtkBorder border, *outer_border;
+ GtkJunctionSides junction;
+ GtkStateFlags state;
+
+ junction = gtk_theming_engine_get_junction_sides (engine);
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get (engine, state,
+ "-tdegtk-outer-stroke-width", &outer_border,
+ NULL);
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ cairo_save (cr);
+
+ cairo_rectangle (cr, x, y, width, height);
+ cairo_clip (cr);
+
+ if (!(junction & GTK_JUNCTION_CORNER_TOPRIGHT))
+ {
+ y = ceil (y);
+ height = floor (height);
+ height += border.bottom + outer_border->bottom;
+ }
+ else
+ {
+ y = floor (y);
+ height = ceil (height);
+ y -= outer_border->top;
+ height += outer_border->bottom;
+ }
+
+ tdegtk_cairo_draw_frame (engine, cr,
+ x, y, width, height,
+ 0, junction);
+
+ cairo_restore (cr);
+
+ gtk_border_free (outer_border);
+}
+
+void
+tdegtk_register_style_default (TdeGtkStyleFunctions *functions)
+{
+ g_assert (functions);
+
+ functions->draw_activity = tdegtk_draw_activity;
+ functions->draw_arrow = tdegtk_draw_arrow;
+ functions->draw_cell_background = tdegtk_draw_cell_background;
+ functions->draw_cell_frame = tdegtk_draw_cell_frame;
+ functions->draw_check = tdegtk_draw_check;
+ functions->draw_common = tdegtk_draw_common;
+ functions->draw_common_background = tdegtk_draw_common_background;
+ functions->draw_common_frame = tdegtk_draw_common_frame;
+ functions->draw_expander = tdegtk_draw_expander;
+ functions->draw_extension = tdegtk_draw_extension;
+ functions->draw_focus = tdegtk_draw_focus;
+ functions->draw_frame_gap = tdegtk_draw_frame_gap;
+ functions->draw_grip = tdegtk_draw_grip;
+ functions->draw_handle = tdegtk_draw_handle;
+ functions->draw_line = tdegtk_draw_line;
+ functions->draw_notebook = tdegtk_draw_notebook;
+ functions->draw_radio = tdegtk_draw_radio;
+ functions->draw_separator = tdegtk_draw_separator;
+ functions->draw_slider = tdegtk_draw_slider;
+ functions->draw_spinbutton_background = tdegtk_draw_spinbutton_background;
+ functions->draw_spinbutton_frame = tdegtk_draw_spinbutton_frame;
+}
diff --git a/tdegtk/tdegtk-draw.h b/tdegtk/tdegtk-draw.h
new file mode 100644
index 0000000..06031cd
--- /dev/null
+++ b/tdegtk/tdegtk-draw.h
@@ -0,0 +1,36 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#ifndef TDEGTK_DRAW_H
+#define TDEGTK_DRAW_H
+
+G_BEGIN_DECLS
+
+#include <gtk/gtk.h>
+
+#include "tdegtk-types.h"
+
+G_GNUC_INTERNAL void tdegtk_register_style_default (TdeGtkStyleFunctions *functions);
+
+G_END_DECLS
+
+#endif /* TDEGTK_DRAW_H */
diff --git a/tdegtk/tdegtk-engine.c b/tdegtk/tdegtk-engine.c
new file mode 100644
index 0000000..dfca517
--- /dev/null
+++ b/tdegtk/tdegtk-engine.c
@@ -0,0 +1,525 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#include <cairo.h>
+#include <cairo-gobject.h>
+#include <gtk/gtk.h>
+
+#include "tdegtk.h"
+#include "tdegtk-cairo-support.h"
+#include "tdegtk-draw.h"
+#include "tdegtk-engine.h"
+#include "tdegtk-support.h"
+#include "tdegtk-types.h"
+
+#define TDEGTK_NAMESPACE "tdegtk"
+
+#define TDEGTK_CAIRO_INIT \
+ cairo_set_line_width (cr, 1.0); \
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); \
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+
+G_DEFINE_DYNAMIC_TYPE (TdeGtkEngine, tdegtk_engine, GTK_TYPE_THEMING_ENGINE)
+
+static void
+tdegtk_engine_render_activity (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+ const GtkWidgetPath *path;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+ path = gtk_theming_engine_get_path (engine);
+
+ if (gtk_widget_path_is_type (path, GTK_TYPE_SCALE))
+ tdegtk_trim_scale_allocation (engine, &x, &y, &width, &height);
+
+ if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_SPINNER))
+ GTK_THEMING_ENGINE_CLASS (tdegtk_engine_parent_class)->render_activity (engine, cr, x, y, width, height);
+ else
+ style_functions->draw_activity (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_arrow (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble angle,
+ gdouble x,
+ gdouble y,
+ gdouble size)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ style_functions->draw_arrow (engine, cr, angle, x, y, size);
+}
+
+static void
+tdegtk_engine_render_background (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+ const GtkWidgetPath *path;
+ GtkRegionFlags flags;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+ path = gtk_theming_engine_get_path (engine);
+
+ if (gtk_widget_path_is_type (path, GTK_TYPE_SCALE) &&
+ gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_TROUGH))
+ tdegtk_trim_scale_allocation (engine, &x, &y, &width, &height);
+
+ if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_BUTTON) &&
+ gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_SPINBUTTON))
+ style_functions->draw_spinbutton_background (engine, cr, x, y, width, height);
+ else if (!gtk_widget_path_is_type (path, GTK_TYPE_ICON_VIEW) &&
+ gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_VIEW) &&
+ gtk_theming_engine_has_region (engine, GTK_STYLE_REGION_COLUMN, &flags))
+ style_functions->draw_cell_background (engine, cr, x, y, width, height, flags);
+ else
+ style_functions->draw_common_background (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_check (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ if (!gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_MENUITEM))
+ {
+ if (tdegtk_cairo_draw_from_texture (engine, cr, x, y, width, height))
+ return;
+ }
+
+ style_functions->draw_check (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_expander (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ style_functions->draw_expander (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_extension (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ GtkPositionType gap_side)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ style_functions->draw_extension (engine, cr, x, y, width, height, gap_side);
+}
+
+static void
+tdegtk_engine_render_focus (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ style_functions->draw_focus (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_frame (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+ const GtkWidgetPath *path;
+ GtkRegionFlags flags;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+ path = gtk_theming_engine_get_path (engine);
+
+ if (gtk_widget_path_is_type (path, GTK_TYPE_SCALE) &&
+ gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_TROUGH))
+ tdegtk_trim_scale_allocation (engine, &x, &y, &width, &height);
+
+ if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_SEPARATOR))
+ style_functions->draw_separator (engine, cr, x, y, width, height);
+ else if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_BUTTON) &&
+ gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_SPINBUTTON))
+ style_functions->draw_spinbutton_frame (engine, cr, x, y, width, height);
+ else if (!gtk_widget_path_is_type (path, GTK_TYPE_ICON_VIEW) &&
+ gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_VIEW) &&
+ gtk_theming_engine_has_region (engine, GTK_STYLE_REGION_COLUMN, &flags))
+ style_functions->draw_cell_frame (engine, cr, x, y, width, height, flags);
+ else
+ style_functions->draw_common_frame (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_frame_gap (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ GtkPositionType gap_side,
+ gdouble xy0_gap,
+ gdouble xy1_gap)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_NOTEBOOK))
+ style_functions->draw_notebook (engine, cr, x, y, width, height, gap_side, xy0_gap, xy1_gap);
+ else
+ style_functions->draw_frame_gap (engine, cr, x, y, width, height, gap_side, xy0_gap, xy1_gap);
+}
+
+static void
+tdegtk_engine_render_handle (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_GRIP))
+ style_functions->draw_grip (engine, cr, x, y, width, height);
+ else
+ style_functions->draw_handle (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_line (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x0,
+ gdouble y0,
+ gdouble x1,
+ gdouble y1)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ style_functions->draw_line (engine, cr, x0, y0, x1, y1);
+}
+
+static void
+tdegtk_engine_render_option (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ if (!gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_MENUITEM))
+ {
+ if (tdegtk_cairo_draw_from_texture (engine, cr, x, y, width, height))
+ return;
+ }
+
+ style_functions->draw_radio (engine, cr, x, y, width, height);
+}
+
+static void
+tdegtk_engine_render_slider (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ gdouble width,
+ gdouble height,
+ GtkOrientation orientation)
+{
+ TdeGtkStyleFunctions *style_functions;
+
+ TDEGTK_CAIRO_INIT
+
+ tdegtk_lookup_functions (TDEGTK_ENGINE (engine), &style_functions);
+
+ if (gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_SCALE))
+ {
+ if (tdegtk_cairo_draw_from_texture (engine, cr, x, y, width, height))
+ return;
+ }
+
+ style_functions->draw_slider (engine, cr, x, y, width, height, orientation);
+}
+
+void
+tdegtk_engine_register_types (GTypeModule *module)
+{
+ tdegtk_engine_register_type (module);
+}
+
+static void
+tdegtk_engine_init (TdeGtkEngine *engine)
+{
+ tdegtk_register_style_default (&engine->style_functions[TDEGTK_STYLE_DEFAULT]);
+}
+
+static void
+tdegtk_engine_class_init (TdeGtkEngineClass *klass)
+{
+ GtkThemingEngineClass *engine_class = GTK_THEMING_ENGINE_CLASS (klass);
+
+ engine_class->render_activity = tdegtk_engine_render_activity;
+ engine_class->render_arrow = tdegtk_engine_render_arrow;
+ engine_class->render_background = tdegtk_engine_render_background;
+ engine_class->render_check = tdegtk_engine_render_check;
+ engine_class->render_expander = tdegtk_engine_render_expander;
+ engine_class->render_extension = tdegtk_engine_render_extension;
+ engine_class->render_focus = tdegtk_engine_render_focus;
+ engine_class->render_frame = tdegtk_engine_render_frame;
+ engine_class->render_frame_gap = tdegtk_engine_render_frame_gap;
+ engine_class->render_handle = tdegtk_engine_render_handle;
+ engine_class->render_line = tdegtk_engine_render_line;
+ engine_class->render_option = tdegtk_engine_render_option;
+ engine_class->render_slider = tdegtk_engine_render_slider;
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("background-texture",
+ "Background texture",
+ "Background texture",
+ CAIRO_GOBJECT_TYPE_PATTERN, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("border-gradient",
+ "Border gradient",
+ "Border gradient",
+ CAIRO_GOBJECT_TYPE_PATTERN, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("bullet-color",
+ "Bullet color",
+ "Bullet color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("bullet-outline-color",
+ "Bullet outline color",
+ "Bullet outline color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("centroid-texture",
+ "Centroid texture",
+ "Centroid texture",
+ CAIRO_GOBJECT_TYPE_PATTERN, 0));
+
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("focus-border-color",
+ "Focus border color",
+ "Focus border color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_int ("focus-border-radius",
+ "Focus border radius",
+ "Focus border radius",
+ 0, G_MAXINT, 0, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("focus-fill-color",
+ "Focus fill color",
+ "Focus fill color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("focus-outer-stroke-color",
+ "Focus outer stroke color",
+ "Focus outer stroke color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_int ("glow-radius",
+ "Glow radius",
+ "Glow radius",
+ 0, G_MAXINT, 0, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("glow-color",
+ "Glow color",
+ "Glow color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("inner-stroke-color",
+ "Inner stroke color",
+ "Inner stroke color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("inner-stroke-top-color",
+ "Inner stroke top color",
+ "Inner stroke top color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("inner-stroke-right-color",
+ "Inner stroke right color",
+ "Inner stroke right color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("inner-stroke-bottom-color",
+ "Inner stroke bottom color",
+ "Inner stroke bottom color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("inner-stroke-left-color",
+ "Inner stroke left color",
+ "Inner stroke left color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("inner-stroke-gradient",
+ "Inner stroke gradient",
+ "Inner stroke gradient",
+ CAIRO_GOBJECT_TYPE_PATTERN, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("inner-stroke-width",
+ "Inner stroke width",
+ "Inner stroke width",
+ GTK_TYPE_BORDER, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("outer-stroke-color",
+ "Outer stroke color",
+ "Outer stroke color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("outer-stroke-top-color",
+ "Outer stroke top color",
+ "Outer stroke top color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("outer-stroke-right-color",
+ "Outer stroke right color",
+ "Outer stroke right color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("outer-stroke-bottom-color",
+ "Outer stroke bottom color",
+ "Outer stroke bottom color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("outer-stroke-left-color",
+ "Outer stroke left color",
+ "Outer stroke left color",
+ GDK_TYPE_RGBA, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("outer-stroke-gradient",
+ "Outer stroke gradient",
+ "Outer stroke gradient",
+ CAIRO_GOBJECT_TYPE_PATTERN, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("outer-stroke-width",
+ "Outer stroke width",
+ "Outer stroke width",
+ GTK_TYPE_BORDER, 0));
+
+ gtk_theming_engine_register_property (TDEGTK_NAMESPACE, NULL,
+ g_param_spec_boxed ("text-shadow-color",
+ "Text shadow color",
+ "Text shadow color",
+ GDK_TYPE_RGBA, 0));
+}
+
+static void
+tdegtk_engine_class_finalize (TdeGtkEngineClass *klass)
+{
+}
diff --git a/tdegtk/tdegtk-engine.h b/tdegtk/tdegtk-engine.h
new file mode 100644
index 0000000..fc61402
--- /dev/null
+++ b/tdegtk/tdegtk-engine.h
@@ -0,0 +1,61 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#ifndef TDEGTK_ENGINE_H
+#define TDEGTK_ENGINE_H
+
+#include <gtk/gtk.h>
+
+#include "tdegtk-types.h"
+
+G_BEGIN_DECLS
+
+#define TDEGTK_TYPE_ENGINE (tdegtk_engine_get_type ())
+#define TDEGTK_ENGINE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TDEGTK_TYPE_ENGINE, TdeGtkEngine))
+#define TDEGTK_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TDEGTK_TYPE_ENGINE, TdeGtkEngineClass))
+#define TDEGTK_IS_ENGINE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TDEGTK_TYPE_ENGINE))
+#define TDEGTK_IS_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TDEGTK_TYPE_ENGINE))
+#define TDEGTK_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TDEGTK_TYPE_ENGINE, TdeGtkEngineClass))
+
+typedef struct _TdeGtkEngine TdeGtkEngine;
+typedef struct _TdeGtkEngineClass TdeGtkEngineClass;
+
+struct _TdeGtkEngine
+{
+ GtkThemingEngine parent_instance;
+ TdeGtkStyleFunctions style_functions[TDEGTK_NUM_STYLES];
+ TdeGtkStyles style;
+};
+
+struct _TdeGtkEngineClass
+{
+ GtkThemingEngineClass parent_class;
+ TdeGtkStyleFunctions style_functions[TDEGTK_NUM_STYLES];
+};
+
+G_GNUC_INTERNAL void tdegtk_engine_register_types (GTypeModule *module);
+
+G_GNUC_INTERNAL GType tdegtk_engine_get_type (void);
+
+G_END_DECLS
+
+#endif /* TDEGTK_ENGINE_H */
diff --git a/tdegtk/tdegtk-support.c b/tdegtk/tdegtk-support.c
new file mode 100644
index 0000000..52c161d
--- /dev/null
+++ b/tdegtk/tdegtk-support.c
@@ -0,0 +1,89 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#include <gtk/gtk.h>
+
+#include "tdegtk-engine.h"
+#include "tdegtk-support.h"
+#include "tdegtk-types.h"
+
+gboolean
+tdegtk_gdk_rgba_is_default (GdkRGBA *color)
+{
+ GdkRGBA default_color;
+
+ /* pink is default GdkRGBA color set in gtk/gtkstyleproperty.c */
+ gdk_rgba_parse (&default_color, "pink");
+
+ return gdk_rgba_equal (&default_color, color);
+}
+
+void
+tdegtk_get_line_width (GtkThemingEngine *engine,
+ gdouble *line_width)
+{
+ GtkBorder border;
+ GtkStateFlags state;
+
+ state = gtk_theming_engine_get_state (engine);
+
+ gtk_theming_engine_get_border (engine, state, &border);
+
+ *line_width = MIN (MIN (border.top, border.bottom),
+ MIN (border.left, border.right));
+}
+
+gboolean
+tdegtk_gtk_border_is_zero (GtkBorder *border)
+{
+ return (border->top == 0) && (border->bottom == 0) && (border->left == 0) && (border->right == 0);
+}
+
+void
+tdegtk_lookup_functions (TdeGtkEngine *engine,
+ TdeGtkStyleFunctions **functions)
+{
+ /* only one style is defined now,
+ * add here a check for a theming engine css property,
+ * for example -tdegtk-style, and assign new styles */
+ if (functions)
+ *functions = &engine->style_functions[TDEGTK_STYLE_DEFAULT];
+}
+
+void
+tdegtk_trim_scale_allocation (GtkThemingEngine *engine,
+ gdouble *x,
+ gdouble *y,
+ gdouble *width,
+ gdouble *height)
+{
+ if (!gtk_theming_engine_has_class (engine, GTK_STYLE_CLASS_VERTICAL))
+ {
+ *y += (gint) (*height / 2.0) - 2.0;
+ *height = 5;
+ }
+ else
+ {
+ *x += (gint) (*width / 2.0) - 2.0;
+ *width = 5;
+ }
+}
diff --git a/tdegtk/tdegtk-support.h b/tdegtk/tdegtk-support.h
new file mode 100644
index 0000000..0f4ec07
--- /dev/null
+++ b/tdegtk/tdegtk-support.h
@@ -0,0 +1,51 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#ifndef TDEGTK_SUPPORT_H
+#define TDEGTK_SUPPORT_H
+
+#include <gtk/gtk.h>
+
+#include "tdegtk-engine.h"
+#include "tdegtk-types.h"
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL gboolean tdegtk_gdk_rgba_is_default (GdkRGBA *color);
+
+G_GNUC_INTERNAL void tdegtk_get_line_width (GtkThemingEngine *engine,
+ gdouble *line_width);
+
+G_GNUC_INTERNAL gboolean tdegtk_gtk_border_is_zero (GtkBorder *border);
+
+G_GNUC_INTERNAL void tdegtk_lookup_functions (TdeGtkEngine *engine,
+ TdeGtkStyleFunctions **functions);
+
+G_GNUC_INTERNAL void tdegtk_trim_scale_allocation (GtkThemingEngine *engine,
+ gdouble *x,
+ gdouble *y,
+ gdouble *width,
+ gdouble *height);
+
+G_END_DECLS
+
+#endif /* TDEGTK_SUPPORT_H */
diff --git a/tdegtk/tdegtk-theme.c b/tdegtk/tdegtk-theme.c
new file mode 100644
index 0000000..564a0fd
--- /dev/null
+++ b/tdegtk/tdegtk-theme.c
@@ -0,0 +1,51 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#include <gmodule.h>
+#include <gtk/gtk.h>
+
+#include "tdegtk-engine.h"
+
+G_MODULE_EXPORT void theme_init (GTypeModule *module);
+
+G_MODULE_EXPORT void theme_exit (void);
+
+G_MODULE_EXPORT GtkThemingEngine* create_engine (void);
+
+G_MODULE_EXPORT void
+theme_init (GTypeModule *module)
+{
+ tdegtk_engine_register_types (module);
+}
+
+G_MODULE_EXPORT void
+theme_exit (void)
+{
+}
+
+G_MODULE_EXPORT GtkThemingEngine*
+create_engine (void)
+{
+ return GTK_THEMING_ENGINE (g_object_new (TDEGTK_TYPE_ENGINE,
+ "name", "tdegtk",
+ NULL));
+}
diff --git a/tdegtk/tdegtk-types.h b/tdegtk/tdegtk-types.h
new file mode 100644
index 0000000..ba280d2
--- /dev/null
+++ b/tdegtk/tdegtk-types.h
@@ -0,0 +1,133 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#ifndef TDEGTK_TYPES_H
+#define TDEGTK_TYPES_H
+
+#define DRAW_ARGS GtkThemingEngine *engine, \
+ cairo_t *cr, \
+ gdouble x, \
+ gdouble y, \
+ gdouble width, \
+ gdouble height
+
+G_BEGIN_DECLS
+
+typedef struct _GtkCssBorderCornerRadius GtkCssBorderCornerRadius;
+typedef struct _GtkCssBorderRadius GtkCssBorderRadius;
+
+struct _GtkCssBorderCornerRadius {
+ gdouble horizontal;
+ gdouble vertical;
+};
+
+struct _GtkCssBorderRadius {
+ GtkCssBorderCornerRadius top_left;
+ GtkCssBorderCornerRadius top_right;
+ GtkCssBorderCornerRadius bottom_right;
+ GtkCssBorderCornerRadius bottom_left;
+};
+
+enum {
+ SIDE_LEFT = 1,
+ SIDE_BOTTOM = 1 << 1,
+ SIDE_RIGHT = 1 << 2,
+ SIDE_TOP = 1 << 3,
+ SIDE_ALL = 0xF
+};
+
+typedef enum
+{
+ TDEGTK_STYLE_DEFAULT = 0,
+ TDEGTK_NUM_STYLES = 1
+} TdeGtkStyles;
+
+typedef struct _TdeGtkStyleFunctions TdeGtkStyleFunctions;
+
+struct _TdeGtkStyleFunctions
+{
+ void (*draw_activity) (DRAW_ARGS);
+
+ void (*draw_arrow) (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble angle,
+ gdouble x,
+ gdouble y,
+ gdouble size);
+
+ void (*draw_cell_background) (DRAW_ARGS,
+ GtkRegionFlags flags);
+
+ void (*draw_cell_frame) (DRAW_ARGS,
+ GtkRegionFlags flags);
+
+ void (*draw_check) (DRAW_ARGS);
+
+ void (*draw_common) (DRAW_ARGS);
+
+ void (*draw_common_background) (DRAW_ARGS);
+
+ void (*draw_common_frame) (DRAW_ARGS);
+
+ void (*draw_expander) (DRAW_ARGS);
+
+ void (*draw_extension) (DRAW_ARGS,
+ GtkPositionType gap_side);
+
+ void (*draw_focus) (DRAW_ARGS);
+
+ void (*draw_frame_gap) (DRAW_ARGS,
+ GtkPositionType gap_side,
+ gdouble xy0_gap,
+ gdouble xy1_gap);
+
+ void (*draw_grip) (DRAW_ARGS);
+
+ void (*draw_handle) (DRAW_ARGS);
+
+ void (*draw_line) (GtkThemingEngine *engine,
+ cairo_t *cr,
+ gdouble x0,
+ gdouble y0,
+ gdouble x1,
+ gdouble y1);
+
+ void (*draw_notebook) (DRAW_ARGS,
+ GtkPositionType gap_side,
+ gdouble xy0_gap,
+ gdouble xy1_gap);
+
+ void (*draw_radio) (DRAW_ARGS);
+
+ void (*draw_separator) (DRAW_ARGS);
+
+ void (*draw_slider) (DRAW_ARGS,
+ GtkOrientation orientation);
+
+ void (*draw_spinbutton_background) (DRAW_ARGS);
+
+ void (*draw_spinbutton_frame) (DRAW_ARGS);
+};
+
+G_END_DECLS
+
+#endif /* TDEGTK_TYPES_H */
diff --git a/tdegtk/tdegtk.h b/tdegtk/tdegtk.h
new file mode 100644
index 0000000..5d642f0
--- /dev/null
+++ b/tdegtk/tdegtk.h
@@ -0,0 +1,33 @@
+/* The TdeGtk Theming Engine for Gtk+.
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Authored by Andrea Cimitan <[email protected]>
+ *
+ */
+
+#ifndef TDEGTK_H
+#define TDEGTK_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+G_END_DECLS
+
+#endif /* TDEGTK_H */
+