diff options
Diffstat (limited to 'tdegtk')
-rw-r--r-- | tdegtk/Makefile.am | 31 | ||||
-rw-r--r-- | tdegtk/exponential-blur.c | 288 | ||||
-rw-r--r-- | tdegtk/exponential-blur.h | 37 | ||||
-rw-r--r-- | tdegtk/gtkroundedbox.c | 421 | ||||
-rw-r--r-- | tdegtk/gtkroundedboxprivate.h | 88 | ||||
-rw-r--r-- | tdegtk/raico-blur.c | 173 | ||||
-rw-r--r-- | tdegtk/raico-blur.h | 67 | ||||
-rw-r--r-- | tdegtk/tdegtk-cairo-support.c | 1418 | ||||
-rw-r--r-- | tdegtk/tdegtk-cairo-support.h | 85 | ||||
-rw-r--r-- | tdegtk/tdegtk-draw.c | 1062 | ||||
-rw-r--r-- | tdegtk/tdegtk-draw.h | 36 | ||||
-rw-r--r-- | tdegtk/tdegtk-engine.c | 525 | ||||
-rw-r--r-- | tdegtk/tdegtk-engine.h | 61 | ||||
-rw-r--r-- | tdegtk/tdegtk-support.c | 89 | ||||
-rw-r--r-- | tdegtk/tdegtk-support.h | 51 | ||||
-rw-r--r-- | tdegtk/tdegtk-theme.c | 51 | ||||
-rw-r--r-- | tdegtk/tdegtk-types.h | 133 | ||||
-rw-r--r-- | tdegtk/tdegtk.h | 33 |
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 */ + |