[gnome-builder] gstyle: new lib to handle colors



commit ab5b98b623cd015ccf377b8b406cfcdf3983c736
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Wed Jul 13 21:30:12 2016 +0200

    gstyle: new lib to handle colors
    
    - a color strings lexer/parser
    
    - L*a*b, XYZ, HSV, RGB colorspaces support
    - a color object
    - a palette object
    
    - a color scale widget
    - a color plane widget
    - a eyedropper widget
    - a color swatch widget
    - a color palette widget
    - a color panel widget
    
    - a slidein panel widget
    - a specific revealer for the color panel
    - some assets for the widgets

 configure.ac                                       |    7 +
 contrib/Makefile.am                                |    1 +
 contrib/gstyle/Makefile.am                         |  186 ++
 contrib/gstyle/OVERVIEW.md                         |    4 +
 contrib/gstyle/TODO.md                             |   60 +
 contrib/gstyle/assets/assets-symbolic.svg          |  201 ++
 contrib/gstyle/assets/assets-symbolic.txt          |    3 +
 contrib/gstyle/assets/assets.svg                   | 1109 ++++++++
 contrib/gstyle/assets/assets.txt                   |   15 +
 .../color-scale-slider-horizontal-active.png       |  Bin 0 -> 1134 bytes
 .../color-scale-slider-horizontal-active 2 png     |  Bin 0 -> 1933 bytes
 ...cale-slider-horizontal-backdrop-insensitive.png |  Bin 0 -> 675 bytes
 ...le-slider-horizontal-backdrop-insensitive 2 png |  Bin 0 -> 905 bytes
 .../color-scale-slider-horizontal-backdrop.png     |  Bin 0 -> 678 bytes
 .../color-scale-slider-horizontal-backdrop 2 png   |  Bin 0 -> 909 bytes
 .../assets/color-scale-slider-horizontal-hover.png |  Bin 0 -> 1040 bytes
 .../color-scale-slider-horizontal-hover 2 png      |  Bin 0 -> 1838 bytes
 .../color-scale-slider-horizontal-insensitive.png  |  Bin 0 -> 675 bytes
 ...color-scale-slider-horizontal-insensitive 2 png |  Bin 0 -> 905 bytes
 .../assets/color-scale-slider-horizontal.png       |  Bin 0 -> 1022 bytes
 .../assets/color-scale-slider-horizontal 2 png     |  Bin 0 -> 1900 bytes
 .../assets/color-scale-slider-vertical-active.png  |  Bin 0 -> 820 bytes
 .../color-scale-slider-vertical-active 2 png       |  Bin 0 -> 1577 bytes
 ...-scale-slider-vertical-backdrop-insensitive.png |  Bin 0 -> 548 bytes
 ...cale-slider-vertical-backdrop-insensitive 2 png |  Bin 0 -> 878 bytes
 .../color-scale-slider-vertical-backdrop.png       |  Bin 0 -> 533 bytes
 .../color-scale-slider-vertical-backdrop 2 png     |  Bin 0 -> 881 bytes
 .../assets/color-scale-slider-vertical-hover.png   |  Bin 0 -> 796 bytes
 .../assets/color-scale-slider-vertical-hover 2 png |  Bin 0 -> 1483 bytes
 .../color-scale-slider-vertical-insensitive.png    |  Bin 0 -> 548 bytes
 .../color-scale-slider-vertical-insensitive 2 png  |  Bin 0 -> 878 bytes
 .../gstyle/assets/color-scale-slider-vertical.png  |  Bin 0 -> 779 bytes
 .../assets/color-scale-slider-vertical 2 png       |  Bin 0 -> 1500 bytes
 contrib/gstyle/assets/eyedropper-symbolic.svg      |  111 +
 contrib/gstyle/assets/render-assets-symbolic.py    |   50 +
 contrib/gstyle/assets/render-assets.sh             |   34 +
 contrib/gstyle/assets/unit-degree-symbolic.svg     |   96 +
 contrib/gstyle/assets/unit-percent-symbolic.svg    |  106 +
 contrib/gstyle/check-palette.sh                    |   17 +
 contrib/gstyle/colorlexer-regen.sh                 |   38 +
 contrib/gstyle/data/palettes/basic.xml             |   32 +
 contrib/gstyle/data/palettes/palette.rng           |  134 +
 contrib/gstyle/gstyle-animation.c                  |   51 +
 contrib/gstyle/gstyle-animation.h                  |   31 +
 contrib/gstyle/gstyle-cielab.c                     |   64 +
 contrib/gstyle/gstyle-cielab.h                     |   45 +
 contrib/gstyle/gstyle-color-component.c            |   50 +
 contrib/gstyle/gstyle-color-component.h            |   45 +
 contrib/gstyle/gstyle-color-convert.c              |  843 ++++++
 contrib/gstyle/gstyle-color-convert.h              |   75 +
 contrib/gstyle/gstyle-color-filter.c               |   42 +
 contrib/gstyle/gstyle-color-filter.h               |   36 +
 contrib/gstyle/gstyle-color-item.c                 |  209 ++
 contrib/gstyle/gstyle-color-item.h                 |   58 +
 contrib/gstyle/gstyle-color-panel-actions.c        |   84 +
 contrib/gstyle/gstyle-color-panel-actions.h        |   32 +
 contrib/gstyle/gstyle-color-panel-private.h        |  151 +
 contrib/gstyle/gstyle-color-panel.c                | 1465 ++++++++++
 contrib/gstyle/gstyle-color-panel.h                |   79 +
 contrib/gstyle/gstyle-color-plane.c                | 1648 +++++++++++
 contrib/gstyle/gstyle-color-plane.h                |   89 +
 contrib/gstyle/gstyle-color-predefined.h           |  189 ++
 contrib/gstyle/gstyle-color-scale.c                |  738 +++++
 contrib/gstyle/gstyle-color-scale.h                |   78 +
 contrib/gstyle/gstyle-color-widget.c               | 1252 ++++++++
 contrib/gstyle/gstyle-color-widget.h               |   71 +
 contrib/gstyle/gstyle-color.c                      | 1305 +++++++++
 contrib/gstyle/gstyle-color.h                      |  110 +
 contrib/gstyle/gstyle-colorlexer.c                 | 3002 ++++++++++++++++++++
 contrib/gstyle/gstyle-colorlexer.h                 |   48 +
 contrib/gstyle/gstyle-colorlexer.re                |  142 +
 contrib/gstyle/gstyle-css-provider.c               |  158 +
 contrib/gstyle/gstyle-css-provider.h               |   37 +
 contrib/gstyle/gstyle-eyedropper.c                 |  400 +++
 contrib/gstyle/gstyle-eyedropper.h                 |   35 +
 contrib/gstyle/gstyle-hsv.c                        |   64 +
 contrib/gstyle/gstyle-hsv.h                        |   45 +
 contrib/gstyle/gstyle-palette-widget.c             | 1454 ++++++++++
 contrib/gstyle/gstyle-palette-widget.h             |   83 +
 contrib/gstyle/gstyle-palette.c                    | 1134 ++++++++
 contrib/gstyle/gstyle-palette.h                    |   86 +
 contrib/gstyle/gstyle-private.h                    |   31 +
 contrib/gstyle/gstyle-revealer.c                   |  341 +++
 contrib/gstyle/gstyle-revealer.h                   |   37 +
 contrib/gstyle/gstyle-slidein.c                    | 1328 +++++++++
 contrib/gstyle/gstyle-slidein.h                    |   64 +
 contrib/gstyle/gstyle-types.h                      |   34 +
 contrib/gstyle/gstyle-utils.c                      |  172 ++
 contrib/gstyle/gstyle-utils.h                      |   93 +
 contrib/gstyle/gstyle-xyz.c                        |   64 +
 contrib/gstyle/gstyle-xyz.h                        |   45 +
 contrib/gstyle/gstyle.gresource.xml                |   40 +
 contrib/gstyle/tests/Makefile.am                   |   94 +
 contrib/gstyle/tests/data/gstyle-color-editor.ui   |  280 ++
 contrib/gstyle/tests/data/palette.gpl              |  142 +
 contrib/gstyle/tests/data/palette.xml              |   32 +
 contrib/gstyle/tests/test-gstyle-color-panel.c     |   78 +
 contrib/gstyle/tests/test-gstyle-color-plane.c     |  142 +
 contrib/gstyle/tests/test-gstyle-color-scale.c     |   70 +
 contrib/gstyle/tests/test-gstyle-color-widget.c    |   85 +
 contrib/gstyle/tests/test-gstyle-color.c           |  397 +++
 contrib/gstyle/tests/test-gstyle-palette-widget.c  |   76 +
 contrib/gstyle/tests/test-gstyle-palette.c         |   74 +
 contrib/gstyle/tests/test-gstyle-parse.c           |  152 +
 contrib/gstyle/theme/gstyle.css                    |  120 +
 contrib/gstyle/ui/gstyle-color-panel.ui            | 1011 +++++++
 contrib/gstyle/ui/gstyle-palette-widget.ui         |  106 +
 po/POTFILES.in                                     |    4 +
 108 files changed, 22844 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index a4a02a1..94b4e56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -198,6 +198,9 @@ PKG_CHECK_MODULES(EGG,      [glib-2.0 >= glib_required_version
 PKG_CHECK_MODULES(GD,       [gtk+-3.0 >= gtk_required_version])
 PKG_CHECK_MODULES(GEDIT,    [glib-2.0 >= glib_required_version
                              gtk+-3.0 >= gtk_required_version])
+PKG_CHECK_MODULES(GSTYLE,   [glib-2.0 >= glib_required_version
+                             gtk+-3.0 >= gtk_required_version
+                             gtksourceview-3.0 >= gtksourceview_required_version])
 PKG_CHECK_MODULES(ICONS,    [gio-2.0 >= glib_required_version])
 PKG_CHECK_MODULES(LIBIDE,   [gio-2.0 >= glib_required_version
                              gio-unix-2.0 >= glib_required_version
@@ -443,6 +446,7 @@ PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_builddir)/contrib/pnl"
 PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_builddir)/libide"
 PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_srcdir)/contrib/egg"
 PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_srcdir)/contrib/gd"
+PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_srcdir)/contrib/gstyle"
 PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_srcdir)/contrib/nautilus"
 PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_srcdir)/contrib/pnl"
 PLUGIN_CFLAGS="$PLUGIN_CFLAGS -I\$(top_srcdir)/contrib/rg"
@@ -464,6 +468,7 @@ PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --target-glib=2.44"
 PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --thread"
 PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --vapidir \$(top_builddir)/libide"
 PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --vapidir \$(top_builddir)/contrib/egg"
+PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --vapidir \$(top_builddir)/contrib/gstyle"
 PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --vapidir \$(top_builddir)/contrib/pnl"
 PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --vapidir \$(top_builddir)/contrib/tmpl"
 PLUGIN_VALAFLAGS="$PLUGIN_VALAFLAGS --pkg libide-1.0"
@@ -483,6 +488,8 @@ AC_CONFIG_FILES([
        contrib/Makefile
        contrib/egg/Makefile
        contrib/gd/Makefile
+       contrib/gstyle/Makefile
+       contrib/gstyle/tests/Makefile
        contrib/libeditorconfig/Makefile
        contrib/nautilus/Makefile
        contrib/pnl/Makefile
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
index 516886b..b7169b0 100644
--- a/contrib/Makefile.am
+++ b/contrib/Makefile.am
@@ -6,6 +6,7 @@ SUBDIRS = \
        pnl \
        rg \
        search \
+       gstyle \
        tmpl \
        xml \
        $(NULL)
diff --git a/contrib/gstyle/Makefile.am b/contrib/gstyle/Makefile.am
new file mode 100644
index 0000000..ba9f636
--- /dev/null
+++ b/contrib/gstyle/Makefile.am
@@ -0,0 +1,186 @@
+CLEANFILES =
+DISTCLEANFILES =
+EXTRA_DIST =
+BUILT_SOURCES =
+
+SUBDIRS = . tests
+
+pkglibdir = $(libdir)/gnome-builder
+pkglib_LTLIBRARIES = libgstyle-private.la
+
+headersdir = $(includedir)/gnome-builder-@VERSION@/gstyle
+headers_DATA =                       \
+       gstyle-animation.h           \
+       gstyle-cielab.h              \
+       gstyle-color.h               \
+       gstyle-color-component.h     \
+       gstyle-color-convert.h       \
+       gstyle-color-filter.h        \
+       gstyle-color-item.h          \
+       gstyle-color-panel.h         \
+       gstyle-color-panel-private.h \
+       gstyle-color-panel-actions.h \
+       gstyle-color-plane.h         \
+       gstyle-color-predefined.h    \
+       gstyle-color-scale.h         \
+       gstyle-color-widget.h        \
+       gstyle-colorlexer.h          \
+       gstyle-css-provider.h        \
+       gstyle-eyedropper.h          \
+       gstyle-hsv.h                 \
+       gstyle-palette.h             \
+       gstyle-palette-widget.h      \
+       gstyle-private.h             \
+       gstyle-revealer.c            \
+       gstyle-slidein.h             \
+       gstyle-types.h               \
+       gstyle-utils.h               \
+       gstyle-xyz.h                 \
+       $(NULL)
+
+libgstyle_private_la_SOURCES =       \
+       $(headers_DATA)              \
+       gstyle-animation.c           \
+       gstyle-cielab.c              \
+       gstyle-color.c               \
+       gstyle-color-component.c     \
+       gstyle-color-convert.c       \
+       gstyle-color-filter.c        \
+       gstyle-color-item.c          \
+       gstyle-color-panel.c         \
+       gstyle-color-panel-actions.c \
+       gstyle-color-plane.c         \
+       gstyle-color-scale.c         \
+       gstyle-color-widget.c        \
+       gstyle-colorlexer.c          \
+       gstyle-css-provider.c        \
+       gstyle-eyedropper.c          \
+       gstyle-hsv.c                 \
+       gstyle-palette.c             \
+       gstyle-palette-widget.c      \
+       gstyle-revealer.h            \
+       gstyle-slidein.c             \
+       gstyle-utils.c               \
+       gstyle-xyz.c                 \
+       $(NULL)
+
+libgstyle_private_la_CFLAGS =            \
+       $(GSTYLE_CFLAGS)                 \
+       $(XML_CFLAGS)                    \
+       $(DEBUG_CFLAGS)                  \
+       $(OPTIMIZE_CFLAGS)               \
+       -I$(top_srcdir)/contrib/search   \
+       -I$(top_builddir)/contrib/search \
+       $(NULL)
+
+libgstyle_private_la_LIBADD =                       \
+       $(GSTYLE_LIBS)                              \
+       $(XML_LIBS)                                 \
+       $(top_builddir)/contrib/search/libsearch.la \
+       $(NULL)
+
+libgstyle_private_la_LDFLAGS = \
+       $(OPTIMIZE_LDFLAGS)    \
+       --no-undefined         \
+       $(NULL)
+
+nodist_libgstyle_private_la_SOURCES = \
+       gstyle-resources.c            \
+       gstyle-resources.h            \
+       $(NULL)
+
+glib_resources_h = gstyle-resources.h
+glib_resources_c = gstyle-resources.c
+glib_resources_xml = gstyle.gresource.xml
+glib_resources_namespace = gstyle
+include $(top_srcdir)/build/autotools/Makefile.am.gresources
+
+
+if HAVE_INTROSPECTION
+-include $(INTROSPECTION_MAKEFILE)
+
+INTROSPECTION_GIRS =
+INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --warn-all
+INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
+
+introspection_sources =          \
+       gstyle-cielab.h          \
+       gstyle-cielab.c          \
+       gstyle-color.h           \
+       gstyle-color.c           \
+       gstyle-color-component.h \
+       gstyle-color-component.c \
+       gstyle-color-convert.h   \
+       gstyle-color-convert.c   \
+       gstyle-color-filter.h    \
+       gstyle-color-filter.c    \
+       gstyle-color-item.h      \
+       gstyle-color-item.c      \
+       gstyle-color-panel.h     \
+       gstyle-color-panel.c     \
+       gstyle-color-plane.h     \
+       gstyle-color-plane.c     \
+       gstyle-color-scale.h     \
+       gstyle-color-scale.c     \
+       gstyle-color-widget.h    \
+       gstyle-color-widget.c    \
+       gstyle-eyedropper.h      \
+       gstyle-eyedropper.c      \
+       gstyle-hsv.h             \
+       gstyle-hsv.c             \
+       gstyle-palette.h         \
+       gstyle-palette.c         \
+       gstyle-palette-widget.h  \
+       gstyle-palette-widget.c  \
+       gstyle-slidein.h         \
+       gstyle-slidein.c         \
+       gstyle-xyz.h             \
+       gstyle-xyz.c             \
+       $(NULL)
+
+Gstyle-1.0.gir: libgstyle-private.la
+Gstyle_1_0_gir_INCLUDES = Gio-2.0 Gdk-3.0 Gtk-3.0 GtkSource-3.0
+Gstyle_1_0_gir_CFLAGS = $(libgstyle_private_la_CFLAGS)
+Gstyle_1_0_gir_LIBS = libgstyle-private.la
+Gstyle_1_0_gir_FILES = $(introspection_sources)
+Gstyle_1_0_gir_SCANNERFLAGS =          \
+       --c-include="gstyle-private.h" \
+       -n Gstyle                      \
+       --identifier-prefix Gstyle     \
+       --symbol-prefix gstyle         \
+       $(NULL)
+INTROSPECTION_GIRS += Gstyle-1.0.gir
+
+girdir = $(datadir)/gnome-builder/gir-1.0
+dist_gir_DATA = $(INTROSPECTION_GIRS)
+
+typelibdir = $(pkglibdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES += $(dist_gir_DATA) $(typelib_DATA)
+endif
+
+
+if ENABLE_VAPIGEN
+-include $(VAPIGEN_MAKEFILE)
+
+gstyle-private.vapi: Gstyle-1.0.gir
+
+VAPIGEN_VAPIS = gstyle-private.vapi
+
+gstyle_private_vapi_DEPS = gio-2.0 gtk+-3.0 GtkSource-3.0
+gstyle_private_vapi_METADATADIRS = $(srcdir)
+gstyle_private_vapi_FILES = Gstyle-1.0.gir
+
+gstyle-private.deps: Makefile
+       $(AM_V_GEN) echo $(libgstyle_private_vapi_DEPS) | tr ' ' '\n' > $@
+
+vapidir = $(datadir)/gnome-builder/vapi
+vapi_DATA = $(VAPIGEN_VAPIS) $(VAPIGEN_VAPIS:.vapi=.deps)
+
+EXTRA_DIST += gstyle-private.deps
+
+DISTCLEANFILES += $(vapi_DATA)
+endif
+
+-include $(top_srcdir)/git.mk
diff --git a/contrib/gstyle/OVERVIEW.md b/contrib/gstyle/OVERVIEW.md
new file mode 100644
index 0000000..618d044
--- /dev/null
+++ b/contrib/gstyle/OVERVIEW.md
@@ -0,0 +1,4 @@
+# Dependencies :
+
+In the current state, GStyle is dependent of a few Gnome Builder contrib parts:
+  - fuzzy.h is used by the search color string entry.
diff --git a/contrib/gstyle/TODO.md b/contrib/gstyle/TODO.md
new file mode 100644
index 0000000..abd7480
--- /dev/null
+++ b/contrib/gstyle/TODO.md
@@ -0,0 +1,60 @@
+#TODO list :
+
+## Enhancements :
+
+### Color :
+- add HSL, HWB and CMYK.
+- add illuminant management.
+
+### Color widget :
+- fix border-radius calculation, result different than the one used by gtk+.
+
+### Color plane :
+- add circle cursor.
+- icon for out-of-gamut color.
+- use filtering framework (reduce set of colors like websafe and colorblindness amongst others)
+
+### Panel :
+- add a horizontal displayed mode ?
+- add a mini-picker mode to be displayed in a popover at cursor position.
+
+### Palettes :
+- add more load/save formats :
+  - including the gtksourceview style scheme : filter the unneeded part but keep it for save it again.
+- allow scroll when drag at the end of list (both list or flow mode).
+
+### CSS parser :
+- add color functions parsing:
+  - darker, lighter, mix, alpha.
+
+### Sort :
+- sort by various mode:
+  - by name.
+  - by light.
+  - by hue.
+
+- sort relative to the selected color:
+  - by approching color deltaE.2000 (calculation already in gstyle)
+
+  Do sorting change the saved order of colors or just the view ?
+
+### Drag'n drop :
+- dnd-lock: a lock-symbolic lock icon.
+
+### Slidein :
+- add optional right click to close the slidein (property).
+- is it possible to not close the slidein when dragging the paned border to extend the panel ?
+
+### Color plane :
+- fix cursor visibility on border when using the sliders.
+
+### Tests :
+- make them real test, not just result output.
+- fix panel test to use prefs pages.
+- fix palette widget test to be able to select a palette.
+
+## FIXES :
+
+### Theme :
+- add a dark theme.
+- add backdrop state.
diff --git a/contrib/gstyle/assets/assets-symbolic.svg b/contrib/gstyle/assets/assets-symbolic.svg
new file mode 100644
index 0000000..fbf46b6
--- /dev/null
+++ b/contrib/gstyle/assets/assets-symbolic.svg
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="744.09448"
+   height="1052.3622"
+   viewBox="0 0 744.09449 1052.3622"
+   id="svg4370"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="assets-symbolic.svg">
+  <defs
+     id="defs4372">
+    <inkscape:path-effect
+       effect="spiro"
+       id="path-effect4178"
+       is_visible="true" />
+    <linearGradient
+       id="linearGradient4418">
+      <stop
+         id="stop4420"
+         offset="0"
+         style="stop-color:#f4f4f4;stop-opacity:1" />
+      <stop
+         style="stop-color:#f4f4f4;stop-opacity:1"
+         offset="0.2"
+         id="stop4422" />
+      <stop
+         id="stop4424"
+         offset="1"
+         style="stop-color:#bce8e7;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="killme">
+      <stop
+         id="stop5583-0-92-8-0-7-6"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1" />
+      <stop
+         style="stop-color:#ededed;stop-opacity:1"
+         offset="0.40000001"
+         id="stop5585-4-7-2-7-9-9" />
+      <stop
+         id="stop5587-6-7-2-0-3-1"
+         offset="1"
+         style="stop-color:#41d3d3;stop-opacity:1" />
+    </linearGradient>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#3a3b39"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32"
+     inkscape:cx="342.95481"
+     inkscape:cy="870.42534"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1016"
+     inkscape:window-x="1920"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-bbox-midpoints="true"
+     units="px"
+     showborder="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:object-nodes="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4918"
+       empcolor="#3ff5ff"
+       empopacity="0.56862745"
+       color="#36ebff"
+       opacity="0.32941176"
+       dotted="false" />
+    <sodipodi:guide
+       position="304.55984,863.01144"
+       orientation="1,0"
+       id="guide4174" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata4375">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       id="unit-percent-symbolic"
+       inkscape:label="#g4167"
+       transform="translate(0.12253463,0)">
+      <circle
+         style="fill:none;fill-rule:evenodd;stroke:#bebebe;stroke-width:0.89999998"
+         id="circle7700"
+         cx="340.18726"
+         cy="160.54944"
+         r="2.7372432" />
+      <ellipse
+         cy="168.16022"
+         cx="344.80249"
+         id="ellipse7702"
+         style="fill:none;fill-rule:evenodd;stroke:#bebebe;stroke-width:0.90353149"
+         rx="2.74575"
+         ry="2.7502201" />
+      <path
+         style="fill:none;fill-rule:evenodd;stroke:#bebebe;stroke-width:0.71361196;stroke-linecap:round"
+         d="m 338,170.3622 9,-12"
+         id="path7704"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cc" />
+      <rect
+         y="156.3622"
+         x="336"
+         height="16"
+         width="13"
+         id="rect9598"
+         style="fill:none;fill-opacity:0.2118644;fill-rule:evenodd;stroke-width:0;stroke-linecap:round" />
+    </g>
+    <g
+       transform="translate(696,388.00002)"
+       id="unit-degree-symbolic"
+       inkscape:label="#g9611">
+      <circle
+         r="2.7372432"
+         cy="-227.45058"
+         cx="-335.81274"
+         id="circle7708"
+         style="fill:none;fill-rule:evenodd;stroke:#bebebe;stroke-width:0.89999998" />
+      <rect
+         y="-231.63782"
+         x="-340"
+         height="16"
+         width="13"
+         id="rect9609"
+         style="fill:none;fill-opacity:0.2118644;fill-rule:evenodd;stroke-width:0;stroke-linecap:round" />
+    </g>
+    <g
+       id="eyedropper-symbolic"
+       transform="translate(20.625,-0.6875)"
+       inkscape:label="#g4291">
+      <path
+         sodipodi:nodetypes="ccc"
+         inkscape:connector-curvature="0"
+         id="path4190"
+         d="m 325.08221,181.00746 -9.39652,9.37044 c -0.0593,0.19104 -0.13503,0.70852 -0.31608,1.83278"
+         
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.85961121;stroke-linecap:round;stroke-linejoin:round"
 />
+      <path
+         d="m 330.01187,178.39722 c 0.50034,0.49896 0.72124,1.67539 0.18776,2.20739 l -1.42563,1.42167 m 
1.23974,-3.62719 c -0.50034,-0.49896 -1.67528,-0.7145 -2.20877,-0.18249 l -1.42563,1.42168"
+         style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.85961121"
+         id="path4194"
+         inkscape:connector-curvature="0" />
+      <path
+         id="path4196"
+         style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.36000001"
+         d="m 327.65392,180.74863 1.99551,2.00859 c 0.74951,0.75441 -0.0403,1.57988 -0.81777,0.81834 l 
-1.96434,-1.93901 m 0.79322,-0.88131 -2.00702,-1.95616 c -0.76156,-0.74225 -1.61765,0.0175 -0.854,0.79288 l 
2.0678,2.04459"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cscccscc" />
+      <path
+         
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.85961121;stroke-linecap:round;stroke-linejoin:round"
+         d="m 327.40101,183.31981 -9.39654,9.37046 c -0.2369,0.13014 -0.79628,0.1733 -1.81098,0.35543"
+         id="path4198"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="ccc" />
+      <path
+         sodipodi:nodetypes="cccccc"
+         inkscape:connector-curvature="0"
+         id="path4210"
+         d="m 316.6416,191.77213 0.0909,-0.72459 c 1.08126,-1.05238 2.4727,-2.56936 3.19187,-3.26065 l 
1.33643,-6e-5 -3.91848,3.9076 z"
+         
style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.05546677;stroke-linecap:square;stroke-linejoin:round"
 />
+    </g>
+  </g>
+</svg>
diff --git a/contrib/gstyle/assets/assets-symbolic.txt b/contrib/gstyle/assets/assets-symbolic.txt
new file mode 100644
index 0000000..a648724
--- /dev/null
+++ b/contrib/gstyle/assets/assets-symbolic.txt
@@ -0,0 +1,3 @@
+eyedropper-symbolic
+unit-percent-symbolic
+unit-degree-symbolic
diff --git a/contrib/gstyle/assets/assets.svg b/contrib/gstyle/assets/assets.svg
new file mode 100644
index 0000000..aee0824
--- /dev/null
+++ b/contrib/gstyle/assets/assets.svg
@@ -0,0 +1,1109 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="1000"
+   height="1052.3622"
+   id="svg9892"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="assets.svg">
+  <defs
+     id="defs9894">
+    <linearGradient
+       id="linearGradient4418">
+      <stop
+         id="stop4420"
+         offset="0"
+         style="stop-color:#f4f4f4;stop-opacity:1" />
+      <stop
+         style="stop-color:#f4f4f4;stop-opacity:1"
+         offset="0.2"
+         id="stop4422" />
+      <stop
+         id="stop4424"
+         offset="1"
+         style="stop-color:#bce8e7;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4402">
+      <stop
+         id="stop4404"
+         offset="0"
+         style="stop-color:#f4f4f4;stop-opacity:1" />
+      <stop
+         style="stop-color:#f4f4f4;stop-opacity:1"
+         offset="0.57427853"
+         id="stop4406" />
+      <stop
+         id="stop4408"
+         offset="1"
+         style="stop-color:#e8e8e7;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="dark-normal">
+      <stop
+         style="stop-color:#323737;stop-opacity:1"
+         offset="0"
+         id="stop5208" />
+      <stop
+         id="stop5210"
+         offset="0.2"
+         style="stop-color:#323737;stop-opacity:1" />
+      <stop
+         style="stop-color:#2a2f2f;stop-opacity:1"
+         offset="1"
+         id="stop5212" />
+    </linearGradient>
+    <linearGradient
+       id="light-hover">
+      <stop
+         id="stop4868"
+         offset="0"
+         style="stop-color:#fefefe;stop-opacity:1" />
+      <stop
+         style="stop-color:#fefefe;stop-opacity:1"
+         offset="0.1"
+         id="stop4870" />
+      <stop
+         id="stop4872"
+         offset="1"
+         style="stop-color:#f2f2f1;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="light-normal">
+      <stop
+         style="stop-color:#f4f4f4;stop-opacity:1"
+         offset="0"
+         id="stop4604" />
+      <stop
+         id="stop4610"
+         offset="0.2"
+         style="stop-color:#f4f4f4;stop-opacity:1" />
+      <stop
+         style="stop-color:#e8e8e7;stop-opacity:1"
+         offset="1"
+         id="stop4608" />
+    </linearGradient>
+    <linearGradient
+       id="killme">
+      <stop
+         id="stop5583-0-92-8-0-7-6"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1" />
+      <stop
+         style="stop-color:#ededed;stop-opacity:1;"
+         offset="0.40000001"
+         id="stop5585-4-7-2-7-9-9" />
+      <stop
+         id="stop5587-6-7-2-0-3-1"
+         offset="1"
+         style="stop-color:#41d3d3;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="dark-hover">
+      <stop
+         id="stop5583-0-92-8-0-7-6-5-1-2-9-5"
+         offset="0"
+         style="stop-color:#393f3f;stop-opacity:1" />
+      <stop
+         style="stop-color:#393f3f;stop-opacity:1"
+         offset="0.2"
+         id="stop5585-4-7-2-7-9-9-92-0-5-3-7" />
+      <stop
+         id="stop5587-6-7-2-0-3-1-21-5-7-8-21"
+         offset="1"
+         style="stop-color:#2f3434;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient8949"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient8951"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient8983"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient8985"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9001"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9003"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-normal"
+       id="linearGradient9019"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9021"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-normal"
+       id="linearGradient9037"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9039"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9063"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9065"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9444"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9446"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9448"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9450"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-normal"
+       id="linearGradient9452"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9454"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-normal"
+       id="linearGradient9456"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9458"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9460"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9462"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9464"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-3.911093e-8,-0.58023095)"
+       x1="140.5"
+       y1="50.895367"
+       x2="159.53287"
+       y2="50.895367" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#light-hover"
+       id="linearGradient9466"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-0.50000004,0.40593305)"
+       x1="140.5"
+       y1="49.909203"
+       x2="160.53281"
+       y2="49.909203" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8754325"
+     inkscape:cx="218"
+     inkscape:cy="1083.5"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     showborder="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1016"
+     inkscape:window-x="1920"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:snap-nodes="true"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:snap-global="true"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:bbox-nodes="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-bbox-midpoints="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-to-guides="false"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-center="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid10919"
+       empspacing="4"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       dotted="false"
+       color="#ae00e9"
+       opacity="0.4627451"
+       empcolor="#3f3fff"
+       empopacity="1" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata9897">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     id="layer3"
+     inkscape:label="superbackdrop"
+     style="display:none"
+     sodipodi:insensitive="true">
+    <rect
+       ry="0"
+       rx="0"
+       y="-192.36218"
+       x="40"
+       height="440"
+       width="392.87714"
+       id="rect18028"
+       
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;marker:none;enable-background:accumulate"
+       transform="scale(1,-1)" />
+    <rect
+       
style="opacity:0.84299999;fill:#3dd3d3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4337"
+       width="24"
+       height="24"
+       x="220"
+       y="-72.637817" />
+    <rect
+       y="-72.637817"
+       x="250"
+       height="24"
+       width="24"
+       id="rect4339"
+       
style="opacity:0.84299999;fill:#3dd3d3;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 />
+    <rect
+       transform="scale(1,-1)"
+       
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#3a3b39;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;marker:none;enable-background:accumulate"
+       id="rect7688"
+       width="392.87714"
+       height="440"
+       x="-370"
+       y="-192.36218"
+       rx="0"
+       ry="0" />
+  </g>
+  <g
+     inkscape:label="assets"
+     inkscape:groupmode="layer"
+     id="layer1"
+     style="display:inline">
+    <g
+       inkscape:label="#g10801"
+       transform="matrix(1.9947791,0,0,1.9939719,354.38167,165.09433)"
+       id="sjhgfjsgf" />
+    <g
+       id="color-scale-slider-horizontal-hover"
+       inkscape:label="#g9085">
+      <g
+         transform="translate(-42,27)"
+         id="g8969">
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path8971"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path8973"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient8983);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8985);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           id="path8975"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path8977"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path8979"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           id="path8981"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+      </g>
+      <g
+         id="g8987"
+         transform="matrix(-1,0,0,1,300,27)">
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           id="path8989"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9001);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9003);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           id="path8991"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path8993"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           id="path8995"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           id="path8997"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path8999"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+      </g>
+    </g>
+    <g
+       id="color-scale-slider-horizontal"
+       inkscape:label="#g9101">
+      <g
+         id="g9005"
+         transform="translate(-42,52)">
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           id="path9007"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9019);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9021);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           id="path9009"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9011"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           id="path9013"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           id="path9015"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9017"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+      </g>
+      <g
+         transform="matrix(-1,0,0,1,300,52)"
+         id="g9023">
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9025"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9027"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9037);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9039);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           id="path9029"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9031"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9033"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           id="path9035"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+      </g>
+    </g>
+    <g
+       id="color-scale-slider-horizontal-active"
+       inkscape:label="#g9067">
+      <g
+         id="g8935"
+         transform="translate(-42,4.9574055e-8)">
+        <g
+           id="g8955">
+          <path
+             sodipodi:nodetypes="cccc"
+             inkscape:connector-curvature="0"
+             id="path8937"
+             d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+          <path
+             sodipodi:nodetypes="cccc"
+             inkscape:connector-curvature="0"
+             id="path8939"
+             d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient8949);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient8951);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+          <path
+             
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+             d="m 157.30918,49.331217 -16.68331,8.352699"
+             id="path8941"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cc" />
+          <path
+             sodipodi:nodetypes="cc"
+             inkscape:connector-curvature="0"
+             id="path8943"
+             d="m 140.53991,42.100327 18.23961,8.813092"
+             
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+          <path
+             sodipodi:nodetypes="cc"
+             inkscape:connector-curvature="0"
+             id="path8945"
+             d="m 158.41403,49.861543 -17.78816,8.927223"
+             
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+          <path
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#184472;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+             d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+             id="path8947"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cccc" />
+        </g>
+      </g>
+      <g
+         transform="matrix(-1,0,0,1,300,4.9574055e-8)"
+         id="g9047">
+        <g
+           id="g9049">
+          <path
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+             d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+             id="path9051"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cccc" />
+          <path
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9063);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9065);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+             d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+             id="path9053"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cccc" />
+          <path
+             sodipodi:nodetypes="cc"
+             inkscape:connector-curvature="0"
+             id="path9055"
+             d="m 157.30918,49.331217 -16.68331,8.352699"
+             
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+          <path
+             
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+             d="m 140.53991,42.100327 18.23961,8.813092"
+             id="path9057"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cc" />
+          <path
+             
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+             d="m 158.41403,49.861543 -17.78816,8.927223"
+             id="path9059"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cc" />
+          <path
+             sodipodi:nodetypes="cccc"
+             inkscape:connector-curvature="0"
+             id="path9061"
+             d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#184472;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        </g>
+      </g>
+    </g>
+    <g
+       id="color-scale-slider-horizontal-insensitive"
+       inkscape:label="#g9311">
+      <path
+         sodipodi:nodetypes="cccc"
+         inkscape:connector-curvature="0"
+         id="path9135"
+         d="M 117.53286,24.287412 98.5,14.862152 98.5107,33.768116 Z"
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+      <path
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+         d="M 140.46714,24.287412 159.5,14.862152 159.4893,33.768116 Z"
+         id="path9151"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cccc" />
+    </g>
+    <g
+       id="color-scale-slider-horizontal-backdrop"
+       inkscape:label="#g9321">
+      <path
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#e8e8e7;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+         d="M 117.53286,-3.712588 98.5,-13.137848 98.5107,5.768116 Z"
+         id="path9303"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cccc" />
+      <path
+         inkscape:label="#path9305"
+         sodipodi:nodetypes="cccc"
+         inkscape:connector-curvature="0"
+         id="path9304"
+         d="M 140.46714,-3.712588 159.5,-13.137848 159.4893,5.768116 Z"
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#e8e8e7;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+    </g>
+    <g
+       id="color-scale-slider-horizontal-backdrop-insensitive"
+       inkscape:label="#g9325">
+      <g
+         transform="translate(0,-56)"
+         id="g9315"
+         inkscape:label="#g9311">
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9317"
+           d="M 117.53286,24.287412 98.5,14.862152 98.5107,33.768116 Z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 140.46714,24.287412 159.5,14.862152 159.4893,33.768116 Z"
+           id="path9319"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+      </g>
+    </g>
+    <g
+       inkscape:label="#g9085"
+       id="color-scale-slider-vertical-hover"
+       transform="matrix(0,1,-1,0,296.36218,-273.63782)">
+      <g
+         id="g9332"
+         transform="translate(-42,27)">
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           id="path9334"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9444);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9446);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           id="path9336"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9338"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           id="path9340"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           id="path9342"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9344"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+      </g>
+      <g
+         transform="matrix(-1,0,0,1,300,27)"
+         id="g9346">
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9348"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9350"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9448);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9450);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           id="path9352"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9354"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9356"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           id="path9358"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+      </g>
+    </g>
+    <g
+       inkscape:label="#g9101"
+       id="color-scale-slider-vertical"
+       transform="matrix(0,1,-1,0,296.36218,-273.63782)">
+      <g
+         transform="translate(-42,52)"
+         id="g9362">
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9364"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9366"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9452);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9454);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        <path
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           id="path9368"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9370"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9372"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           id="path9374"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+      </g>
+      <g
+         id="g9376"
+         transform="matrix(-1,0,0,1,300,52)">
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+           id="path9378"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9456);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9458);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+           id="path9380"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           sodipodi:nodetypes="cc"
+           inkscape:connector-curvature="0"
+           id="path9382"
+           d="m 157.30918,49.331217 -16.68331,8.352699"
+           
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+        <path
+           
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 140.53991,42.100327 18.23961,8.813092"
+           id="path9384"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 158.41403,49.861543 -17.78816,8.927223"
+           id="path9386"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cc" />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9388"
+           d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+      </g>
+    </g>
+    <g
+       inkscape:label="#g9067"
+       id="color-scale-slider-vertical-active"
+       transform="matrix(0,1,-1,0,296.36218,-273.63782)">
+      <g
+         transform="translate(-42,4.9574055e-8)"
+         id="g9392">
+        <g
+           id="g9394">
+          <path
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+             d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+             id="path9396"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cccc" />
+          <path
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9460);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9462);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+             d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+             id="path9398"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cccc" />
+          <path
+             sodipodi:nodetypes="cc"
+             inkscape:connector-curvature="0"
+             id="path9400"
+             d="m 157.30918,49.331217 -16.68331,8.352699"
+             
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+          <path
+             
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+             d="m 140.53991,42.100327 18.23961,8.813092"
+             id="path9402"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cc" />
+          <path
+             
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+             d="m 158.41403,49.861543 -17.78816,8.927223"
+             id="path9404"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cc" />
+          <path
+             sodipodi:nodetypes="cccc"
+             inkscape:connector-curvature="0"
+             id="path9406"
+             d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#184472;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+        </g>
+      </g>
+      <g
+         id="g9408"
+         transform="matrix(-1,0,0,1,300,4.9574055e-8)">
+        <g
+           id="g9410">
+          <path
+             sodipodi:nodetypes="cccc"
+             inkscape:connector-curvature="0"
+             id="path9412"
+             d="M 159.53286,51.381509 140.5,41.956249 l 0.0107,18.905964 z"
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+          <path
+             sodipodi:nodetypes="cccc"
+             inkscape:connector-curvature="0"
+             id="path9414"
+             d="M 159.53286,50.287412 140.5,40.862152 l 0.0107,18.905964 z"
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient9464);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient9466);stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+          <path
+             
style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#f5f5f5;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+             d="m 157.30918,49.331217 -16.68331,8.352699"
+             id="path9416"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cc" />
+          <path
+             sodipodi:nodetypes="cc"
+             inkscape:connector-curvature="0"
+             id="path9418"
+             d="m 140.53991,42.100327 18.23961,8.813092"
+             
style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+          <path
+             sodipodi:nodetypes="cc"
+             inkscape:connector-curvature="0"
+             id="path9420"
+             d="m 158.41403,49.861543 -17.78816,8.927223"
+             
style="display:inline;fill:none;fill-rule:evenodd;stroke:#cfcfcf;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 />
+          <path
+             
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#184472;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+             d="M 159.53286,50.381509 140.5,40.956249 l 0.0107,18.905964 z"
+             id="path9422"
+             inkscape:connector-curvature="0"
+             sodipodi:nodetypes="cccc" />
+        </g>
+      </g>
+    </g>
+    <g
+       inkscape:label="#g9311"
+       id="color-scale-slider-vertical-insensitive"
+       transform="matrix(0,1,-1,0,296.36218,-273.63782)">
+      <path
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+         d="M 117.53286,24.287412 98.5,14.862152 98.5107,33.768116 Z"
+         id="path9426"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cccc" />
+      <path
+         sodipodi:nodetypes="cccc"
+         inkscape:connector-curvature="0"
+         id="path9428"
+         d="M 140.46714,24.287412 159.5,14.862152 159.4893,33.768116 Z"
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+    </g>
+    <g
+       inkscape:label="#g9321"
+       id="color-scale-slider-vertical-backdrop"
+       transform="matrix(0,1,-1,0,296.36218,-273.63782)">
+      <path
+         sodipodi:nodetypes="cccc"
+         inkscape:connector-curvature="0"
+         id="path9432"
+         d="M 117.53286,-3.712588 98.5,-13.137848 98.5107,5.768116 Z"
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#e8e8e7;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+      <path
+         
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#e8e8e7;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+         d="M 140.46714,-3.712588 159.5,-13.137848 159.4893,5.768116 Z"
+         id="path9434"
+         inkscape:connector-curvature="0"
+         sodipodi:nodetypes="cccc"
+         inkscape:label="#path9305" />
+    </g>
+    <g
+       inkscape:label="#g9325"
+       id="color-scale-slider-vertical-backdrop-insensitive"
+       transform="matrix(0,1,-1,0,296.36218,-273.63782)">
+      <g
+         inkscape:label="#g9311"
+         id="g9438"
+         transform="translate(0,-56)">
+        <path
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+           d="M 117.53286,24.287412 98.5,14.862152 98.5107,33.768116 Z"
+           id="path9440"
+           inkscape:connector-curvature="0"
+           sodipodi:nodetypes="cccc" />
+        <path
+           sodipodi:nodetypes="cccc"
+           inkscape:connector-curvature="0"
+           id="path9442"
+           d="M 140.46714,24.287412 159.5,14.862152 159.4893,33.768116 Z"
+           
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f1f1f1;fill-opacity:1;fill-rule:nonzero;stroke:#9d9d99;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
 />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/contrib/gstyle/assets/assets.txt b/contrib/gstyle/assets/assets.txt
new file mode 100644
index 0000000..bf0a6e4
--- /dev/null
+++ b/contrib/gstyle/assets/assets.txt
@@ -0,0 +1,15 @@
+color-scale-slider-horizontal
+color-scale-slider-horizontal-hover
+color-scale-slider-horizontal-active
+color-scale-slider-horizontal-insensitive
+color-scale-slider-horizontal-backdrop
+color-scale-slider-horizontal-backdrop-insensitive
+color-scale-slider-vertical
+color-scale-slider-vertical-hover
+color-scale-slider-vertical-active
+color-scale-slider-vertical-insensitive
+color-scale-slider-vertical-backdrop
+color-scale-slider-vertical-backdrop-insensitive
+gstyle-picker
+unit-percent
+unit-degree
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-active.png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-active.png
new file mode 100644
index 0000000..6eb2cb9
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-active.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-active 2 png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-active 2 png
new file mode 100644
index 0000000..4800fa2
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-active 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop-insensitive.png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop-insensitive.png
new file mode 100644
index 0000000..46944de
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop-insensitive.png 
differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop-insensitive 2 png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop-insensitive 2 png
new file mode 100644
index 0000000..eeadf0d
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop-insensitive 2 png 
differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop.png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop.png
new file mode 100644
index 0000000..711396e
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop 2 png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop 2 png
new file mode 100644
index 0000000..fb3421e
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-backdrop 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-hover.png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-hover.png
new file mode 100644
index 0000000..a71a509
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-hover.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-hover 2 png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-hover 2 png
new file mode 100644
index 0000000..cbe7dda
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-hover 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-insensitive.png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-insensitive.png
new file mode 100644
index 0000000..46944de
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-insensitive.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal-insensitive 2 png 
b/contrib/gstyle/assets/color-scale-slider-horizontal-insensitive 2 png
new file mode 100644
index 0000000..eeadf0d
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal-insensitive 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal.png 
b/contrib/gstyle/assets/color-scale-slider-horizontal.png
new file mode 100644
index 0000000..972ea4d
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-horizontal 2 png 
b/contrib/gstyle/assets/color-scale-slider-horizontal 2 png
new file mode 100644
index 0000000..f353f2c
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-horizontal 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-active.png 
b/contrib/gstyle/assets/color-scale-slider-vertical-active.png
new file mode 100644
index 0000000..98f4b04
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-active.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-active 2 png 
b/contrib/gstyle/assets/color-scale-slider-vertical-active 2 png
new file mode 100644
index 0000000..dc33262
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-active 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-backdrop-insensitive.png 
b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop-insensitive.png
new file mode 100644
index 0000000..521aaae
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop-insensitive.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-backdrop-insensitive 2 png 
b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop-insensitive 2 png
new file mode 100644
index 0000000..ebc05d2
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop-insensitive 2 png 
differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-backdrop.png 
b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop.png
new file mode 100644
index 0000000..fa72ee5
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-backdrop 2 png 
b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop 2 png
new file mode 100644
index 0000000..6b5054e
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-backdrop 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-hover.png 
b/contrib/gstyle/assets/color-scale-slider-vertical-hover.png
new file mode 100644
index 0000000..e155e21
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-hover.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-hover 2 png 
b/contrib/gstyle/assets/color-scale-slider-vertical-hover 2 png
new file mode 100644
index 0000000..9d0a254
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-hover 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-insensitive.png 
b/contrib/gstyle/assets/color-scale-slider-vertical-insensitive.png
new file mode 100644
index 0000000..521aaae
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-insensitive.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical-insensitive 2 png 
b/contrib/gstyle/assets/color-scale-slider-vertical-insensitive 2 png
new file mode 100644
index 0000000..ebc05d2
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical-insensitive 2 png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical.png 
b/contrib/gstyle/assets/color-scale-slider-vertical.png
new file mode 100644
index 0000000..be639a0
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical.png differ
diff --git a/contrib/gstyle/assets/color-scale-slider-vertical 2 png 
b/contrib/gstyle/assets/color-scale-slider-vertical 2 png
new file mode 100644
index 0000000..cc0b33f
Binary files /dev/null and b/contrib/gstyle/assets/color-scale-slider-vertical 2 png differ
diff --git a/contrib/gstyle/assets/eyedropper-symbolic.svg b/contrib/gstyle/assets/eyedropper-symbolic.svg
new file mode 100644
index 0000000..54adac2
--- /dev/null
+++ b/contrib/gstyle/assets/eyedropper-symbolic.svg
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="15.999982"
+   height="16.000017"
+   viewBox="0 0 15.999982 16.000017"
+   id="svg4370"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="eyedropper-symbolic.svg">
+  <defs
+     id="defs4372" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#3a3b39"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32"
+     inkscape:cx="7.453515"
+     inkscape:cy="10.78978"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1043"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-bbox-midpoints="true"
+     units="px"
+     showborder="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:object-nodes="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4918"
+       empcolor="#3ff5ff"
+       empopacity="0.56862745"
+       color="#36ebff"
+       opacity="0.32941176"
+       dotted="false"
+       originx="-335.5638"
+       originy="-859.57305" />
+    <sodipodi:guide
+       position="-31.003958,3.4383656"
+       orientation="1,0"
+       id="guide4174" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata4375">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-335.56379,-176.78911)">
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#ffffff;fill-rule:evenodd;stroke-width:0.85961121;stroke-linecap:round;stroke-linejoin:round;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 345.69922,179.88672 a 0.42984859,0.42984859 0 0 0 -0.29492,0.1289 l -9.39649,9.3711 a 
0.42984859,0.42984859 0 0 0 -0.10742,0.17578 c -0.0937,0.30197 -0.14933,0.77018 -0.33008,1.89258 a 
0.43027012,0.43027012 0 0 0 0.84961,0.13672 c 0.17297,-1.07406 0.25709,-1.57187 0.28711,-1.69141 l 
9.30274,-9.27539 a 0.42984859,0.42984859 0 0 0 -0.31055,-0.73828 z"
+       id="path4190"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#ffffff;fill-rule:evenodd;stroke-width:0.85961121;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 349.59766,176.80664 c -0.50881,-0.0598 -1.0717,0.0201 -1.47071,0.41797 l -1.42578,1.42187 
0.60742,0.60938 1.42579,-1.42188 c 0.13448,-0.13411 0.4246,-0.21348 0.76171,-0.17382 0.33618,0.0395 
0.68426,0.20133 0.83789,0.35351 4.4e-4,4.3e-4 0.002,0.002 0.002,0.002 0.1526,0.15322 0.31488,0.50186 
0.35547,0.8379 0.0407,0.33698 -0.0364,0.62656 -0.16993,0.75976 l -1.42578,1.42188 0.60742,0.60742 
1.42579,-1.42188 c 0.39991,-0.3988 0.47748,-0.96173 0.41601,-1.4707 -0.0614,-0.50808 -0.25728,-0.9955 
-0.60351,-1.3418 -4.2e-4,-4.2e-4 -0.002,4.2e-4 -0.002,0 -0.34729,-0.34562 -0.8336,-0.54178 -1.34179,-0.60156 
z"
+       id="path4194"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#ffffff;fill-rule:evenodd;stroke-width:1.36000001;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 345.77734,177.14844 c -0.34753,-0.0394 -0.69207,0.0483 -0.95507,0.28711 -0.26301,0.23879 
-0.40365,0.61407 -0.3711,0.97461 0.0326,0.36054 0.21384,0.69204 0.48828,0.9707 l 0.004,0.004 2.07031,2.04687 
0,0.002 1.9668,1.93946 c 0.27935,0.27363 0.6111,0.45311 0.9668,0.49023 0.3557,0.0371 0.72778,-0.0855 
0.97656,-0.33984 0.49756,-0.50878 0.37835,-1.3837 -0.16797,-1.9336 l -1.99414,-2.00781 -0.1211,0.11914 
0.11915,-0.12109 -2.00586,-1.95508 c -0.27752,-0.27048 -0.62903,-0.4372 -0.97657,-0.47656 z"
+       id="path4196"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#ffffff;fill-rule:evenodd;stroke-width:0.85961121;stroke-linecap:round;stroke-linejoin:round;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 348.01758,182.19922 a 0.42984859,0.42984859 0 0 0 -0.29492,0.1289 l -9.33008,9.30665 c 
-0.0297,0.0113 -0.1779,0.0563 -0.44727,0.10156 -0.28716,0.0483 -0.68807,0.10677 -1.20312,0.19922 a 
0.42984859,0.42984859 0 1 0 0.15234,0.8457 c 0.49964,-0.0897 0.88793,-0.14591 1.19336,-0.19727 
0.30543,-0.0514 0.52205,-0.0809 0.74805,-0.20507 a 0.42984859,0.42984859 0 0 0 0.0976,-0.0723 l 
9.39649,-9.36914 a 0.42984859,0.42984859 0 0 0 -0.3125,-0.73828 z"
+       id="path4198"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#ffffff;fill-rule:evenodd;stroke-width:1.05546677;stroke-linecap:square;stroke-linejoin:round;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 340.54883,186.57227 a 0.52778616,0.52778616 0 0 0 -0.36524,0.14648 c -0.75207,0.72292 
-2.13158,2.23025 -3.19336,3.26367 a 0.52778616,0.52778616 0 0 0 -0.15625,0.3125 l -0.0918,0.72461 a 
0.52778616,0.52778616 0 0 0 0.58203,0.58985 l 0.70117,-0.0781 a 0.52778616,0.52778616 0 0 0 0.31445,-0.15039 
l 3.91797,-3.9082 a 0.52778616,0.52778616 0 0 0 -0.37109,-0.90039 l -1.33789,0 z"
+       id="path4210"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/contrib/gstyle/assets/render-assets-symbolic.py b/contrib/gstyle/assets/render-assets-symbolic.py
new file mode 100755
index 0000000..0fb4d00
--- /dev/null
+++ b/contrib/gstyle/assets/render-assets-symbolic.py
@@ -0,0 +1,50 @@
+#!/usr/bin/python3
+
+import os
+import subprocess
+import shutil
+
+INKSCAPE = "/usr/bin/inkscape"
+SVG_SRC = "assets-symbolic.svg"
+TXT_SRC = "assets-symbolic.txt"
+
+CWD = os.getcwd()
+
+class Exporter(object):
+    def __init__(self):
+        self.ids = []
+        with open(TXT_SRC) as input_file:
+            for line in input_file:
+                self.ids.append(line.strip())
+
+    def start(self):
+        for id in self.ids:
+            self.export (id)
+            print("id:'{}' exported".format(id))
+
+    def export(self, id):
+        src = "".join([CWD, "/", SVG_SRC])
+        dst = "".join([CWD, "/", id, ".svg"])
+        shutil.copyfile (src, dst)
+        self.call_inkscape([dst,
+                            "--select={}".format(id),
+                            "--verb=FitCanvasToSelection",
+                            "--verb=EditInvertInAllLayers",
+                            "--verb=EditDelete",
+                            "--verb=EditSelectAll",
+                            "--verb=SelectionUnGroup",
+                            "--verb=SelectionUnGroup",
+                            "--verb=SelectionUnGroup",
+                            "--verb=StrokeToPath",
+                            "--verb=FileVacuum",
+                            "--verb=FileSave",
+                            "--verb=FileClose",
+                            "--verb=FileQuit"])
+
+    def call_inkscape(self, cmd):
+        cmd.insert(0, INKSCAPE)
+        subprocess.run(cmd, stdout=subprocess.PIPE)
+
+if __name__ == "__main__":
+    app = Exporter()
+    app.start()
diff --git a/contrib/gstyle/assets/render-assets.sh b/contrib/gstyle/assets/render-assets.sh
new file mode 100755
index 0000000..da1b240
--- /dev/null
+++ b/contrib/gstyle/assets/render-assets.sh
@@ -0,0 +1,34 @@
+#! /bin/bash
+
+INKSCAPE="/usr/bin/inkscape"
+OPTIPNG="/usr/bin/optipng"
+
+SRC_FILE="assets.svg"
+ASSETS_DIR="."
+INDEX="assets.txt"
+
+for i in `cat $INDEX`
+do
+if [ -f $ASSETS_DIR/$i.png ]; then
+    echo $ASSETS_DIR/$i.png exists.
+else
+    echo
+    echo Rendering $ASSETS_DIR/$i.png
+    $INKSCAPE --export-id=$i \
+              --export-id-only \
+              --export-png=$ASSETS_DIR/$i.png $SRC_FILE >/dev/null
+    $OPTIPNG -o7 --quiet $ASSETS_DIR/$i.png
+fi
+if [ -f $ASSETS_DIR/$i 2 png ]; then
+    echo $ASSETS_DIR/$i 2 png exists.
+else
+    echo
+    echo Rendering $ASSETS_DIR/$i 2 png
+    $INKSCAPE --export-id=$i \
+              --export-dpi=180 \
+              --export-id-only \
+              --export-png=$ASSETS_DIR/$i 2 png $SRC_FILE >/dev/null #\
+    $OPTIPNG -o7 --quiet $ASSETS_DIR/$i 2 png
+fi
+done
+exit 0
diff --git a/contrib/gstyle/assets/unit-degree-symbolic.svg b/contrib/gstyle/assets/unit-degree-symbolic.svg
new file mode 100644
index 0000000..75c867f
--- /dev/null
+++ b/contrib/gstyle/assets/unit-degree-symbolic.svg
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="13"
+   height="16"
+   viewBox="0 0 13 16"
+   id="svg4370"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="unit-degree-symbolic.svg">
+  <defs
+     id="defs4372" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#3a3b39"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32"
+     inkscape:cx="-12.98269"
+     inkscape:cy="-9.63714"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1043"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-bbox-midpoints="true"
+     units="px"
+     showborder="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:object-nodes="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4918"
+       empcolor="#3ff5ff"
+       empopacity="0.56862745"
+       color="#36ebff"
+       opacity="0.32941176"
+       dotted="false"
+       originx="-356"
+       originy="-879.99998" />
+    <sodipodi:guide
+       position="-51.440163,-16.988554"
+       orientation="1,0"
+       id="guide4174" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata4375">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-356,-156.3622)">
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#bebebe;fill-rule:evenodd;stroke-width:0.89999998;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 360.1875,157.36133 c -1.75494,0 -3.1875,1.43256 -3.1875,3.1875 0,1.75493 1.43256,3.1875 
3.1875,3.1875 1.75494,0 3.1875,-1.43257 3.1875,-3.1875 0,-1.75494 -1.43256,-3.1875 -3.1875,-3.1875 z m 
0,0.90039 c 1.26854,0 2.28711,1.01857 2.28711,2.28711 0,1.26854 -1.01857,2.28711 -2.28711,2.28711 -1.26854,0 
-2.28711,-1.01857 -2.28711,-2.28711 0,-1.26854 1.01857,-2.28711 2.28711,-2.28711 z"
+       id="circle7708"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill-rule:evenodd;stroke-width:0;stroke-linecap:round;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 355.98438,156.3457 0,0.0156 0,16.01758 13.03124,0 0,-16.03321 -13.03124,0 z m 0.0312,0.0332 
12.96876,0 0,15.96679 -12.96876,0 0,-15.96679 z"
+       id="rect9609"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/contrib/gstyle/assets/unit-percent-symbolic.svg b/contrib/gstyle/assets/unit-percent-symbolic.svg
new file mode 100644
index 0000000..786854b
--- /dev/null
+++ b/contrib/gstyle/assets/unit-percent-symbolic.svg
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   width="13"
+   height="16"
+   viewBox="0 0 13 16"
+   id="svg4370"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="unit-percent-symbolic.svg">
+  <defs
+     id="defs4372" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#3a3b39"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="1"
+     inkscape:pageshadow="2"
+     inkscape:zoom="32"
+     inkscape:cx="6.8947754"
+     inkscape:cy="-9.6371447"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1920"
+     inkscape:window-height="1043"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-bbox-midpoints="true"
+     units="px"
+     showborder="false"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:object-paths="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-midpoints="true"
+     inkscape:object-nodes="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4918"
+       empcolor="#3ff5ff"
+       empopacity="0.56862745"
+       color="#36ebff"
+       opacity="0.32941176"
+       dotted="false"
+       originx="-336.12253"
+       originy="-879.99998" />
+    <sodipodi:guide
+       position="-31.562698,-16.988559"
+       orientation="1,0"
+       id="guide4174" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata4375">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-336.12253,-156.3622)">
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#bebebe;fill-rule:evenodd;stroke-width:0.89999998;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 340.31055,157.36133 c -1.75494,0 -3.1875,1.43256 -3.1875,3.1875 0,1.75493 1.43256,3.1875 
3.1875,3.1875 1.75493,0 3.18554,-1.43257 3.18554,-3.1875 0,-1.75494 -1.43061,-3.1875 -3.18554,-3.1875 z m 
0,0.90039 c 1.26854,0 2.28711,1.01857 2.28711,2.28711 0,1.26854 -1.01857,2.28711 -2.28711,2.28711 -1.26854,0 
-2.28711,-1.01857 -2.28711,-2.28711 0,-1.26854 1.01857,-2.28711 2.28711,-2.28711 z"
+       id="circle7700"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#bebebe;fill-rule:evenodd;stroke-width:0.90353149;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 344.92578,164.95898 c -1.76098,0 -3.19922,1.43852 -3.19922,3.20118 0,1.76266 1.43824,3.20117 
3.19922,3.20117 1.76099,0 3.19727,-1.43851 3.19727,-3.20117 0,-1.76266 -1.43628,-3.20118 -3.19727,-3.20118 z 
m 0,0.90235 c 1.27189,0 2.29297,1.02368 2.29297,2.29883 0,1.27515 -1.02108,2.29882 -2.29297,2.29882 
-1.27188,0 -2.29492,-1.02367 -2.29492,-2.29882 0,-1.27515 1.02304,-2.29883 2.29492,-2.29883 z"
+       id="ellipse7702"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill:#bebebe;fill-rule:evenodd;stroke-width:0.71361196;stroke-linecap:round;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 347.09961,158.00195 a 0.35684166,0.35684166 0 0 0 -0.26172,0.14649 l -9,12 a 
0.35684166,0.35684166 0 1 0 0.57031,0.42773 l 9,-12 a 0.35684166,0.35684166 0 0 0 -0.30859,-0.57422 z"
+       id="path7704"
+       inkscape:connector-curvature="0" />
+    <path
+       
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;overflow:visible;color-interpolation-filters:linearRGB;solid-opacity:1;fill-rule:evenodd;stroke-width:0;stroke-linecap:round;image-rendering:auto;text-rendering:auto;enable-background:accumulate"
+       d="m 336.10742,156.3457 0,0.0156 0,16.01758 13.03125,0 0,-16.03321 -13.03125,0 z m 0.0312,0.0332 
12.96875,0 0,15.96679 -12.96875,0 0,-15.96679 z"
+       id="rect9598"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/contrib/gstyle/check-palette.sh b/contrib/gstyle/check-palette.sh
new file mode 100755
index 0000000..72fcdba
--- /dev/null
+++ b/contrib/gstyle/check-palette.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# "./check-palette.sh files..." will validate files given on command line.
+# "./check-palette.sh" without arguments will validate all palette files
+# in the ./data/palettes directory
+
+files=""
+
+if [ $1 ]; then
+  files=$@
+else
+  cd ./data/palettes
+  files=*.xml
+fi
+
+for file in $files; do
+  xmllint --relaxng palette.rng --noout $file || exit 1
+done
diff --git a/contrib/gstyle/colorlexer-regen.sh b/contrib/gstyle/colorlexer-regen.sh
new file mode 100755
index 0000000..8b13702
--- /dev/null
+++ b/contrib/gstyle/colorlexer-regen.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+RE2C="re2c"
+MIN_VERSION="0.13.7"
+MIN_MAJOR_VERSION="0"
+MIN_MINOR_VERSION="13"
+MIN_MICRO_VERSION="7"
+
+BASE_DIR=$(dirname "$0")
+
+if [ ! hash $RE2C 2>/dev/null ]; then
+  echo "Can't find re2c program. You need to install it in a version >= $version"
+  exit 1
+fi
+
+CURRENT_VERSION=$(echo `re2c -v`| cut -f2 -d " ")
+CURRENT_MAJOR_VERSION=$(echo "$CURRENT_VERSION" | cut -f1 -d.)
+CURRENT_MINOR_VERSION=$(echo "$CURRENT_VERSION" | cut -f2 -d.)
+CURRENT_MICRO_VERSION=$(echo "$CURRENT_VERSION" | cut -f3 -d.)
+
+if [ $CURRENT_MICRO_VERSION="" ]; then
+  CURRENT_MICRO_VERSION="0"
+fi
+
+echo "re2c current version found: $CURRENT_VERSION"
+
+if [ $CURRENT_MAJOR_VERSION -lt $MIN_MAJOR_VERSION ]; then
+  if [ $CURRENT_MINOR_VERSION -lt $MIN_MINOR_VERSION ]; then
+    if [ $CURRENT_MICRO_VERSION -lt $MIN_MICRO_VERSION ]; then
+      echo "You need a re2c version of at least $MIN_VERSION"
+      exit 1
+    fi
+  fi
+fi
+
+`re2c ${BASE_DIR}/gstyle-colorlexer.re -b -s -8 -i -o ${BASE_DIR}/gstyle-colorlexer.c`
+
+echo "gstyle-colorlexer.re compiled in gstyle-colorlexer.c"
diff --git a/contrib/gstyle/data/palettes/basic.xml b/contrib/gstyle/data/palettes/basic.xml
new file mode 100644
index 0000000..f62c42d
--- /dev/null
+++ b/contrib/gstyle/data/palettes/basic.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+-->
+<palette id="basic" _name="Basic">
+
+  <color name="color_hex6"           value="#808080"/>
+  <color name="color_hex3"           value="#1aF"/>
+  <color name="color_rgb"            value="rgb(100, 200, 50)"/>
+  <color name="color_rgb_percent"    value="rgb(10%, 50%, 70%)"/>
+  <color name="color_rgba"           value="rgba(0, 10, 70, 1)"/>
+  <color name="color_rgba_percent"   value="rgba(10%, 50%, 40%, 0.5)"/>
+  <color name="color_hsl"            value="hsl(100, 100%, 50%)"/>
+  <color name="color_hsla"           value="hsla(400, 50%, 40%, 0.5)"/>
+  <color name="color_named"          value="aliceblue"/>
+
+</palette>
diff --git a/contrib/gstyle/data/palettes/palette.rng b/contrib/gstyle/data/palettes/palette.rng
new file mode 100644
index 0000000..6046745
--- /dev/null
+++ b/contrib/gstyle/data/palettes/palette.rng
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+-->
+<grammar xmlns="http://relaxng.org/ns/structure/1.0";
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes";
+         ns="">
+
+<define name="color_hex6">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">#([0-9a-fA-F]+){6}</param>
+    </data>
+  </attribute>
+</define>
+
+<define name="color_hex3">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">#([0-9a-fA-F]+){3}</param>
+    </data>
+  </attribute>
+</define>
+
+<define name="color_rgb">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">rgb\((\s*[0-9]*\.?[0-9]+\s*,){2}\s*[0-9]*\.?[0-9]+\s*\)</param>
+    </data>
+  </attribute>
+</define>
+
+<define name="color_rgb_percent">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">rgb\((\s*[0-9]*\.?[0-9]+%\s*,){2}\s*[0-9]*\.?[0-9]+%\s*\)</param>
+    </data>
+  </attribute>
+</define>
+
+<define name="color_rgba">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">rgba\((\s*[0-9]*\.?[0-9]+\s*,){3}\s*[0-9]*\.?[0-9]+\s*\)</param>
+    </data>
+  </attribute>
+</define>
+
+<define name="color_rgba_percent">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">rgba\((\s*[0-9]*\.?[0-9]+%\s*,){3}\s*[0-9]*\.?[0-9]+\s*\)</param>
+    </data>
+  </attribute>
+
+</define>
+  <define name="color_hsl">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">hsl\(\s*[0-9]*\.?[0-9]+\s*(,\s*[0-9]*\.?[0-9]+%\s*){2}\)</param>
+    </data>
+  </attribute>
+</define>
+
+<define name="color_hsla">
+  <attribute name="value">
+    <data type="string">
+      <param 
name="pattern">hsla\(\s*[0-9]*\.?[0-9]+\s*(,\s*[0-9]*\.?[0-9]+%\s*){2},\s*[0-9]*\.?[0-9]+\s*\)</param>
+    </data>
+  </attribute>
+</define>
+
+<!-- TODO: add named colors list to the pattern -->
+<define name="color_named">
+  <attribute name="value">
+    <data type="string">
+      <param name="pattern">[a-zA-Z]+</param>
+    </data>
+  </attribute>
+</define>
+
+<start>
+  <element name="palette">
+    <attribute name="id">
+      <data type="string">
+        <param name="pattern">[a-zA-Z0-9_]+</param>
+      </data>
+    </attribute>
+    <choice>
+      <attribute name="name"/>
+      <attribute name="_name"/>
+    </choice>
+    <optional>
+      <oneOrMore>
+          <element name="color">
+            <attribute name="name">
+              <data type="string">
+                <param name="pattern">[a-zA-Z0-9_]+</param>
+              </data>
+            </attribute>
+            <choice>
+              <ref name="color_hex6"/>
+              <ref name="color_hex3"/>
+              <ref name="color_rgb"/>
+              <ref name="color_rgb_percent"/>
+              <ref name="color_rgba"/>
+              <ref name="color_rgba_percent"/>
+              <ref name="color_hsl"/>
+              <ref name="color_hsla"/>
+              <ref name="color_named"/>
+            </choice>
+          </element>
+      </oneOrMore>
+    </optional>
+  </element>
+</start>
+
+</grammar>
+
diff --git a/contrib/gstyle/gstyle-animation.c b/contrib/gstyle/gstyle-animation.c
new file mode 100644
index 0000000..dc63096
--- /dev/null
+++ b/contrib/gstyle/gstyle-animation.c
@@ -0,0 +1,51 @@
+/* gstyle-animation.c
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+
+#include "gstyle-animation.h"
+
+gdouble
+gstyle_animation_ease_in_out_cubic (gdouble offset)
+{
+  gdouble val;
+
+  if (offset < 0.5)
+    return (offset * offset * offset * 4.0);
+  else
+    {
+      val = (offset - 0.5) * 2.0;
+      val = val - 1.0;
+      val = val * val * val + 1.0;
+      val = val / 2.0 + 0.5;
+
+      return val;
+    }
+}
+
+gboolean
+gstyle_animation_check_enable_animation (void)
+{
+  gboolean enable_animation;
+
+  g_object_get (gtk_settings_get_default (),
+                "gtk-enable-animations", &enable_animation,
+                NULL);
+
+  return enable_animation;
+}
diff --git a/contrib/gstyle/gstyle-animation.h b/contrib/gstyle/gstyle-animation.h
new file mode 100644
index 0000000..a28be56
--- /dev/null
+++ b/contrib/gstyle/gstyle-animation.h
@@ -0,0 +1,31 @@
+/* gstyle-animation.h
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_ANIMATION_H
+#define GSTYLE_ANIMATION_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gdouble           gstyle_animation_ease_in_out_cubic         (gdouble   offset);
+gboolean          gstyle_animation_check_enable_animation    (void);
+
+G_END_DECLS
+
+#endif /* GSTYLE_ANIMATION_H */
diff --git a/contrib/gstyle/gstyle-cielab.c b/contrib/gstyle/gstyle-cielab.c
new file mode 100644
index 0000000..631d479
--- /dev/null
+++ b/contrib/gstyle/gstyle-cielab.c
@@ -0,0 +1,64 @@
+/* gstyle-cielab.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-cielab"
+
+#include "gstyle-cielab.h"
+
+G_DEFINE_BOXED_TYPE (GstyleCielab, gstyle_cielab, gstyle_cielab_copy, gstyle_cielab_free)
+
+/**
+ * GstyleCielab:
+ * @l: color- lightness dimension from 0 (darkest black) to 100 (brightest white)
+ * @a: color-opponent dimension from green (-300) to red (+299).
+ * @b: color-opponent dimension from blue (-300) to yellow (+299).
+ * @alpha: The opacity of the color in [0, 1] range.
+ *
+ * A #GstyleCielab used to represent a color in
+ * the CIE L*a*b* 1976 colorspace.
+ */
+
+/**
+ * gstyle_cielab_copy:
+ * @self: a #GstyleCielab
+ *
+ * Makes a copy of a #GstyleCielab.
+ *
+ * The result must be freed through gstyle_cielab_free().
+ *
+ * Returns: a newly allocated #GstyleCielab, with the same contents as @self
+ *
+ */
+GstyleCielab *
+gstyle_cielab_copy (const GstyleCielab *self)
+{
+  return g_slice_dup (GstyleCielab, self);
+}
+
+/**
+ * gstyle_cielab_free:
+ * @self: a #GstyleCielab
+ *
+ * Frees a #GstyleCielab created with gstyle_cielab_copy().
+ *
+ */
+void
+gstyle_cielab_free (GstyleCielab *self)
+{
+  g_slice_free (GstyleCielab, self);
+}
diff --git a/contrib/gstyle/gstyle-cielab.h b/contrib/gstyle/gstyle-cielab.h
new file mode 100644
index 0000000..32acaef
--- /dev/null
+++ b/contrib/gstyle/gstyle-cielab.h
@@ -0,0 +1,45 @@
+/* gstyle-cielab.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_CIELAB_H
+#define GSTYLE_CIELAB_H
+
+#include <glib.h>
+
+#include "gstyle-types.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_CIELAB (gstyle_cielab_get_type ())
+
+struct _GstyleCielab
+{
+  gdouble l;
+  gdouble a;
+  gdouble b;
+  gdouble alpha;
+};
+
+GType          gstyle_cielab_get_type                (void) G_GNUC_CONST;
+
+GstyleCielab  *gstyle_cielab_copy                    (const GstyleCielab  *self);
+void           gstyle_cielab_free                    (GstyleCielab        *self);
+
+G_END_DECLS
+
+#endif /* GSTYLE_CIELAB_H */
diff --git a/contrib/gstyle/gstyle-color-component.c b/contrib/gstyle/gstyle-color-component.c
new file mode 100644
index 0000000..e88dec3
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-component.c
@@ -0,0 +1,50 @@
+/* gstyle-color-component.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+
+#include "gstyle-color-component.h"
+
+GType
+gstyle_color_component_get_type (void)
+{
+  static GType type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_COLOR_COMPONENT_HSV_H,     "GSTYLE_COLOR_COMPONENT_HSV_H",     "hsv_h"    },
+    { GSTYLE_COLOR_COMPONENT_HSV_S,     "GSTYLE_COLOR_COMPONENT_HSV_S",     "hsv_s"   },
+    { GSTYLE_COLOR_COMPONENT_HSV_V,     "GSTYLE_COLOR_COMPONENT_HSV_V",     "hsv_v"  },
+    { GSTYLE_COLOR_COMPONENT_LAB_L,     "GSTYLE_COLOR_COMPONENT_LAB_L",     "lab_l"    },
+    { GSTYLE_COLOR_COMPONENT_LAB_A,     "GSTYLE_COLOR_COMPONENT_LAB_A",     "lab_a"  },
+    { GSTYLE_COLOR_COMPONENT_LAB_B,     "GSTYLE_COLOR_COMPONENT_LAB_B",     "lab_b"   },
+    { GSTYLE_COLOR_COMPONENT_RGB_RED,   "GSTYLE_COLOR_COMPONENT_RGB_RED",   "rgb_red" },
+    { GSTYLE_COLOR_COMPONENT_RGB_GREEN, "GSTYLE_COLOR_COMPONENT_RGB_GREEN", "rgb_green" },
+    { GSTYLE_COLOR_COMPONENT_RGB_BLUE,  "GSTYLE_COLOR_COMPONENT_RGB_BLUE",  "rgb_blue" },
+    { GSTYLE_COLOR_COMPONENT_NONE,      "GSTYLE_COLOR_COMPONENT_NONE",      "none" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstyleColorComponent", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/gstyle/gstyle-color-component.h b/contrib/gstyle/gstyle-color-component.h
new file mode 100644
index 0000000..a7f694e
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-component.h
@@ -0,0 +1,45 @@
+/* gstyle-color-component.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_COMPONENT_H
+#define GSTYLE_COLOR_COMPONENT_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_COLOR_COMPONENT (gstyle_color_component_get_type()
+
+typedef enum {
+  GSTYLE_COLOR_COMPONENT_HSV_H,
+  GSTYLE_COLOR_COMPONENT_HSV_S,
+  GSTYLE_COLOR_COMPONENT_HSV_V,
+  GSTYLE_COLOR_COMPONENT_LAB_L,
+  GSTYLE_COLOR_COMPONENT_LAB_A,
+  GSTYLE_COLOR_COMPONENT_LAB_B,
+  GSTYLE_COLOR_COMPONENT_RGB_RED,
+  GSTYLE_COLOR_COMPONENT_RGB_GREEN,
+  GSTYLE_COLOR_COMPONENT_RGB_BLUE,
+  N_GSTYLE_COLOR_COMPONENT,
+  GSTYLE_COLOR_COMPONENT_NONE
+} GstyleColorComponent;
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_COMPONENT_H */
+
diff --git a/contrib/gstyle/gstyle-color-convert.c b/contrib/gstyle/gstyle-color-convert.c
new file mode 100644
index 0000000..33d5d82
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-convert.c
@@ -0,0 +1,843 @@
+/* gstyle-color-convert.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "gstyle-color-convert.h"
+
+#define _2PI          6.2831853071795864769252867665590057683943387987502
+#define PI_d_6        0.523598775598298873077107230546583814032861566562516
+#define PI_d_30       0.104719755119659774615421446109316762806572313312503
+#define _63PI_d_180   1.099557428756427633461925184147826009469009289781285
+#define _180_d_PI     57.29577951308232087679815481410517033240547246656442
+#define _25_pow_7     6103515625
+#define _30PI_d_180   0.523598775598298873077107230546583814032861566562516
+#define _16_d_116     0.137931034
+
+#define one_third     0.333333333333333333333333333333333333333333333333333
+#define two_third     0.666666666666666666666666666666666666666666666666666
+
+#define D65_xref      0.95047
+#define D65_yref      1.0
+#define D65_zref      1.08883
+
+/* DeltaE algorithm described at:
+ * http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf
+ *
+ */
+
+/* pow_1_24 and pow_24 are adapted version from babl, published under LGPL */
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2012, Red Hat, Inc.
+ */
+
+/* Chebychev polynomial terms for x^(5/12) expanded around x=1.5
+ * Non-zero terms calculated via
+ * NIntegrate[(2/Pi)*ChebyshevT[N,u]/Sqrt [1-u^2]*((u+3)/2)^(5/12),{u,-1,1}, PrecisionGoal->20, 
WorkingPrecision -> 100]
+ * Zeroth term is similar except it uses 1/pi rather than 2/pi.
+ */
+static const double Cn[] = {
+  1.1758200232996901923,
+  0.16665763094889061230,
+  -0.0083154894939042125035,
+  0.00075187976780420279038,
+  -0.000083240178519391795367,
+  0.000010229209410070008679,
+  -1.3401001466409860246e-6,
+  1.8333422241635376682e-7,
+  -2.5878596761348859722e-8
+};
+
+/* Returns x^(5/12) for x in [1,2) */
+static inline gdouble
+pow512norm (gdouble x)
+{
+  gdouble Tn[9];
+  gdouble u;
+
+  u = 2.0*x - 3.0;
+  Tn[0] = 1.0;
+  Tn[1] = u;
+  Tn[2] = 2*u*Tn[2-1] - Tn[2-2];
+  Tn[3] = 2*u*Tn[3-1] - Tn[3-2];
+  Tn[4] = 2*u*Tn[4-1] - Tn[4-2];
+  Tn[5] = 2*u*Tn[5-1] - Tn[5-2];
+  Tn[6] = 2*u*Tn[6-1] - Tn[6-2];
+
+  return Cn[0]*Tn[0] + Cn[1]*Tn[1] + Cn[2]*Tn[2] + Cn[3]*Tn[3] + Cn[4]*Tn[4] + Cn[5]*Tn[5] + Cn[6]*Tn[6];
+}
+
+/* Precalculated (2^N) ^ (5 / 12) */
+static const gdouble pow2_512[12] =
+{
+  1.0,
+  1.3348398541700343678,
+  1.7817974362806785482,
+  2.3784142300054420538,
+  3.1748021039363991669,
+  4.2378523774371812394,
+  5.6568542494923805819,
+  7.5509945014535482244,
+  1.0079368399158985525e1,
+  1.3454342644059433809e1,
+  1.7959392772949968275e1,
+  2.3972913230026907883e1
+};
+
+/* Returns x^(1/2.4) == x^(5/12) */
+static inline gdouble
+pow_1_24 (gdouble x)
+{
+  gdouble s;
+  gint iexp;
+  div_t qr = {0};
+
+  s = frexp (x, &iexp);
+  s *= 2.0;
+  iexp -= 1;
+
+  qr = div (iexp, 12);
+  if (qr.rem < 0)
+    {
+      qr.quot -= 1;
+      qr.rem += 12;
+    }
+
+  return ldexp (pow512norm (s) * pow2_512[qr.rem], 5 * qr.quot);
+}
+
+/* Chebychev polynomial terms for x^(7/5) expanded around x=1.5
+ * Non-zero terms calculated via
+ * NIntegrate[(2/Pi)*ChebyshevT[N,u]/Sqrt [1-u^2]*((u+3)/2)^(7/5),{u,-1,1}, PrecisionGoal->20, 
WorkingPrecision -> 100]
+ * Zeroth term is similar except it uses 1/pi rather than 2/pi.
+ */
+static const gdouble iCn[] =
+{
+  1.7917488588043277509,
+  0.82045614371976854984,
+  0.027694100686325412819,
+  -0.00094244335181762134018,
+  0.000064355540911469709545,
+  -5.7224404636060757485e-6,
+  5.8767669437311184313e-7,
+  -6.6139920053589721168e-8,
+  7.9323242696227458163e-9
+};
+
+/* Returns x^(7/5) for x in [1,2) */
+static inline gdouble
+pow75norm (gdouble x)
+{
+  gdouble Tn[9];
+  gdouble u;
+
+  u = 2.0*x - 3.0;
+  Tn[0] = 1.0;
+  Tn[1] = u;
+  Tn[2] = 2*u*Tn[2-1] - Tn[2-2];
+  Tn[3] = 2*u*Tn[3-1] - Tn[3-2];
+  Tn[4] = 2*u*Tn[4-1] - Tn[4-2];
+  Tn[5] = 2*u*Tn[5-1] - Tn[5-2];
+
+  return iCn[0]*Tn[0] + iCn[1]*Tn[1] + iCn[2]*Tn[2] + iCn[3]*Tn[3] + iCn[4]*Tn[4] + iCn[5]*Tn[5];
+}
+
+/* Precalculated (2^N) ^ (7 / 5) */
+static const gdouble pow2_75[5] =
+{
+  1.0,
+  2.6390158215457883983,
+  6.9644045063689921093,
+  1.8379173679952558018e+1,
+  4.8502930128332728543e+1
+};
+
+/* Returns x^2.4 == x * x ^1.4 == x * x^(7/5) */
+static inline gdouble
+pow_24 (gdouble x)
+{
+  gdouble s;
+  gint iexp;
+  div_t qr = {0};
+
+  s = frexp (x, &iexp);
+  s *= 2.0;
+  iexp -= 1;
+
+  qr = div (iexp, 5);
+  if (qr.rem < 0)
+    {
+      qr.quot -= 1;
+      qr.rem += 5;
+    }
+
+  return x * ldexp (pow75norm (s) * pow2_75[qr.rem], 7 * qr.quot);
+}
+
+static inline gboolean
+fix_rgb_bounds (GdkRGBA *rgba)
+{
+  gdouble r, g, b;
+  gboolean res = TRUE;
+
+  r = rgba->red;
+  g = rgba->green;
+  b = rgba->blue;
+
+  if (r < 0.0)
+    {
+      rgba->red = 0.0;
+      res = FALSE;
+    }
+  else if (r > 1.0)
+    {
+      rgba->red = 1.0;
+      res = FALSE;
+    }
+
+  if (g < 0.0)
+    {
+      rgba->green = 0.0;
+      res = FALSE;
+    }
+  else if (g > 1.0)
+    {
+      rgba->green = 1.0;
+      res = FALSE;
+    }
+
+    if (b < 0.0)
+    {
+      rgba->blue = 0.0;
+      res = FALSE;
+    }
+  else if (b > 1.0)
+    {
+      rgba->blue = 1.0;
+      res = FALSE;
+    }
+
+  return res;
+}
+
+static inline void
+gstyle_color_convert_rgb_to_srgb (GdkRGBA *rgba,
+                                  gdouble *red,
+                                  gdouble *green,
+                                  gdouble *blue)
+{
+  /* rgba and srgb values range [0, 1] */
+
+  *red = (rgba->red > 0.04045) ? pow_24 (((rgba->red + 0.055) / 1.055)) : rgba->red / 12.92;
+  *green = (rgba->green > 0.04045) ? pow_24 (((rgba->green + 0.055) / 1.055)) : rgba->green / 12.92;
+  *blue = (rgba->blue > 0.04045) ? pow_24 (((rgba->blue + 0.055) / 1.055)) : rgba->blue / 12.92;
+}
+
+static inline void
+gstyle_color_convert_srgb_to_rgb (gdouble  red,
+                                  gdouble  green,
+                                  gdouble  blue,
+                                  GdkRGBA *rgba)
+{
+  /* rgba and srgb values range [0, 1] */
+
+  rgba->red = (red > 0.0031308) ? (pow_1_24 (red) * 1.055) - 0.055 : red * 12.92;
+  rgba->green = (green > 0.0031308) ? (pow_1_24 (green) * 1.055) - 0.055 : green * 12.92;
+  rgba->blue = (blue > 0.0031308) ? (pow_1_24 (blue) * 1.055) - 0.055 : blue * 12.92;
+
+  fix_rgb_bounds (rgba);
+}
+
+static inline void
+gstyle_color_convert_srgb_to_xyz (gdouble    red,
+                                  gdouble    green,
+                                  gdouble    blue,
+                                  GstyleXYZ *xyz)
+{
+  /* srgb range [0, 1] x [0, 0.9505] y [0, 1] z [0, 1.08883] Observer= 2°, Illuminant= D65 */
+
+  xyz->x = (red * 0.4124564 + green * 0.3575761 + blue * 0.1804375);
+  xyz->y = (red * 0.2126729 + green * 0.7151522 + blue * 0.0721750);
+  xyz->z = (red * 0.0193339 + green * 0.1191920 + blue * 0.9503041);
+
+  //fix_xyz_bounds (xyz);
+}
+
+static inline void
+gstyle_color_convert_xyz_to_srgb (GstyleXYZ *xyz,
+                                  gdouble   *red,
+                                  gdouble   *green,
+                                  gdouble   *blue)
+{
+  /* srgb range [0, 1] x [0, 0.9505] y [0, 1] z [0, 1.08883] Observer= 2°, Illuminant= D65 */
+
+  *red   = xyz->x *  3.2404542 + xyz->y * -1.5371385 + xyz->z * -0.4985314;
+  *green = xyz->x * -0.9692660 + xyz->y *  1.8760108 + xyz->z *  0.0415560;
+  *blue  = xyz->x *  0.0556434 + xyz->y * -0.2040259 + xyz->z *  1.0572252;
+}
+
+inline void
+gstyle_color_convert_cielab_to_xyz (GstyleCielab *lab,
+                                    GstyleXYZ    *xyz)
+{
+  gdouble tmp_x, tmp_y, tmp_z;
+  gdouble pow3_x, pow3_y, pow3_z;
+
+  tmp_y = (lab->l + 16.0 ) / 116.0;
+  tmp_x = lab->a / 500.0 + tmp_y;
+  tmp_z = tmp_y - lab->b / 200.0;
+
+  /* far faster than pow (x, 3) */
+  pow3_x = tmp_x * tmp_x * tmp_x;
+  pow3_y = tmp_y * tmp_y * tmp_y;
+  pow3_z = tmp_z * tmp_z * tmp_z;
+
+  tmp_x = (pow3_x > 0.008856) ? pow3_x : (tmp_x - _16_d_116) / 7.787;
+  tmp_y = (pow3_y > 0.008856) ? pow3_y : (tmp_y - _16_d_116) / 7.787;
+  tmp_z = (pow3_z > 0.008856) ? pow3_z : (tmp_z - _16_d_116) / 7.787;
+
+  xyz->x = tmp_x * D65_xref;
+  xyz->y = tmp_y * D65_yref;
+  xyz->z = tmp_z * D65_zref;
+}
+
+/* fastpow (x, 0.333333333) */
+inline void
+gstyle_color_convert_xyz_to_cielab (GstyleXYZ    *xyz,
+                                    GstyleCielab *lab)
+{
+  /* Observer= 2°, Illuminant= D65 */
+  gdouble x, y, z;
+
+  x = xyz->x / D65_xref;
+  y = xyz->y / D65_yref;
+  z = xyz->z / D65_zref;
+
+  x = (x > 0.008856) ? cbrt (x) : (x * 7.787) + _16_d_116;
+  y = (y > 0.008856) ? cbrt (y) : (y * 7.787) + _16_d_116;
+  z = (z > 0.008856) ? cbrt (z) : (z * 7.787) + _16_d_116;
+
+  lab->l = y * 116.0 - 16.0;
+  lab->a = (x - y) * 500.0;
+  lab->b = (y - z) * 200.0;
+}
+
+/**
+ * gstyle_color_convert_rgb_to_hsl:
+ * @rgba: A #GdkRGBA struct.
+ * @hue: (out): The hue component of a hsl color in range  [0.0-360.0[
+ * @saturation: (out): The saturation component of a hsl color in range [0.0-100.0]
+ * @lightness: (out): The lightness component of a hsl color in range [0.0-100.0]
+ *
+ * Convert rgb components to HSL ones.
+ * The alpha component is not used because it doesn't change in the conversion.
+ *
+ */
+void
+gstyle_color_convert_rgb_to_hsl (GdkRGBA *rgba,
+                                 gdouble *hue,
+                                 gdouble *saturation,
+                                 gdouble *lightness)
+{
+  gdouble tmp_hue = 0.0;
+  gdouble tmp_saturation = 0.0;
+  gdouble tmp_lightness;
+
+  gdouble red = rgba->red;
+  gdouble green = rgba->green;
+  gdouble blue = rgba->blue;
+
+  gdouble min;
+  gdouble max;
+  gdouble d;
+  gdouble max_min;
+
+  if (red > green)
+    {
+      max = (red > blue) ? red : blue;
+      min = (green < blue) ? green : blue;
+    }
+  else
+    {
+      max = (green > blue) ? green : blue;
+      min = (red < blue) ? red : blue;
+    }
+
+  max_min = max + min;
+  tmp_lightness = max_min / 2.0;
+  if (max != min)
+    {
+      d = max - min;
+      tmp_saturation = (tmp_lightness > 0.5) ? d / (2.0 - max - min) : d / max_min;
+      if (max == red)
+        tmp_hue = (green - blue) / d + (green < blue ? 6.0 : 0.0);
+      else if (max == green)
+        tmp_hue = (blue - red) / d + 2.0;
+      else
+        tmp_hue = (red - green) / d + 4.0;
+    }
+
+  if (hue != NULL)
+    *hue = tmp_hue * 60.0;
+
+  if (saturation != NULL)
+    *saturation = tmp_saturation * 100.0;
+
+  if (lightness != NULL)
+    *lightness = tmp_lightness * 100.0;
+}
+
+static inline gdouble
+hue2rgb (gdouble m1,
+         gdouble m2,
+         gdouble hue)
+{
+  while (hue < 0.0)
+    hue += 360.0;
+
+  while (hue > 360.0)
+    hue -= 360.0;
+
+  if (hue < 60.0)
+    return m1 + (m2 - m1) * hue / 60.0;
+
+  if (hue < 180.0)
+    return m2;
+
+  if (hue < 240.0)
+    return m1 + (m2 - m1) * (240.0 - hue) / 60.0;
+
+  return m1;
+}
+
+/**
+ * gstyle_color_convert_hsl_to_rgb:
+ * @hue: The hue component of a hsl color in range  [0.0-360.0[
+ * @saturation: The saturation component of a hsl color in range [0.0-100.0]
+ * @lightness: The lightness component of a hsl color in range [0.0-100.0]
+ * @rgba: A #GdkRGBA.
+ *
+ * Convert RGB components to HSL ones.
+ * The alpha component is not used because it doesn't change in the conversion.
+ *
+ */
+void
+gstyle_color_convert_hsl_to_rgb (gdouble   hue,
+                                 gdouble   saturation,
+                                 gdouble   lightness,
+                                 GdkRGBA  *rgba)
+{
+  gdouble m1;
+  gdouble m2;
+
+  if (saturation == 0.0)
+    rgba->red = rgba->green = rgba->blue = lightness;
+  else
+    {
+      m2 = (lightness > 0.5) ? lightness + saturation - (lightness * saturation) : lightness * (1.0 + 
saturation);
+      m1 = 2.0 * lightness - m2;
+
+      rgba->red = hue2rgb (m1, m2, hue + 120.0);
+      rgba->green = hue2rgb (m1, m2, hue);
+      rgba->blue = hue2rgb (m1, m2, hue - 120.0);
+    }
+}
+
+/**
+ * gstyle_color_convert_hsv_to_rgb:
+ * @hue: The hue component of a hsv color in range  [0.0-1.0[
+ * @saturation: The saturation component of a hsv color in range [0.0-1.0]
+ * @value: The value component of a hsv color in range [0.0-1.0]
+ * @rgba: A #GdkRGBA.
+ *
+ * Convert HSV components to RGB ones.
+ * The alpha component is not used because it doesn't change in the conversion.
+ *
+ */
+void
+gstyle_color_convert_hsv_to_rgb (gdouble   hue,
+                                 gdouble   saturation,
+                                 gdouble   value,
+                                 GdkRGBA  *rgba)
+{
+  gdouble f;
+  gdouble p;
+  gdouble q;
+  gdouble t;
+  gint i;
+
+  if (saturation == 0.0)
+    rgba->red = rgba->green = rgba->blue = value;
+  else
+    {
+      hue *= 6.0;
+      if (hue == 6.0)
+        hue = 0.0;
+
+      i = (int)hue;
+      f = hue - i;
+      p = value * (1.0 - saturation);
+      q = value * (1.0 - saturation * f);
+      t = value * (1.0 - saturation * (1.0 - f));
+
+      switch (i)
+        {
+        case 0:
+          rgba->red = value;
+          rgba->green = t;
+          rgba->blue = p;
+          break;
+
+        case 1:
+          rgba->red = q;
+          rgba->green = value;
+          rgba->blue = p;
+          break;
+
+        case 2:
+          rgba->red = p;
+          rgba->green = value;
+          rgba->blue = t;
+          break;
+
+        case 3:
+          rgba->red = p;
+          rgba->green = q;
+          rgba->blue = value;
+          break;
+
+        case 4:
+          rgba->red = t;
+          rgba->green = p;
+          rgba->blue = value;
+          break;
+
+        case 5:
+          rgba->red = value;
+          rgba->green = p;
+          rgba->blue = q;
+          break;
+
+        default:
+          g_assert_not_reached ();
+        }
+    }
+}
+
+/**
+ * gstyle_color_convert_rgb_to_xyz:
+ * @rgba: An #GdkRGBA.
+ * @xyz: A #GstyleXYZ.
+ *
+ * Convert RGB components to XYZ ones.
+ * The alpha component is not used because it doesn't change in the conversion.
+ *
+ */
+void
+gstyle_color_convert_rgb_to_xyz (GdkRGBA   *rgba,
+                                 GstyleXYZ *xyz)
+{
+  gdouble srgb_red, srgb_green, srgb_blue;
+
+  gstyle_color_convert_rgb_to_srgb (rgba, &srgb_red, &srgb_green, &srgb_blue);
+  gstyle_color_convert_srgb_to_xyz (srgb_red, srgb_green, srgb_blue, xyz);
+}
+
+/**
+ * gstyle_color_convert_rgb_to_hsv:
+ * @rgba: An #GdkRGBA.
+ * @hue: (out): The hue component of a hsv color in range  [0.0-1.0[
+ * @saturation: (out): The saturation component of a hsv color in range [0.0-1.0]
+ * @value: (out): The value component of a hsv color in range [0.0-1.0]
+ *
+ * Convert RGB components to HSV ones.
+ * The alpha component is not used because it doesn't change in the conversion.
+ *
+ */
+void
+gstyle_color_convert_rgb_to_hsv (GdkRGBA *rgba,
+                                 gdouble *hue,
+                                 gdouble *saturation,
+                                 gdouble *value)
+{
+  gdouble vmin, vmax, delta;
+  gdouble d_red, d_green, d_blue;
+  gdouble delta_d_2;
+
+  if (rgba->red > rgba->green)
+    {
+      vmax = (rgba->red > rgba->blue) ? rgba->red : rgba->blue;
+      vmin = (rgba->green < rgba->blue) ? rgba->green : rgba->blue;
+    }
+  else
+    {
+      vmax = (rgba->green > rgba->blue) ? rgba->green : rgba->blue;
+      vmin = (rgba->red < rgba->blue) ? rgba->red : rgba->blue;
+    }
+
+  delta = vmax - vmin;
+  delta_d_2 = delta / 2.0;
+
+  *value = vmax;
+
+  if (delta < 1e-20 )
+    *hue = *saturation = 0.0;
+  else
+    {
+      *saturation = delta / vmax;
+
+      d_red   = ((vmax - rgba->red)   / 6.0 + delta_d_2) / delta;
+      d_green = ((vmax - rgba->green) / 6.0 + delta_d_2) / delta;
+      d_blue  = ((vmax - rgba->blue)  / 6.0 + delta_d_2) / delta;
+
+      if (vmax == rgba->red)
+         *hue = d_blue - d_green;
+      else if (vmax == rgba->green)
+         *hue = one_third + d_red - d_blue;
+      else if (vmax == rgba->blue)
+        *hue = two_third + d_green - d_red;
+
+      if (*hue < 0.0)
+        *hue += 1.0;
+      else if (*hue > 1.0 )
+        *hue -= 1.0;
+    }
+}
+
+/**
+ * gstyle_color_convert_rgb_to_cielab:
+ * @rgba: An #GdkRGBA.
+ * @lab: (out): A #GstyleCieLab struct.
+ *
+ * Convert RGB components to CIELAB ones.
+ * The alpha component is not used because it doesn't change in the conversion.
+ *
+ */
+void
+gstyle_color_convert_rgb_to_cielab (GdkRGBA      *rgba,
+                                    GstyleCielab *lab)
+{
+  gdouble srgb_red, srgb_green, srgb_blue;
+  GstyleXYZ xyz;
+
+  gstyle_color_convert_rgb_to_srgb (rgba, &srgb_red, &srgb_green, &srgb_blue);
+  gstyle_color_convert_srgb_to_xyz (srgb_red, srgb_green, srgb_blue, &xyz);
+  gstyle_color_convert_xyz_to_cielab (&xyz, lab);
+}
+
+/**
+ * gstyle_color_convert_cielab_to_rgb:
+ * @lab: A #GstyleCieLab struct.
+ * @rgba: (out): An #GdkRGBA.
+ *
+ * Convert CIELAB components to RGB ones.
+ * The alpha component is not used because it doesn't change in the conversion.
+ *
+ */
+void
+gstyle_color_convert_cielab_to_rgb (GstyleCielab *lab,
+                                    GdkRGBA      *rgba)
+{
+  gdouble srgb_red, srgb_green, srgb_blue;
+  GstyleXYZ xyz;
+
+  gstyle_color_convert_cielab_to_xyz (lab, &xyz);
+  gstyle_color_convert_xyz_to_srgb (&xyz, &srgb_red, &srgb_green, &srgb_blue);
+  gstyle_color_convert_srgb_to_rgb (srgb_red, srgb_green, srgb_blue, rgba);
+}
+
+inline void
+gstyle_color_convert_xyz_to_rgb (GstyleXYZ *xyz,
+                                 GdkRGBA   *rgba)
+{
+  gdouble srgb_red, srgb_green, srgb_blue;
+
+  gstyle_color_convert_xyz_to_srgb (xyz, &srgb_red, &srgb_green, &srgb_blue);
+  gstyle_color_convert_srgb_to_rgb (srgb_red, srgb_green, srgb_blue, rgba);
+}
+
+/**
+ * gstyle_color_convert_hsv_to_xyz:
+ * @hue:  The hue component of a hsv color in range  [0.0-1.0[
+ * @saturation: The saturation component of a hsv color in range [0.0-1.0]
+ * @value: The value component of a hsv color in range [0.0-1.0]
+ * @xyz: (out): An #GstyleXYZ.
+ *
+ * Convert HSV components to XYZ ones.
+ *
+ */
+void
+gstyle_color_convert_hsv_to_xyz (gdouble    hue,
+                                 gdouble    saturation,
+                                 gdouble    value,
+                                 GstyleXYZ *xyz)
+{
+  gdouble srgb_red, srgb_green, srgb_blue;
+  GdkRGBA rgba;
+
+  gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &rgba);
+  gstyle_color_convert_rgb_to_srgb (&rgba, &srgb_red, &srgb_green, &srgb_blue);
+  gstyle_color_convert_srgb_to_xyz (srgb_red, srgb_green, srgb_blue, xyz);
+}
+
+/**
+ * gstyle_color_convert_xyz_to_hsv:
+ * @xyz: An #GstyleXYZ.
+ * @hue: (out): The hue component of a hsv color in range  [0.0-1.0[
+ * @saturation: (out): The saturation component of a hsv color in range [0.0-1.0]
+ * @value: (out): The value component of a hsv color in range [0.0-1.0]
+ *
+ * Convert XYZ components to HSV ones.
+ *
+ */
+void
+gstyle_color_convert_xyz_to_hsv (GstyleXYZ *xyz,
+                                 gdouble   *hue,
+                                 gdouble   *saturation,
+                                 gdouble   *value)
+{
+  GdkRGBA rgba;
+  gdouble srgb_red, srgb_green, srgb_blue;
+
+  gstyle_color_convert_xyz_to_srgb (xyz, &srgb_red, &srgb_green, &srgb_blue);
+  gstyle_color_convert_srgb_to_rgb (srgb_red, srgb_green, srgb_blue, &rgba);
+  gstyle_color_convert_rgb_to_hsv (&rgba, hue, saturation, value);
+}
+
+/**
+ * gstyle_color_delta_e:
+ * @lab1: A #GstyleCielab.
+ * @lab2: A #GstyleCielab.
+ *
+ * Compute the color difference between lab1 and lab2,
+ * based on the deltaE CIEDE2000 formula.
+ *
+ * Returns: the deltaE value.
+ *
+ */
+gdouble
+gstyle_color_delta_e (GstyleCielab *lab1,
+                      GstyleCielab *lab2)
+{
+  gdouble ap1, Cp1, hp1, Cab1;
+  gdouble ap2, Cp2, hp2, Cab2;
+  gdouble Cab;
+
+  gdouble Cp1Cp2;
+  gdouble Cab_pow_7, G;
+
+  gdouble DLp, DCp, DHp;
+  gdouble dhp, Lp, Cp, hp;
+
+  gdouble T;
+  gdouble Dtheta_rad;
+  gdouble Rc, RT;
+
+  gdouble _50Lp_pow2;
+  gdouble SL, SC, SH;
+
+  gdouble lab1_bb = lab1->b * lab1->b;
+  gdouble lab2_bb = lab2->b * lab2->b;
+
+  Cab1 = sqrt (lab1->a * lab1->a + lab1_bb);
+  Cab2 = sqrt (lab2->a * lab2->a + lab2_bb);
+  Cab = (Cab1 + Cab2) / 2.0;
+  Cab_pow_7 = pow (Cab, 7);
+
+  G = 0.5 * (1.0 - sqrt (Cab_pow_7 / (Cab_pow_7 + _25_pow_7)));
+
+  ap1 = (1.0 + G) * lab1->a;
+  ap2 = (1.0 + G) * lab2->a;
+
+  Cp1 = sqrt (ap1 * ap1 + lab1_bb);
+  Cp2 = sqrt (ap2 * ap2 + lab2_bb);
+  Cp1Cp2 = (Cp1 * Cp2);
+
+  if (ap1 == 0 && lab1->b == 0)
+    hp1 = 0.0;
+  else
+    {
+      hp1 = atan2 (lab1->b, ap1);
+      if (hp1 < 0)
+        hp1 += _2PI;
+    }
+
+  if (ap2 == 0 && lab2->b == 0)
+    hp2 = 0.0;
+  else
+    {
+      hp2 = atan2 (lab2->b, ap2);
+      if (hp2 < 0)
+        hp2 += _2PI;
+    }
+
+  DLp = (lab2->l - lab1->l);
+  DCp = (Cp2 - Cp1);
+
+  if (Cp1Cp2 == 0.0)
+    {
+      dhp = 0.0;
+      DHp = 0.0;
+
+      hp = hp1 + hp2;
+    }
+  else
+    {
+      dhp = (hp2 - hp1);
+      if (dhp > G_PI)
+        dhp -= _2PI;
+
+      if (dhp < -G_PI)
+        dhp += _2PI;
+
+      DHp = 2.0 * sqrt (Cp1Cp2) * sin (dhp / 2.0);
+
+      hp = (hp1 + hp2) / 2.0;
+      if (fabs (hp1 - hp2) > G_PI)
+        hp -= G_PI;
+
+      if (hp < 0)
+        hp += _2PI;
+    }
+
+  Lp = (lab1->l + lab2->l) / 2.0;
+  Cp = (Cp1 + Cp2) / 2.0;
+
+  T = 1.0 - 0.17 * cos (hp - PI_d_6) +
+      0.24 * cos (2.0 * hp) +
+      0.32 * cos (3.0 * hp + PI_d_30) -
+      0.20 * cos (4.0 * hp - _63PI_d_180);
+
+  Dtheta_rad = _30PI_d_180 * exp (-pow (((_180_d_PI * hp - 275.0) / 25.0), 2.0));
+
+  Rc = 2.0 * sqrt (pow (Cp, 7.0) / (pow (Cp, 7.0) + _25_pow_7));
+
+  _50Lp_pow2 = (Lp - 50.0) * (Lp - 50.0);
+  SL = 1.0 + (0.015 * _50Lp_pow2 / sqrt (20.0 + _50Lp_pow2));
+  SC = 1.0 + 0.045 * Cp;
+  SH = 1.0 + 0.015 * Cp * T;
+
+  RT = -sin (2.0 * Dtheta_rad) * Rc;
+
+  return sqrt( pow ((DLp / SL), 2.0) +
+         pow((DCp / SC), 2.0) +
+         pow((DHp / SH), 2.0) +
+         RT * (DCp / SC) * (DHp / SH));
+}
diff --git a/contrib/gstyle/gstyle-color-convert.h b/contrib/gstyle/gstyle-color-convert.h
new file mode 100644
index 0000000..7f2071a
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-convert.h
@@ -0,0 +1,75 @@
+/* gstyle-color-convert.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_CONVERT_H
+#define GSTYLE_COLOR_CONVERT_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+#include "gstyle-types.h"
+#include "gstyle-cielab.h"
+#include "gstyle-hsv.h"
+#include "gstyle-xyz.h"
+
+G_BEGIN_DECLS
+
+void                  gstyle_color_convert_rgb_to_hsl       (GdkRGBA             *rgba,
+                                                             gdouble             *hue,
+                                                             gdouble             *saturation,
+                                                             gdouble             *lightness);
+void                  gstyle_color_convert_rgb_to_hsv       (GdkRGBA             *rgba,
+                                                             gdouble             *hue,
+                                                             gdouble             *saturation,
+                                                             gdouble             *value);
+void                  gstyle_color_convert_hsl_to_rgb       (gdouble              hue,
+                                                             gdouble              saturation,
+                                                             gdouble              lightness,
+                                                             GdkRGBA             *rgba);
+void                  gstyle_color_convert_hsv_to_rgb       (gdouble              hue,
+                                                             gdouble              saturation,
+                                                             gdouble              value,
+                                                             GdkRGBA             *rgba);
+void                  gstyle_color_convert_rgb_to_cielab    (GdkRGBA             *rgba,
+                                                             GstyleCielab        *lab);
+void                  gstyle_color_convert_cielab_to_rgb    (GstyleCielab        *lab,
+                                                             GdkRGBA             *rgba);
+gdouble               gstyle_color_delta_e                  (GstyleCielab        *lab1,
+                                                             GstyleCielab        *lab2);
+
+void                  gstyle_color_convert_rgb_to_xyz       (GdkRGBA             *rgba,
+                                                             GstyleXYZ           *xyz);
+extern void           gstyle_color_convert_cielab_to_xyz    (GstyleCielab        *lab,
+                                                             GstyleXYZ           *xyz);
+void                  gstyle_color_convert_hsv_to_xyz       (gdouble              hue,
+                                                             gdouble              saturation,
+                                                             gdouble              value,
+                                                             GstyleXYZ           *xyz);
+
+extern void           gstyle_color_convert_xyz_to_cielab    (GstyleXYZ           *xyz,
+                                                             GstyleCielab        *lab);
+extern void           gstyle_color_convert_xyz_to_rgb       (GstyleXYZ           *xyz,
+                                                             GdkRGBA             *rgba);
+void                  gstyle_color_convert_xyz_to_hsv       (GstyleXYZ           *xyz,
+                                                             gdouble             *hue,
+                                                             gdouble             *saturation,
+                                                             gdouble             *value);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_CONVERT_H */
diff --git a/contrib/gstyle/gstyle-color-filter.c b/contrib/gstyle/gstyle-color-filter.c
new file mode 100644
index 0000000..a264ee0
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-filter.c
@@ -0,0 +1,42 @@
+/* gstyle-color-filter.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gstyle-color-filter.h"
+
+static gdouble web_colors [] = {0.0, 0.2, 0.2, 0.4, 0.4 , 0.6 , 0.6, 0.8, 0.8, 1.0, 1.0};
+#define TO_WEB_COLOR(x) (web_colors [(gint)(x * 10.0)])
+
+/**
+ * gstyle_color_filter_func:
+ * @rgba: The source #GdkRGBA color
+ * @filter_rgba: (out): the filtered #GdkRGBA color
+ * @user_data: A user data pointer
+ *
+ * A WebSafe Color filter usable with #GstyleColorScale and GstyleColorPlane.
+ *
+ */
+void
+gstyle_color_filter_websafe (GdkRGBA  *rgba,
+                             GdkRGBA  *filter_rgba,
+                             gpointer  user_data)
+{
+  filter_rgba->red = TO_WEB_COLOR (rgba->red);
+  filter_rgba->green = TO_WEB_COLOR (rgba->green);
+  filter_rgba->blue  = TO_WEB_COLOR (rgba->blue);
+  filter_rgba->alpha = rgba->alpha;
+}
diff --git a/contrib/gstyle/gstyle-color-filter.h b/contrib/gstyle/gstyle-color-filter.h
new file mode 100644
index 0000000..085bd5a
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-filter.h
@@ -0,0 +1,36 @@
+/* gstyle-color-filter.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_FILTER_H
+#define GSTYLE_COLOR_FILTER_H
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+typedef void (*GstyleColorFilter)(GdkRGBA *rgba, GdkRGBA *filter_rgba, gpointer user_data);
+
+void           gstyle_color_filter_websafe        (GdkRGBA          *rgba,
+                                                   GdkRGBA          *filter_rgba,
+                                                   gpointer          user_data);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_FILTER_H */
+
diff --git a/contrib/gstyle/gstyle-color-item.c b/contrib/gstyle/gstyle-color-item.c
new file mode 100644
index 0000000..36fa795
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-item.c
@@ -0,0 +1,209 @@
+/* gstyle-color-item.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-color-item"
+
+#include "gstyle-color-item.h"
+
+G_DEFINE_BOXED_TYPE (GstyleColorItem, gstyle_color_item, gstyle_color_item_ref, gstyle_color_item_unref)
+
+/**
+ * gstyle_color_item_get_color:
+ * @self: A #GstyleColorItem
+ *
+ * Get the #GstyleColor inside the #GstyleColorItem.
+ *
+ * Returns: (transfer none): A #GstyleColor.
+ *
+ */
+const GstyleColor *
+gstyle_color_item_get_color (GstyleColorItem *self)
+{
+  g_return_val_if_fail (self != NULL, NULL);
+
+  return self->color;
+}
+
+/**
+ * gstyle_color_item_set_color:
+ * @self: A #GstyleColorItem
+ * @color: (nullable): A #GstyleColor or %NULL
+ *
+ * Set the #GstyleColor inside the #GstyleColorItem.
+ *
+ */
+void
+gstyle_color_item_set_color (GstyleColorItem *self,
+                             GstyleColor     *color)
+{
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (GSTYLE_IS_COLOR (color));
+
+  g_clear_object (&self->color);
+  self->color = g_object_ref (color);
+}
+
+/**
+ * gstyle_color_item_get_start:
+ * @self: A #GstyleColorItem
+ *
+ * Get the start position of the #GstyleColorItem.
+ *
+ * Returns: a position in bytes, in the analysed buffer, starting from offset 0.
+ *
+ */
+guint
+gstyle_color_item_get_start (GstyleColorItem *self)
+{
+  g_return_val_if_fail (self != NULL, 0);
+
+  return self->start;
+}
+
+/**
+ * gstyle_color_item_get_len:
+ * @self: A #GstyleColorItem
+ *
+ * Get the size of the #GstyleColorItem.
+ *
+ * Returns: the #GstyleColorItem size in bytes.
+ *
+ */
+guint
+gstyle_color_item_get_len (GstyleColorItem *self)
+{
+  g_return_val_if_fail (self != NULL, 0);
+
+  return self->len;
+}
+
+/**
+ * gstyle_color_item_copy:
+ * @self: a #GstyleColorItem
+ *
+ * Makes a deep copy of a #GstyleColorItem
+ *
+ * The result must be freed with gstyle_color_item_free()
+ * or un-refed with gstyle_color_item_unref().
+ *
+ * Returns: (transfer full): A newly allocated #GstyleColorItem, with the same contents as @self
+ *
+ */
+GstyleColorItem *
+gstyle_color_item_copy (GstyleColorItem *self)
+{
+  GstyleColorItem *item;
+  GstyleColor *src_color;
+
+  g_return_val_if_fail (self != NULL, NULL);
+
+  item = g_slice_dup (GstyleColorItem, self);
+
+  src_color = (GstyleColor *)gstyle_color_item_get_color (self);
+  if (src_color != NULL && GSTYLE_IS_COLOR (src_color))
+    self->color = gstyle_color_copy (src_color);
+
+  return item;
+}
+
+/**
+ * gstyle_color_item_free:
+ * @self: a #GstyleColorItem
+ *
+ * Free a #GstyleColorItem created with gstyle_color_item_copy().
+ *
+ */
+void
+gstyle_color_item_free (GstyleColorItem *self)
+{
+  g_return_if_fail (self != NULL);
+  g_assert_cmpint (self->ref_count, ==, 0);
+
+  if (self->color != NULL && GSTYLE_IS_COLOR (self->color))
+    g_object_unref (self->color);
+
+  g_slice_free (GstyleColorItem, self);
+}
+
+/**
+ * gstyle_color_item_new:
+ * @color: (nullable): A #GstyleColor or NULL
+ * @start: start offset of the item
+ * @len: length of the item
+ *
+ * Return a new #GstyleColorItem.
+ * It must be freed with gstyle_color_item_free().
+ *
+ * Returns: a #GstyleColorItem.
+ *
+ */
+GstyleColorItem *
+gstyle_color_item_new (GstyleColor *color,
+                       gint         start,
+                       gint         len)
+{
+  GstyleColorItem *item;
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR (color) || color == NULL, NULL);
+
+  item = g_slice_new0 (GstyleColorItem);
+  item->ref_count = 1;
+  item->start = start;
+  item->len = len;
+
+  if (color != NULL)
+    item->color = g_object_ref (color);
+
+  return item;
+}
+
+/**
+ * gstyle_color_item_ref:
+ * @self: An #GstyleColorItem
+ *
+ * Increments the reference count of @self by one.
+ *
+ * Returns: (transfer none): @self
+ */
+GstyleColorItem *
+gstyle_color_item_ref (GstyleColorItem *self)
+{
+  g_return_val_if_fail (self != NULL, NULL);
+  g_return_val_if_fail (self->ref_count, NULL);
+
+  g_atomic_int_inc (&self->ref_count);
+
+  return self;
+}
+
+/**
+ * gstyle_color_item_unref:
+ * @self: (transfer none): An #GstyleColorItem
+ *
+ * Decrements the reference count of @GstyleColorItem by one, freeing the structure
+ * when the reference count reaches zero.
+ */
+void
+gstyle_color_item_unref (GstyleColorItem *self)
+{
+  g_return_if_fail (self != NULL);
+  g_return_if_fail (self->ref_count);
+
+  if (g_atomic_int_dec_and_test (&self->ref_count))
+    gstyle_color_item_free (self);
+}
diff --git a/contrib/gstyle/gstyle-color-item.h b/contrib/gstyle/gstyle-color-item.h
new file mode 100644
index 0000000..20a12d9
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-item.h
@@ -0,0 +1,58 @@
+/* gstyle-color-item.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_ITEM_H
+#define GSTYLE_COLOR_ITEM_H
+
+#include <glib.h>
+
+#include "gstyle-types.h"
+#include "gstyle-color.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_COLOR_ITEM (gstyle_color_item_get_type ())
+
+struct _GstyleColorItem
+{
+  GstyleColor    *color;
+  guint           start;
+  guint           len;
+  volatile gint   ref_count;
+};
+
+GType                gstyle_color_item_get_type                (void) G_GNUC_CONST;
+
+GstyleColorItem     *gstyle_color_item_new                     (GstyleColor      *color,
+                                                                gint              start,
+                                                                gint              len);
+GstyleColorItem     *gstyle_color_item_copy                    (GstyleColorItem  *self);
+void                 gstyle_color_item_free                    (GstyleColorItem  *self);
+GstyleColorItem     *gstyle_color_item_ref                     (GstyleColorItem  *self);
+void                 gstyle_color_item_unref                   (GstyleColorItem  *self);
+
+const GstyleColor   *gstyle_color_item_get_color               (GstyleColorItem  *self);
+void                 gstyle_color_item_set_color               (GstyleColorItem  *self,
+                                                                GstyleColor      *color);
+
+guint                gstyle_color_item_get_start               (GstyleColorItem  *self);
+guint                gstyle_color_item_get_len                 (GstyleColorItem  *self);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_ITEM_H */
diff --git a/contrib/gstyle/gstyle-color-panel-actions.c b/contrib/gstyle/gstyle-color-panel-actions.c
new file mode 100644
index 0000000..53cd501
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-panel-actions.c
@@ -0,0 +1,84 @@
+/* gstyle-color-panel-actions.c
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-color-panel"
+
+#include "gstyle-color-panel-private.h"
+#include "gstyle-color-panel.h"
+#include "gstyle-slidein.h"
+
+#include "gstyle-color-panel-actions.h"
+
+static void
+gstyle_color_panel_actions_toggle_page (GSimpleAction *action,
+                                        GVariant      *variant,
+                                        gpointer       user_data)
+{
+  GstyleColorPanel *self = (GstyleColorPanel *)user_data;
+  g_autoptr (GVariant) value = NULL;
+  g_autofree gchar *page_name = NULL;
+  const gchar *name;
+  gboolean state;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  value = g_action_get_state (G_ACTION (action));
+  state = g_variant_get_boolean (value);
+  name = g_action_get_name(G_ACTION (action));
+  if (!g_str_has_prefix (name, "toggle-"))
+    return;
+
+  page_name = g_strdup (&name [7]);
+  g_simple_action_set_state (action, g_variant_new_boolean (!state));
+  if (!state)
+    {
+      _gstyle_color_panel_update_prefs_page (self, page_name);
+      gtk_stack_set_visible_child_name (self->prefs_stack, page_name);
+    }
+
+  gstyle_slidein_reveal_slide (GSTYLE_SLIDEIN (self->prefs_slidein),
+                               !gstyle_slidein_get_revealed (GSTYLE_SLIDEIN (self->prefs_slidein)));
+}
+
+static GActionEntry ColorPanelPagesPrefsActions[] = {
+  { "toggle-components-page", NULL, "b", "false", gstyle_color_panel_actions_toggle_page },
+  { "toggle-colorstrings-page", NULL, "b", "false", gstyle_color_panel_actions_toggle_page },
+  { "toggle-palettes-page", NULL, "b", "false", gstyle_color_panel_actions_toggle_page },
+  { "toggle-paletteslist-page", NULL, "b", "false", gstyle_color_panel_actions_toggle_page },
+};
+
+void
+gstyle_color_panel_actions_init (GstyleColorPanel *self)
+{
+  g_autoptr (GSimpleActionGroup) pages_group = NULL;
+  GActionGroup *palette_widget_actions_group;
+
+  pages_group = g_simple_action_group_new ();
+  g_action_map_add_action_entries (G_ACTION_MAP (pages_group), ColorPanelPagesPrefsActions,
+                                   G_N_ELEMENTS (ColorPanelPagesPrefsActions), self);
+  gtk_widget_insert_action_group (GTK_WIDGET (self), "gstyle-pages-prefs", G_ACTION_GROUP (pages_group));
+
+  if (self->palette_widget != NULL)
+    {
+      palette_widget_actions_group = gtk_widget_get_action_group (GTK_WIDGET (self->palette_widget), 
"gstyle-palettes-prefs");
+      if (palette_widget_actions_group != NULL)
+        gtk_widget_insert_action_group (GTK_WIDGET (self),
+                                        "gstyle-palettes-prefs",
+                                        palette_widget_actions_group);
+    }
+}
diff --git a/contrib/gstyle/gstyle-color-panel-actions.h b/contrib/gstyle/gstyle-color-panel-actions.h
new file mode 100644
index 0000000..9a59593
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-panel-actions.h
@@ -0,0 +1,32 @@
+/* gstyle-color-panel-actions.h
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef GSTYLE_COLOR_PANEL_ACTIONS_H
+#define GSTYLE_COLOR_PANEL_ACTIONS_H
+
+#include <glib-object.h>
+
+#include "gstyle-color-panel.h"
+
+G_BEGIN_DECLS
+
+void gstyle_color_panel_actions_init   (GstyleColorPanel *self);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_PANEL_ACTIONS_H */
+
diff --git a/contrib/gstyle/gstyle-color-panel-private.h b/contrib/gstyle/gstyle-color-panel-private.h
new file mode 100644
index 0000000..1b70997
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-panel-private.h
@@ -0,0 +1,151 @@
+/* gstyle-color-panel-private.h
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_PANEL_PRIVATE_H
+#define GSTYLE_COLOR_PANEL_PRIVATE_H
+
+#include <glib-object.h>
+
+#include <fuzzy.h>
+
+#include "gstyle-cielab.h"
+#include "gstyle-color.h"
+#include "gstyle-color-convert.h"
+#include "gstyle-color-component.h"
+#include "gstyle-color-plane.h"
+#include "gstyle-color-scale.h"
+#include "gstyle-color-widget.h"
+#include "gstyle-css-provider.h"
+#include "gstyle-eyedropper.h"
+#include "gstyle-palette-widget.h"
+#include "gstyle-revealer.h"
+#include "gstyle-slidein.h"
+#include "gstyle-utils.h"
+
+#include "gstyle-color-panel.h"
+
+G_BEGIN_DECLS
+
+#define PREFS_COMPONENTS_PAGE    "components-page"
+#define PREFS_COLOR_STRINGS_PAGE "colorstrings-page"
+#define PREFS_PALETTES_PAGE      "palettes-page"
+#define PREFS_PALETTES_LIST_PAGE "paletteslist-page"
+
+typedef struct _ColorComp
+{
+  GtkToggleButton  *toggle;
+  GtkSpinButton    *spin;
+  GstyleColorScale *scale;
+
+  gulong            toggle_handler_id;
+} ColorComp;
+
+struct _GstyleColorPanel
+{
+  GtkBox                               parent_instance;
+
+  GstyleCssProvider                   *default_provider;
+
+  GstyleColorPlane                    *color_plane;
+  GtkAdjustment                       *adj_alpha;
+
+  GstyleColor                         *new_color;
+  GstyleColor                         *old_color;
+  GstyleColorWidget                   *new_swatch;
+  GstyleColorWidget                   *old_swatch;
+
+  GtkButton                           *picker_button;
+  GstyleEyedropper                    *eyedropper;
+  GtkWidget                           *search_color_entry;
+  GtkWidget                           *search_strings_popover;
+  GtkWidget                           *search_strings_list;
+
+  Fuzzy                               *fuzzy;
+
+  GtkToggleButton                     *components_toggle;
+  GtkToggleButton                     *strings_toggle;
+  GtkToggleButton                     *palette_toggle;
+
+  GtkWidget                           *hsv_grid;
+  GtkWidget                           *lab_grid;
+  GtkWidget                           *rgb_grid;
+
+  GstyleRevealer                      *scale_reveal;
+  GstyleRevealer                      *string_reveal;
+  GstyleRevealer                      *palette_reveal;
+
+  GtkWidget                           *components_controls;
+  GtkWidget                           *strings_controls;
+  GtkWidget                           *palette_controls;
+
+  GstyleColorScale                    *ref_scale;
+  GstyleColorScale                    *alpha_scale;
+
+  GtkLabel                            *res_hex3_label;
+  GtkLabel                            *res_hex6_label;
+  GtkLabel                            *res_rgb_label;
+  GtkLabel                            *res_rgba_label;
+  GtkLabel                            *res_hsl_label;
+  GtkLabel                            *res_hsla_label;
+
+  GtkLabel                            *hex3_label;
+  GtkLabel                            *hex6_label;
+  GtkLabel                            *rgb_label;
+  GtkLabel                            *rgba_label;
+  GtkLabel                            *hsl_label;
+  GtkLabel                            *hsla_label;
+
+  GstylePaletteWidget                 *palette_widget;
+
+  GIcon                               *degree_icon;
+  GIcon                               *percent_icon;
+
+  GtkToggleButton                     *components_prefs_button;
+  GtkToggleButton                     *color_strings_prefs_button;
+  GtkToggleButton                     *palettes_prefs_button;
+  GtkToggleButton                     *palettes_list_prefs_button;
+  GtkToggleButton                     *last_checked_prefs_button;
+
+  gulong                               components_prefs_button_handler_id;
+  gulong                               color_strings_prefs_button_handler_id;
+  gulong                               palettes_prefs_button_handler_id;
+  gulong                               palettes_list_prefs_button_handler_id;
+
+  GtkWidget                           *components_prefs_bin;
+  GtkWidget                           *color_strings_prefs_bin;
+  GtkWidget                           *palettes_prefs_bin;
+  GtkWidget                           *palettes_list_prefs_bin;
+
+  ColorComp                            components [N_GSTYLE_COLOR_COMPONENT];
+  GstyleColorComponent                 current_comp;
+  GstyleColorUnit                      preferred_unit;
+
+  GstyleSlidein                       *prefs_slidein;
+  GtkStack                            *prefs_stack;
+  GtkWidget                           *last_toggled_prefs;
+
+  GstyleColorPanelStringsVisibleFlags  strings_visible_flags;
+};
+
+void                  _gstyle_color_panel_update_prefs_page                   (GstyleColorPanel       *self,
+                                                                               const gchar            
*page_name);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_PANEL_PRIVATE_H */
+
diff --git a/contrib/gstyle/gstyle-color-panel.c b/contrib/gstyle/gstyle-color-panel.c
new file mode 100644
index 0000000..7832d41
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-panel.c
@@ -0,0 +1,1465 @@
+/* gstyle-color-panel.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-color-panel"
+
+#include <glib/gi18n.h>
+
+#include "gstyle-color-panel-private.h"
+#include "gstyle-color-panel-actions.h"
+#include "gstyle-revealer.h"
+#include "gstyle-color.h"
+
+#define HSV_TO_SCALE_FACTOR (1.0 / 256.0)
+#define CIELAB_L_TO_SCALE_FACTOR (100.0 / 256.0)
+
+#define PREFS_BOX_MARGIN (10)
+
+G_DEFINE_TYPE (GstyleColorPanel, gstyle_color_panel, GTK_TYPE_BOX)
+
+static gchar * comp_names [N_GSTYLE_COLOR_COMPONENT] =
+  {
+    "hsv_h",
+    "hsv_s",
+    "hsv_v",
+    "lab_l",
+    "lab_a",
+    "lab_b",
+    "rgb_red",
+    "rgb_green",
+    "rgb_blue"
+  };
+
+/* Conversion between component and color plane mode :
+ * component without a corresponding mode return
+ * GSTYLE_COLOR_PLANE_MODE_NONE
+ */
+static GstyleColorPlaneMode component_to_plane_mode [N_GSTYLE_COLOR_COMPONENT] =
+  {
+    GSTYLE_COLOR_PLANE_MODE_HUE,
+    GSTYLE_COLOR_PLANE_MODE_SATURATION,
+    GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS,
+    GSTYLE_COLOR_PLANE_MODE_CIELAB_L,
+    GSTYLE_COLOR_PLANE_MODE_CIELAB_A,
+    GSTYLE_COLOR_PLANE_MODE_CIELAB_B,
+    GSTYLE_COLOR_PLANE_MODE_RED,
+    GSTYLE_COLOR_PLANE_MODE_GREEN,
+    GSTYLE_COLOR_PLANE_MODE_BLUE
+  };
+
+enum {
+  PROP_0,
+  PROP_HSV_VISIBLE,
+  PROP_LAB_VISIBLE,
+  PROP_RGB_VISIBLE,
+  PROP_RGB_UNIT,
+  PROP_STRINGS_VISIBLE,
+  PROP_RGBA,
+  PROP_XYZ,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+enum {
+  UPDATE_PREFS,
+  LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL];
+
+/**
+ * gstyle_color_panel_get_rgba:
+ * @self: A #GstyleColorPanel.
+ * @rgba: (out): A #GdkRGBA adress.
+ *
+ * Fill @rgba with the current color plane rgba.
+ *
+ */
+void
+gstyle_color_panel_get_rgba (GstyleColorPanel *self,
+                             GdkRGBA          *rgba)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_PANEL (self));
+
+  gstyle_color_plane_get_rgba (self->color_plane, rgba);
+  rgba->alpha = gtk_adjustment_get_value (self->adj_alpha) / 100.0;
+}
+
+/**
+ * gstyle_color_panel_get_xyz:
+ * @self: A #GstyleColorPanel.
+ * @xyz: (out): A #GstyleXYZ adress.
+ *
+ * Fill @xyz with the current color plane xyz.
+ *
+ */
+void
+gstyle_color_panel_get_xyz (GstyleColorPanel *self,
+                            GstyleXYZ        *xyz)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_PANEL (self));
+
+  gstyle_color_plane_get_xyz (self->color_plane, xyz);
+  xyz->alpha = gtk_adjustment_get_value (self->adj_alpha) / 100.0;
+}
+
+/**
+ * gstyle_color_panel_set_rgba:
+ * @self: A #GstyleColorPanel.
+ * @rgba: A #GdkRGBA.
+ *
+ * Set the color plane and sliders to rgba.
+ *
+ */
+void
+gstyle_color_panel_set_rgba (GstyleColorPanel *self,
+                             const GdkRGBA    *rgba)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_PANEL (self));
+
+  gtk_adjustment_set_value (self->adj_alpha, rgba->alpha * 100.0);
+  gstyle_color_plane_set_rgba (self->color_plane, rgba);
+}
+
+/**
+ * gstyle_color_panel_set_xyz:
+ * @self: A #GstyleColorPanel.
+ * @xyz: A #GstyleXYZ.
+ *
+ * Set the color plane and sliders to the xyz value.
+ *
+ */
+void
+gstyle_color_panel_set_xyz (GstyleColorPanel *self,
+                            const GstyleXYZ  *xyz)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_PANEL (self));
+
+  gtk_adjustment_set_value (self->adj_alpha, xyz->alpha * 100.0);
+  gstyle_color_plane_set_xyz (self->color_plane, xyz);
+}
+
+/**
+ * gstyle_color_panel_get_palette_widget:
+ * @self: A #GstyleColorPanel.
+ *
+ * Returns: (nullable) (transfer none): The #GstylePaletteWidget used by the panel.
+ *
+ */
+GstylePaletteWidget *
+gstyle_color_panel_get_palette_widget (GstyleColorPanel *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR_PANEL (self), NULL);
+
+  return self->palette_widget;
+}
+
+static void
+update_hsv_hue_color_ramp (GstyleColorPanel *self,
+                           GstyleColorScale *scale,
+                           GdkRGBA          *rgba)
+{
+  gdouble hue;
+  guint32 *data;
+  GdkRGBA dst_rgba = {0};
+
+  /* TODO: malloc in init and keep data around */
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      hue = x * HSV_TO_SCALE_FACTOR;
+      gstyle_color_convert_hsv_to_rgb (hue, 1.0, 1.0, &dst_rgba);
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_hsv_saturation_color_ramp (GstyleColorPanel *self,
+                                  GstyleColorScale *scale,
+                                  GdkRGBA          *rgba)
+{
+  gdouble hue, saturation, value;
+  guint32 *data;
+  GdkRGBA dst_rgba = {0};
+
+  /* TODO: malloc in init and keep data around */
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  gstyle_color_convert_rgb_to_hsv (rgba, &hue, &saturation, &value);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      saturation = x * HSV_TO_SCALE_FACTOR;
+      gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &dst_rgba);
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_hsv_value_color_ramp (GstyleColorPanel *self,
+                             GstyleColorScale *scale,
+                             GdkRGBA          *rgba)
+{
+  gdouble hue, saturation, value;
+  guint32 *data;
+  GdkRGBA dst_rgba = {0};
+
+  /* TODO: malloc in init and keep data around */
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  gstyle_color_convert_rgb_to_hsv (rgba, &hue, &saturation, &value);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      value = x * HSV_TO_SCALE_FACTOR;
+      gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &dst_rgba);
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_rgb_red_color_ramp (GstyleColorPanel *self,
+                           GstyleColorScale *scale,
+                           GdkRGBA          *rgba)
+{
+  guint32 *data;
+  GdkRGBA dst_rgba = *rgba;
+
+  /* TODO: malloc in init and keep data around */
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      dst_rgba.red = x / 256.0;
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_rgb_green_color_ramp (GstyleColorPanel *self,
+                             GstyleColorScale *scale,
+                             GdkRGBA          *rgba)
+{
+  guint32 *data;
+  GdkRGBA dst_rgba = *rgba;
+
+  /* TODO: malloc in init and keep data around */
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      dst_rgba.green = x / 256.0;
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_rgb_blue_color_ramp (GstyleColorPanel *self,
+                            GstyleColorScale *scale,
+                            GdkRGBA          *rgba)
+{
+  guint32 *data;
+  GdkRGBA dst_rgba = *rgba;
+
+  /* TODO: malloc in init and keep data around */
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      dst_rgba.blue = x / 256.0;
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_lab_l_color_ramp (GstyleColorPanel *self,
+                         GstyleColorScale *scale,
+                         GdkRGBA          *rgba)
+{
+  GstyleCielab lab;
+  GdkRGBA dst_rgba = {0};
+  guint32 *data;
+
+  /* TODO: malloc in init and keep data around */
+  gstyle_color_convert_rgb_to_cielab (rgba, &lab);
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      lab.l = x * CIELAB_L_TO_SCALE_FACTOR;
+      gstyle_color_convert_cielab_to_rgb (&lab, &dst_rgba);
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_lab_a_color_ramp (GstyleColorPanel *self,
+                         GstyleColorScale *scale,
+                         GdkRGBA          *rgba)
+{
+  GstyleCielab lab;
+  GdkRGBA dst_rgba = {0};
+  guint32 *data;
+
+  /* TODO: malloc in init and keep data around */
+  gstyle_color_convert_rgb_to_cielab (rgba, &lab);
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      lab.a = x - 128;
+      gstyle_color_convert_cielab_to_rgb (&lab, &dst_rgba);
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_lab_b_color_ramp (GstyleColorPanel *self,
+                         GstyleColorScale *scale,
+                         GdkRGBA          *rgba)
+{
+  GstyleCielab lab;
+  GdkRGBA dst_rgba = {0};
+  guint32 *data;
+
+  /* TODO: malloc in init and keep data around */
+  gstyle_color_convert_rgb_to_cielab (rgba, &lab);
+  data = g_malloc0 (GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE);
+  for (gint x = 0; x < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++x)
+    {
+      lab.b = x - 128;
+      gstyle_color_convert_cielab_to_rgb (&lab, &dst_rgba);
+      data [x] = pack_rgba24 (&dst_rgba);
+    }
+
+  gstyle_color_scale_set_custom_data (scale, data);
+  g_free (data);
+}
+
+static void
+update_ref_color_ramp (GstyleColorPanel *self,
+                       GdkRGBA          *rgba)
+{
+  switch (self->current_comp)
+    {
+    case GSTYLE_COLOR_COMPONENT_HSV_H:
+      update_hsv_hue_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_HSV_S:
+      update_hsv_saturation_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_HSV_V:
+      update_hsv_value_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_LAB_L:
+      update_lab_l_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_LAB_A:
+      update_lab_a_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_LAB_B:
+      update_lab_b_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_RGB_RED:
+      update_rgb_red_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_RGB_GREEN:
+      update_rgb_green_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case GSTYLE_COLOR_COMPONENT_RGB_BLUE:
+      update_rgb_blue_color_ramp (self, self->ref_scale, rgba);
+      break;
+
+    case N_GSTYLE_COLOR_COMPONENT:
+    case GSTYLE_COLOR_COMPONENT_NONE:
+    default:
+      break;
+    }
+}
+
+static void
+update_color_strings (GstyleColorPanel *self,
+                      GstyleColor      *color)
+{
+  gchar *str;
+  g_autofree gchar *str_rgb = NULL;
+  g_autofree gchar *str_rgba = NULL;
+  const gchar *label;
+
+  str = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGB_HEX3);
+  label = gtk_label_get_label (self->res_hex3_label);
+  if (g_strcmp0 (str, label) != 0)
+    gtk_label_set_label (self->res_hex3_label, str);
+  g_free (str);
+
+  str = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGB_HEX6);
+  label = gtk_label_get_label (self->res_hex6_label);
+  if (g_strcmp0 (str, label) != 0)
+    gtk_label_set_label (self->res_hex6_label, str);
+  g_free (str);
+
+  if (self->preferred_unit == GSTYLE_COLOR_UNIT_PERCENT)
+    {
+      str_rgb = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGB_PERCENT);
+      str_rgba = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGBA_PERCENT);
+    }
+  else if (self->preferred_unit == GSTYLE_COLOR_UNIT_VALUE)
+    {
+      str_rgb = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGB);
+      str_rgba = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGBA);
+    }
+  else
+    g_assert_not_reached ();
+
+  label = gtk_label_get_label (self->res_rgb_label);
+  if (g_strcmp0 (str_rgb, label) != 0)
+    gtk_label_set_label (self->res_rgb_label, str_rgb);
+
+  label = gtk_label_get_label (self->res_rgba_label);
+  if (g_strcmp0 (str_rgba, label) != 0)
+    gtk_label_set_label (self->res_rgba_label, str_rgba);
+
+  str = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_HSL);
+  label = gtk_label_get_label (self->res_hsl_label);
+  if (g_strcmp0 (str, label) != 0)
+    gtk_label_set_label (self->res_hsl_label, str);
+  g_free (str);
+
+  str = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_HSLA);
+  label = gtk_label_get_label (self->res_hsla_label);
+  if (g_strcmp0 (str, label) != 0)
+    gtk_label_set_label (self->res_hsla_label, str);
+  g_free (str);
+}
+
+static void
+color_picked_cb (GstyleColorPanel *self,
+                 GdkRGBA          *rgba)
+{
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  gstyle_color_plane_set_rgba (self->color_plane, rgba);
+}
+
+static void
+grab_released_cb (GstyleColorPanel *self)
+{
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  /* FIX: release the eyedropper here cause a Segfault  */
+  //g_clear_object (&self->eyedropper);
+}
+
+static void
+picker_button_clicked_cb (GstyleColorPanel *self,
+                          GtkButton        *picker_button)
+{
+  GdkEvent *event;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (GTK_IS_BUTTON (picker_button));
+
+  event = gtk_get_current_event ();
+  g_assert (event != NULL);
+
+  self->eyedropper = g_object_new (GSTYLE_TYPE_EYEDROPPER,
+                                   "source-event", event,
+                                   NULL);
+  gdk_event_free (event);
+
+  g_signal_connect_swapped (self->eyedropper,
+                            "color-picked",
+                            G_CALLBACK (color_picked_cb),
+                            self);
+
+  g_signal_connect_swapped (self->eyedropper,
+                            "grab-released",
+                            G_CALLBACK (grab_released_cb),
+                            self);
+}
+
+static void
+palette_row_activated_cb (GstyleColorPanel    *self,
+                          GstylePalette       *palette,
+                          gint                 position,
+                          GstylePaletteWidget *palette_widget)
+{
+  const GstyleColor *color;
+  GdkRGBA rgba = {0};
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (GSTYLE_IS_PALETTE (palette));
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (palette_widget));
+
+  color = gstyle_palette_get_color_at_index (palette, position);
+  gstyle_color_fill_rgba ((GstyleColor *)color, &rgba);
+
+  gstyle_color_panel_set_rgba (self, &rgba);
+}
+
+static void
+update_sub_panels (GstyleColorPanel *self,
+                   GdkRGBA           rgba)
+{
+   g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  rgba.alpha = gtk_adjustment_get_value (self->adj_alpha) / 100.0;
+  gstyle_color_set_rgba (self->old_color, &rgba);
+  update_color_strings (self, self->old_color);
+
+  rgba.alpha = 1.0;
+  /* TODO: compare with old value and update only when needed */
+
+  update_hsv_hue_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_HSV_H].scale, &rgba);
+  update_hsv_saturation_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_HSV_S].scale, &rgba);
+  update_hsv_value_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_HSV_V].scale, &rgba);
+
+  update_rgb_red_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_RGB_RED].scale, &rgba);
+  update_rgb_green_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_RGB_GREEN].scale, &rgba);
+  update_rgb_blue_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_RGB_BLUE].scale, &rgba);
+
+  update_lab_l_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_LAB_L].scale, &rgba);
+  update_lab_a_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_LAB_A].scale, &rgba);
+  update_lab_b_color_ramp (self, self->components [GSTYLE_COLOR_COMPONENT_LAB_B].scale, &rgba);
+
+  update_ref_color_ramp (self, &rgba);
+}
+
+static void
+component_toggled_cb (GstyleColorPanel *self,
+                      GtkToggleButton  *toggle)
+{
+  GdkRGBA rgba = {0};
+  GtkAdjustment *adj;
+
+  if (!gtk_toggle_button_get_active (toggle))
+    {
+      gtk_toggle_button_set_active (toggle, TRUE);
+      return;
+    }
+
+  for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
+    {
+      if (toggle != self->components [i].toggle)
+        {
+          g_signal_handler_block (self->components [i].toggle, self->components [i].toggle_handler_id);
+          gtk_toggle_button_set_active (self->components [i].toggle, FALSE);
+          g_signal_handler_unblock (self->components [i].toggle, self->components [i].toggle_handler_id);
+        }
+      else
+        {
+          self->current_comp = i;
+          gstyle_color_plane_set_mode (self->color_plane, component_to_plane_mode [i]);
+          adj = gstyle_color_plane_get_component_adjustment (self->color_plane, i);
+          gtk_range_set_adjustment (GTK_RANGE (self->ref_scale), adj);
+
+          gstyle_color_plane_get_rgba (self->color_plane, &rgba);
+          update_ref_color_ramp (self, &rgba);
+        }
+    }
+}
+
+static void
+search_list_add_color (GstyleColorPanel *self,
+                       GstyleColor      *color)
+{
+  GtkWidget *color_widget;
+
+  color_widget = g_object_new (GSTYLE_TYPE_COLOR_WIDGET,
+                               "color", color,
+                               "visible", TRUE,
+                               "halign", GTK_ALIGN_FILL,
+                               NULL);
+
+  gtk_list_box_insert (GTK_LIST_BOX (self->search_strings_list), color_widget, -1);
+}
+
+static void
+search_color_entry_changed_cb (GstyleColorPanel *self,
+                               GtkSearchEntry   *entry)
+{
+  g_autoptr (GPtrArray) ar = NULL;
+  GstyleColor *color;
+  const gchar *str;
+  GList *children;
+  GList *l;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (GTK_IS_SEARCH_ENTRY (entry));
+
+  str = gtk_entry_get_text(GTK_ENTRY(entry));
+  if (gstyle_str_empty0 (str))
+    {
+      gtk_widget_set_visible (self->search_strings_popover, FALSE);
+      return;
+    }
+
+  children = gtk_container_get_children (GTK_CONTAINER (self->search_strings_list));
+  for (l = children; l != NULL; l = g_list_next (l))
+    gtk_widget_destroy (GTK_WIDGET (l->data));
+
+  if (str[0] == '#' || g_str_has_prefix (str, "rgb") || g_str_has_prefix (str, "hsl"))
+    {
+      color = gstyle_color_new_from_string (NULL, str);
+      if (color != NULL)
+        {
+          search_list_add_color (self, color);
+          gtk_widget_set_visible (self->search_strings_popover, TRUE);
+        }
+    }
+  else
+    {
+      ar = gstyle_color_fuzzy_parse_color_string (str);
+      for (gint i = 0; i < ar->len; ++i)
+        {
+          color = g_ptr_array_index (ar, i);
+          search_list_add_color (self, color);
+        }
+
+      gtk_widget_set_visible (self->search_strings_popover, (ar->len > 0));
+    }
+}
+
+static void
+adj_alpha_value_changed_cb (GstyleColorPanel *self,
+                            GtkAdjustment    *adj)
+{
+  gdouble alpha;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  alpha = gtk_adjustment_get_value (self->adj_alpha) / 100.0;
+  gstyle_color_set_alpha (self->old_color, alpha);
+  update_color_strings (self, self->old_color);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RGBA]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_XYZ]);
+}
+
+static GIcon *
+get_degree_icon (GstyleColorPanel *self)
+{
+  GIcon *icon;
+  g_autoptr (GFile) file = NULL;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  file = g_file_new_for_uri ("resource:///org/gnome/libgstyle/icons/unit-degree-symbolic.svg");
+  icon = g_file_icon_new (file);
+
+  return icon;
+}
+
+static GIcon *
+get_percent_icon (GstyleColorPanel *self)
+{
+  GIcon *icon;
+  g_autoptr (GFile) file = NULL;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  file = g_file_new_for_uri ("resource:///org/gnome/libgstyle/icons/unit-percent-symbolic.svg");
+  icon = g_file_icon_new (file);
+
+  return icon;
+}
+
+static void
+set_preferred_unit (GstyleColorPanel *self,
+                   GstyleColorUnit  preferred_unit)
+{
+  GIcon *icon;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  if (self->preferred_unit != preferred_unit)
+    {
+      self->preferred_unit = preferred_unit;
+      if (preferred_unit == GSTYLE_COLOR_UNIT_PERCENT)
+        icon = self->percent_icon;
+      else if (preferred_unit == GSTYLE_COLOR_UNIT_VALUE)
+        icon = NULL;
+      else
+        g_assert_not_reached ();
+
+      gstyle_color_plane_set_preferred_unit (self->color_plane, preferred_unit);
+      //update_color_strings (self, self->old_color);
+
+      gtk_entry_set_icon_from_gicon (GTK_ENTRY (self->components [GSTYLE_COLOR_COMPONENT_RGB_RED].spin),
+                                     GTK_ENTRY_ICON_SECONDARY, icon);
+      gtk_entry_set_icon_from_gicon (GTK_ENTRY (self->components [GSTYLE_COLOR_COMPONENT_RGB_GREEN].spin),
+                                     GTK_ENTRY_ICON_SECONDARY, icon);
+      gtk_entry_set_icon_from_gicon (GTK_ENTRY (self->components [GSTYLE_COLOR_COMPONENT_RGB_BLUE].spin),
+                                     GTK_ENTRY_ICON_SECONDARY, icon);
+    }
+}
+
+/* TODO: only keep one transformation func ? */
+static gboolean
+rgba_plane_to_new_color (GBinding     *binding,
+                         const GValue *from_value,
+                         GValue       *to_value,
+                         gpointer      user_data)
+{
+  GstyleColorPanel *self = (GstyleColorPanel *)user_data;
+  GdkRGBA *rgba = {0};
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  rgba = g_value_get_boxed (from_value);
+  rgba->alpha = 1.0;
+  g_value_set_boxed (to_value, rgba);
+
+  update_sub_panels (self, *rgba);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RGBA]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_XYZ]);
+
+  return TRUE;
+}
+
+static gboolean
+rgba_new_color_to_plane (GBinding     *binding,
+                         const GValue *from_value,
+                         GValue       *to_value,
+                         gpointer      user_data)
+{
+  GstyleColorPanel *self = (GstyleColorPanel *)user_data;
+  GdkRGBA *rgba = {0};
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  rgba = g_value_get_boxed (from_value);
+  rgba->alpha = 1.0;
+  g_value_set_boxed (to_value, rgba);
+
+  update_sub_panels (self, *rgba);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RGBA]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_XYZ]);
+
+  return TRUE;
+}
+
+static void
+prefs_button_notify_active_cb (GstyleColorPanel *self,
+                               GParamSpec       *pspec,
+                               GtkToggleButton  *button)
+{
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (GTK_IS_TOGGLE_BUTTON (button));
+
+  if (gtk_toggle_button_get_active (button))
+    self->last_checked_prefs_button = button;
+  else
+    self->last_checked_prefs_button = NULL;
+}
+
+static void
+slide_is_closing_cb (GstyleColorPanel *self,
+                     GstyleSlidein    *slidein)
+{
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (GSTYLE_IS_SLIDEIN (slidein));
+
+  if (self->last_checked_prefs_button != NULL)
+    gtk_toggle_button_set_active (self->last_checked_prefs_button, FALSE);
+}
+
+static void
+update_palette_name (GstyleColorPanel *self,
+                     GstylePalette    *palette)
+{
+  const gchar *name;
+  g_autofree gchar *full_name = NULL;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (palette == NULL || GSTYLE_IS_PALETTE (palette));
+
+  if (palette != NULL &&
+      (name = gstyle_palette_get_name (palette)) &&
+      !gstyle_str_empty0 (name))
+    full_name = g_strconcat (_("Palette: "), name, NULL);
+  else
+    full_name = g_strdup (_("Palette"));
+
+  gtk_button_set_label (GTK_BUTTON (self->palette_toggle), full_name);
+}
+
+static void
+palette_selected_notify_cb (GstyleColorPanel    *self,
+                            GParamSpec          *pspec,
+                            GstylePaletteWidget *palette_widget)
+{
+  GstylePalette *palette;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (palette_widget));
+
+  palette = gstyle_palette_widget_get_selected_palette (palette_widget);
+  update_palette_name (self, palette);
+}
+
+void
+_gstyle_color_panel_update_prefs_page (GstyleColorPanel *self,
+                                       const gchar      *page_name)
+{
+  GstyleColorPanelPrefs prefs_type;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  if (g_strcmp0 (page_name, PREFS_COMPONENTS_PAGE) == 0)
+    prefs_type = GSTYLE_COLOR_PANEL_PREFS_COMPONENTS;
+  else if (g_strcmp0 (page_name, PREFS_COLOR_STRINGS_PAGE) == 0)
+    prefs_type = GSTYLE_COLOR_PANEL_PREFS_COLOR_STRINGS;
+  else if (g_strcmp0 (page_name, PREFS_PALETTES_PAGE) == 0)
+    prefs_type = GSTYLE_COLOR_PANEL_PREFS_PALETTES;
+  else if (g_strcmp0 (page_name, PREFS_PALETTES_LIST_PAGE) == 0)
+    prefs_type = GSTYLE_COLOR_PANEL_PREFS_PALETTES_LIST;
+  else
+    g_assert_not_reached ();
+
+  g_signal_emit (self, signals [UPDATE_PREFS], 0, prefs_type);
+}
+
+static void
+replace_prefs_page (GstyleColorPanel  *self,
+                    GtkWidget         *new_page,
+                    GtkWidget        **bin,
+                    const gchar       *page_name)
+{
+  if (*bin != NULL)
+    {
+      gtk_container_remove (GTK_CONTAINER (self->prefs_stack), *bin);
+      *bin = NULL;
+    }
+
+  if (new_page != NULL)
+    {
+      *bin = new_page;
+      gtk_stack_add_named (self->prefs_stack, new_page, page_name);
+    }
+}
+
+void
+gstyle_color_panel_set_prefs_pages (GstyleColorPanel *self,
+                                    GtkWidget        *components_page,
+                                    GtkWidget        *colorstrings_page,
+                                    GtkWidget        *palettes_page,
+                                    GtkWidget        *palettes_list_page)
+{
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (components_page == NULL || GTK_IS_WIDGET (components_page));
+  g_assert (colorstrings_page == NULL || GTK_IS_WIDGET (colorstrings_page));
+  g_assert (palettes_page == NULL || GTK_IS_WIDGET (palettes_page));
+  g_assert (palettes_list_page == NULL || GTK_IS_WIDGET (palettes_list_page));
+
+  replace_prefs_page (self, components_page, &self->components_prefs_bin, PREFS_COMPONENTS_PAGE);
+  replace_prefs_page (self, colorstrings_page, &self->color_strings_prefs_bin, PREFS_COLOR_STRINGS_PAGE);
+  replace_prefs_page (self, palettes_page, &self->palettes_prefs_bin, PREFS_PALETTES_PAGE);
+  replace_prefs_page (self, palettes_list_page, &self->palettes_list_prefs_bin, PREFS_PALETTES_LIST_PAGE);
+}
+
+static void
+bar_toggled_cb (GtkToggleButton *toggle,
+                GstyleRevealer  *reveal)
+{
+  GtkStyleContext *context;
+  gboolean active;
+
+  g_assert (GTK_IS_TOGGLE_BUTTON (toggle));
+  g_assert (GSTYLE_IS_REVEALER (reveal));
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (toggle));
+  active  = gtk_toggle_button_get_active (toggle);
+  gstyle_revealer_set_reveal_child (reveal, active);
+
+  if (active)
+    gtk_style_context_remove_class (context, "dim-label");
+  else
+    gtk_style_context_add_class (context, "dim-label");
+}
+
+static void
+setup_ui (GstyleColorPanel *self)
+{
+  GdkRGBA rgba = {0.26, 0.5, 0.5};
+  GtkAdjustment *adj;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
+    {
+      g_autofree gchar *toggle = g_strconcat (comp_names [i], "_toggle", NULL);
+      g_autofree gchar *spin = g_strconcat (comp_names [i], "_spin", NULL);
+      g_autofree gchar *scale = g_strconcat (comp_names [i], "_scale", NULL);
+
+      self->components [i].toggle =
+        GTK_TOGGLE_BUTTON (gtk_widget_get_template_child (GTK_WIDGET (self),
+                                                          GSTYLE_TYPE_COLOR_PANEL,
+                                                          toggle));
+      self->components [i].spin =
+        GTK_SPIN_BUTTON (gtk_widget_get_template_child (GTK_WIDGET (self),
+                                                        GSTYLE_TYPE_COLOR_PANEL,
+                                                        spin));
+      self->components [i].scale =
+        GSTYLE_COLOR_SCALE (gtk_widget_get_template_child (GTK_WIDGET (self),
+                                                           GSTYLE_TYPE_COLOR_PANEL,
+                                                           scale));
+
+      adj = gstyle_color_plane_get_component_adjustment (self->color_plane, i);
+      gtk_range_set_adjustment (GTK_RANGE (self->components [i].scale), adj);
+      gtk_spin_button_set_adjustment (self->components [i].spin, adj);
+
+      self->components [i].toggle_handler_id =
+        g_signal_connect_swapped (self->components [i].toggle,
+                                  "toggled",
+                                  G_CALLBACK (component_toggled_cb),
+                                  self);
+    }
+
+  self->current_comp = GSTYLE_COLOR_COMPONENT_HSV_H;
+  gtk_toggle_button_set_active (self->components [GSTYLE_COLOR_COMPONENT_HSV_H].toggle, TRUE);
+
+  self->adj_alpha = gtk_adjustment_new (50.0, 0.0, 100.0, 0.1, 1.0, 0.0);
+  gtk_range_set_adjustment (GTK_RANGE (self->alpha_scale), self->adj_alpha);
+  g_signal_connect_swapped (self->adj_alpha, "value-changed",
+                            G_CALLBACK (adj_alpha_value_changed_cb), self);
+
+  self->new_color = gstyle_color_new (NULL, GSTYLE_COLOR_KIND_RGB_HEX6, 0.0, 0.0, 0.0, 100);
+  gstyle_color_widget_set_color (self->new_swatch, self->new_color);
+  g_object_set (self->new_swatch,
+                "dnd-lock", GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALPHA |
+                            GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_KIND |
+                            GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NAME,
+                NULL);
+
+  self->old_color = gstyle_color_new (NULL, GSTYLE_COLOR_KIND_RGB_HEX6, 0.0, 0.0, 0.0, 50);
+  gstyle_color_widget_set_color (self->old_swatch, self->old_color);
+  g_object_set (self->old_swatch,
+                "dnd-lock", GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALL,
+                NULL);
+
+  bar_toggled_cb (self->components_toggle, self->scale_reveal);
+  g_signal_connect (self->components_toggle, "toggled",
+                    G_CALLBACK (bar_toggled_cb), self->scale_reveal);
+
+  bar_toggled_cb (self->strings_toggle, self->string_reveal);
+  g_signal_connect (self->strings_toggle, "toggled",
+                    G_CALLBACK (bar_toggled_cb), self->string_reveal);
+
+  bar_toggled_cb (self->palette_toggle, self->palette_reveal);
+  g_signal_connect (self->palette_toggle, "toggled",
+                    G_CALLBACK (bar_toggled_cb), self->palette_reveal);
+
+  /* default value to start with */
+  g_object_bind_property_full (self->color_plane, "rgba", self->new_color,
+                               "rgba", G_BINDING_BIDIRECTIONAL,
+                               rgba_plane_to_new_color, rgba_new_color_to_plane,
+                               self, NULL);
+  gstyle_color_plane_set_rgba (self->color_plane, &rgba);
+
+  gtk_popover_set_relative_to (GTK_POPOVER (self->search_strings_popover),
+                               GTK_WIDGET (self->search_color_entry));
+  g_signal_connect_swapped (self->search_color_entry, "search-changed",
+                            G_CALLBACK (search_color_entry_changed_cb),
+                            self);
+
+  gtk_entry_set_icon_from_gicon (GTK_ENTRY (self->components [GSTYLE_COLOR_COMPONENT_HSV_H].spin),
+                                 GTK_ENTRY_ICON_SECONDARY, self->degree_icon);
+  gtk_entry_set_icon_from_gicon (GTK_ENTRY (self->components [GSTYLE_COLOR_COMPONENT_HSV_S].spin),
+                                 GTK_ENTRY_ICON_SECONDARY, self->percent_icon);
+  gtk_entry_set_icon_from_gicon (GTK_ENTRY (self->components [GSTYLE_COLOR_COMPONENT_HSV_V].spin),
+                                 GTK_ENTRY_ICON_SECONDARY, self->percent_icon);
+  gtk_entry_set_icon_from_gicon (GTK_ENTRY (self->components [GSTYLE_COLOR_COMPONENT_LAB_L].spin),
+                                 GTK_ENTRY_ICON_SECONDARY, self->percent_icon);
+  set_preferred_unit (self, GSTYLE_COLOR_UNIT_VALUE);
+
+  g_signal_connect_swapped (self->palette_widget, "activated",
+                            G_CALLBACK (palette_row_activated_cb),
+                            self);
+  g_signal_connect_swapped (self->palette_widget, "notify::selected-palette-id",
+                            G_CALLBACK (palette_selected_notify_cb),
+                            self);
+
+  g_signal_connect_swapped (self->picker_button, "clicked",
+                            G_CALLBACK (picker_button_clicked_cb),
+                            self);
+
+  g_signal_connect_swapped (self->prefs_slidein, "closing",
+                            G_CALLBACK (slide_is_closing_cb),
+                            self);
+
+  g_signal_connect_swapped (self->components_prefs_button,
+                            "notify::active",
+                            G_CALLBACK (prefs_button_notify_active_cb),
+                            self);
+  g_signal_connect_swapped (self->color_strings_prefs_button,
+                            "notify::active",
+                            G_CALLBACK (prefs_button_notify_active_cb),
+                            self);
+  g_signal_connect_swapped (self->palettes_prefs_button,
+                            "notify::active",
+                            G_CALLBACK (prefs_button_notify_active_cb),
+                            self);
+  g_signal_connect_swapped (self->palettes_list_prefs_button,
+                            "notify::active",
+                            G_CALLBACK (prefs_button_notify_active_cb),
+                            self);
+}
+
+/**
+ * gstyle_color_panel_show_palette:
+ * @self: A #GstyleColorPanel.
+ * @palette: A GstylePalette.
+ *
+ * Show the @palette and update it's name in the bar.
+ *
+ */
+void
+gstyle_color_panel_show_palette (GstyleColorPanel *self,
+                                 GstylePalette    *palette)
+{
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+  g_assert (GSTYLE_IS_PALETTE (palette));
+
+  if(gstyle_palette_widget_show_palette (self->palette_widget, palette))
+    update_palette_name (self, palette);
+}
+
+static void
+gstyle_color_panel_set_strings_visible (GstyleColorPanel                    *self,
+                                        GstyleColorPanelStringsVisibleFlags  flags)
+{
+  gboolean hex3_visible;
+  gboolean hex6_visible;
+  gboolean rgb_visible;
+  gboolean rgba_visible;
+  gboolean hsl_visible;
+  gboolean hsla_visible;
+
+  g_assert (GSTYLE_IS_COLOR_PANEL (self));
+
+  if (self->strings_visible_flags != flags)
+    {
+      self->strings_visible_flags = flags;
+
+      hex3_visible = !!(flags & GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX3);
+      hex6_visible = !!(flags & GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX6);
+      rgb_visible = !!(flags & GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGB);
+      rgba_visible = !!(flags & GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGBA);
+      hsl_visible = !!(flags & GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSL);
+      hsla_visible = !!(flags & GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSLA);
+
+      gtk_widget_set_visible (GTK_WIDGET (self->hex3_label), hex3_visible);
+      gtk_widget_set_visible (GTK_WIDGET (self->res_hex3_label), hex3_visible);
+
+      gtk_widget_set_visible (GTK_WIDGET (self->hex6_label), hex6_visible);
+      gtk_widget_set_visible (GTK_WIDGET (self->res_hex6_label), hex6_visible);
+
+      gtk_widget_set_visible (GTK_WIDGET (self->rgb_label), rgb_visible);
+      gtk_widget_set_visible (GTK_WIDGET (self->res_rgb_label), rgb_visible);
+
+      gtk_widget_set_visible (GTK_WIDGET (self->rgba_label), rgba_visible);
+      gtk_widget_set_visible (GTK_WIDGET (self->res_rgba_label), rgba_visible);
+
+      gtk_widget_set_visible (GTK_WIDGET (self->hsl_label), hsl_visible);
+      gtk_widget_set_visible (GTK_WIDGET (self->res_hsl_label), hsl_visible);
+
+      gtk_widget_set_visible (GTK_WIDGET (self->hsla_label), hsla_visible);
+      gtk_widget_set_visible (GTK_WIDGET (self->res_hsla_label), hsla_visible);
+    }
+}
+
+GstyleColorPanel *
+gstyle_color_panel_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_COLOR_PANEL, NULL);
+}
+
+static void
+gstyle_color_panel_dispose (GObject *object)
+{
+  GstyleColorPanel *self = (GstyleColorPanel *)object;
+
+  g_clear_object (&self->new_color);
+  g_clear_object (&self->default_provider);
+  g_clear_object (&self->degree_icon);
+  g_clear_object (&self->percent_icon);
+  gstyle_color_panel_set_prefs_pages (self, NULL, NULL, NULL, NULL);
+
+  G_OBJECT_CLASS (gstyle_color_panel_parent_class)->dispose (object);
+}
+
+static void
+gstyle_color_panel_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  GstyleColorPanel *self = GSTYLE_COLOR_PANEL (object);
+  GdkRGBA rgba = {0};
+  GstyleXYZ xyz;
+
+  switch (prop_id)
+    {
+    case PROP_HSV_VISIBLE:
+      g_value_set_boolean (value, gtk_widget_get_visible (self->hsv_grid));
+      break;
+    case PROP_LAB_VISIBLE:
+      g_value_set_boolean (value, gtk_widget_get_visible (self->lab_grid));
+      break;
+
+    case PROP_RGB_VISIBLE:
+      g_value_set_boolean (value, gtk_widget_get_visible (self->rgb_grid));
+      break;
+
+    case PROP_STRINGS_VISIBLE:
+      g_value_set_flags (value, self->strings_visible_flags);
+      break;
+
+    case PROP_RGBA:
+      gstyle_color_panel_get_rgba (self, &rgba);
+      g_value_set_boxed (value, &rgba);
+      break;
+
+    case PROP_RGB_UNIT:
+      g_value_set_enum (value, self->preferred_unit);
+      break;
+
+    case PROP_XYZ:
+      gstyle_color_panel_get_xyz (self, &xyz);
+      g_value_set_boxed (value, &xyz);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_panel_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GstyleColorPanel *self = GSTYLE_COLOR_PANEL (object);
+  GdkRGBA *rgba_p;
+  GstyleXYZ *xyz_p;
+
+  switch (prop_id)
+    {
+    case PROP_HSV_VISIBLE:
+      gtk_widget_set_visible (self->hsv_grid, g_value_get_boolean (value));
+      break;
+
+    case PROP_LAB_VISIBLE:
+      gtk_widget_set_visible (self->lab_grid, g_value_get_boolean (value));
+      break;
+
+    case PROP_RGB_VISIBLE:
+      gtk_widget_set_visible (self->rgb_grid, g_value_get_boolean (value));
+      break;
+
+    case PROP_STRINGS_VISIBLE:
+      gstyle_color_panel_set_strings_visible (self, g_value_get_flags (value));
+      break;
+
+    case PROP_RGB_UNIT:
+      set_preferred_unit (self, g_value_get_enum (value));
+      break;
+
+    case PROP_RGBA:
+      rgba_p = (GdkRGBA *)g_value_get_boxed (value);
+      if (rgba_p != NULL)
+        gstyle_color_panel_set_rgba (self, rgba_p);
+      break;
+
+    case PROP_XYZ:
+      xyz_p = (GstyleXYZ *)g_value_get_boxed (value);
+      if (xyz_p != NULL)
+        gstyle_color_panel_set_xyz (self, xyz_p);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_panel_class_init (GstyleColorPanelClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = gstyle_color_panel_dispose;
+  object_class->get_property = gstyle_color_panel_get_property;
+  object_class->set_property = gstyle_color_panel_set_property;
+
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                               "/org/gnome/libgstyle/ui/gstyle-color-panel.ui");
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, new_swatch);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, old_swatch);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, color_plane);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, hsv_grid);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, lab_grid);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, rgb_grid);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, components_controls);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, strings_controls);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, palette_controls);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, components_toggle);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, strings_toggle);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, palette_toggle);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, scale_reveal);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, string_reveal);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, palette_reveal);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, ref_scale);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, alpha_scale);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, palette_widget);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, res_hex3_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, res_hex6_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, res_rgb_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, res_rgba_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, res_hsl_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, res_hsla_label);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, hex3_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, hex6_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, rgb_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, rgba_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, hsl_label);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, hsla_label);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, prefs_stack);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, components_prefs_button);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, color_strings_prefs_button);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, palettes_prefs_button);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, palettes_list_prefs_button);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, search_color_entry);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, search_strings_popover);
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, search_strings_list);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, picker_button);
+
+  gtk_widget_class_bind_template_child (widget_class, GstyleColorPanel, prefs_slidein);
+
+  g_type_ensure (GSTYLE_TYPE_SLIDEIN);
+  g_type_ensure (GSTYLE_TYPE_COLOR_SCALE);
+  g_type_ensure (GSTYLE_TYPE_COLOR_PLANE);
+  g_type_ensure (GSTYLE_TYPE_COLOR_WIDGET);
+  g_type_ensure (GSTYLE_TYPE_REVEALER);
+  g_type_ensure (GSTYLE_TYPE_PALETTE_WIDGET);
+
+  for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
+    {
+      g_autofree gchar *toggle = g_strconcat (comp_names [i], "_toggle", NULL);
+      g_autofree gchar *spin = g_strconcat (comp_names [i], "_spin", NULL);
+      g_autofree gchar *scale = g_strconcat (comp_names [i], "_scale", NULL);
+
+      gtk_widget_class_bind_template_child_full (widget_class, toggle, FALSE, 0);
+      gtk_widget_class_bind_template_child_full (widget_class, spin, FALSE, 0);
+      gtk_widget_class_bind_template_child_full (widget_class, scale, FALSE, 0);
+    }
+
+  gtk_widget_class_set_css_name (widget_class, "gstylecolorpanel");
+
+  properties [PROP_RGBA] =
+    g_param_spec_boxed ("rgba",
+                        "rgba",
+                        "current color of the color plane",
+                        GDK_TYPE_RGBA,
+                        (G_PARAM_CONSTRUCT |
+                         G_PARAM_READWRITE |
+                         G_PARAM_EXPLICIT_NOTIFY |
+                         G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_XYZ] =
+    g_param_spec_boxed ("xyz",
+                        "xyz",
+                        "current xyz color of the color plane",
+                        GSTYLE_TYPE_XYZ,
+                        (G_PARAM_CONSTRUCT |
+                         G_PARAM_READWRITE |
+                         G_PARAM_EXPLICIT_NOTIFY |
+                         G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_HSV_VISIBLE] =
+    g_param_spec_boolean ("hsv-visible",
+                          "hsv-visible",
+                          "Visibility of the HSV components",
+                          TRUE,
+                          (G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_LAB_VISIBLE] =
+    g_param_spec_boolean ("lab-visible",
+                          "lab-visible",
+                          "Visibility of the LAB components",
+                          TRUE,
+                          (G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_RGB_VISIBLE] =
+    g_param_spec_boolean ("rgb-visible",
+                          "rgb-visible",
+                          "Visibility of the RGB components",
+                          TRUE,
+                          (G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_RGB_UNIT] =
+    g_param_spec_enum ("rgb-unit",
+                       "rgb-unit",
+                       "Units used by the RGB components and strings",
+                       GSTYLE_TYPE_COLOR_UNIT,
+                       GSTYLE_COLOR_UNIT_PERCENT,
+                       (G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_STRINGS_VISIBLE] =
+    g_param_spec_flags ("strings-visible",
+                        "strings-visible",
+                        "Color strings visible",
+                        GSTYLE_TYPE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS,
+                        GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX3 |
+                        GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX6 |
+                        GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGB  |
+                        GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGBA |
+                        GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSL  |
+                        GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSLA ,
+                        (G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  signals [UPDATE_PREFS] = g_signal_new ("update-prefs",
+                                          G_TYPE_FROM_CLASS (klass),
+                                          G_SIGNAL_RUN_LAST,
+                                          0,
+                                          NULL, NULL, NULL,
+                                          G_TYPE_NONE,
+                                          1,
+                                          GSTYLE_TYPE_COLOR_PANEL_PREFS);
+
+  /* signals [DISCONNECT_PREFS] = g_signal_new ("disconnect-prefs", */
+  /*                                            G_TYPE_FROM_CLASS (klass), */
+  /*                                            G_SIGNAL_RUN_LAST, */
+  /*                                            0, */
+  /*                                            NULL, NULL, NULL, */
+  /*                                            G_TYPE_NONE, */
+  /*                                            2, */
+  /*                                            GSTYLE_TYPE_COLOR_PANEL_PREFS, */
+  /*                                            GTK_TYPE_WIDGET); */
+}
+
+static void
+gstyle_color_panel_init (GstyleColorPanel *self)
+{
+  GtkStyleContext *context;
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+  gstyle_color_panel_actions_init (self);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  self->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
+  gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),
+                                    "/org/gnome/libgstyle/icons");
+
+  self->degree_icon = get_degree_icon (self);
+  self->percent_icon = get_percent_icon (self);
+
+  self->preferred_unit = GSTYLE_COLOR_UNIT_VALUE;
+  setup_ui (self);
+}
+
+GType
+gstyle_color_panel_prefs_get_type (void)
+{
+  static GType type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_COLOR_PANEL_PREFS_COMPONENTS,    "GSTYLE_COLOR_PANEL_PREFS_COMPONENTS",    "components" },
+    { GSTYLE_COLOR_PANEL_PREFS_COLOR_STRINGS, "GSTYLE_COLOR_PANEL_PREFS_COLOR_STRINGS", "colorstrings" },
+    { GSTYLE_COLOR_PANEL_PREFS_PALETTES,      "GSTYLE_COLOR_PANEL_PREFS_PALETTES",      "palettes" },
+    { GSTYLE_COLOR_PANEL_PREFS_PALETTES_LIST, "GSTYLE_COLOR_PANEL_PREFS_PALETTES_LIST", "paletteslist" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstyleColorPanelPrefs", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
+
+GType
+gstyle_color_panel_strings_visible_flags_get_type (void)
+{
+  static GType type_id;
+  static const GFlagsValue values[] = {
+    { GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_NONE, "GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_NONE", "none" 
},
+    { GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX3, "GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX3", "hex3" 
},
+    { GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX6, "GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX6", "hex6" 
},
+    { GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGB,  "GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGB",  "rgb"  
},
+    { GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGBA, "GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGBA", "rgba" 
},
+    { GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSL,  "GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSL",  "hsl"  
},
+    { GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSLA, "GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSLA", "hsla" 
},
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_flags_register_static ("GstyleColorPanelStringsVisibleFlags", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/gstyle/gstyle-color-panel.h b/contrib/gstyle/gstyle-color-panel.h
new file mode 100644
index 0000000..ebf643e
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-panel.h
@@ -0,0 +1,79 @@
+/* gstyle-color-panel.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_PANEL_H
+#define GSTYLE_COLOR_PANEL_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-palette.h"
+#include "gstyle-palette-widget.h"
+#include "gstyle-xyz.h"
+
+
+#define GSTYLE_TYPE_COLOR_PANEL_PREFS                 (gstyle_color_panel_prefs_get_type())
+#define GSTYLE_TYPE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS (gstyle_color_panel_strings_visible_flags_get_type ())
+#define GSTYLE_TYPE_COLOR_PANEL                       (gstyle_color_panel_get_type())
+
+typedef enum
+{
+  GSTYLE_COLOR_PANEL_PREFS_COMPONENTS,
+  GSTYLE_COLOR_PANEL_PREFS_COLOR_STRINGS,
+  GSTYLE_COLOR_PANEL_PREFS_PALETTES,
+  GSTYLE_COLOR_PANEL_PREFS_PALETTES_LIST
+} GstyleColorPanelPrefs;
+
+typedef enum
+{
+  GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_NONE = 0,
+  GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX3 = 1 << 0,
+  GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HEX6 = 1 << 1,
+  GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGB  = 1 << 2,
+  GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_RGBA = 1 << 3,
+  GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSL  = 1 << 4,
+  GSTYLE_COLOR_PANEL_STRINGS_VISIBLE_FLAGS_HSLA = 1 << 5
+} GstyleColorPanelStringsVisibleFlags;
+
+G_DECLARE_FINAL_TYPE (GstyleColorPanel, gstyle_color_panel, GSTYLE, COLOR_PANEL, GtkBox)
+
+GType                       gstyle_color_panel_prefs_get_type                    (void);
+GType                       gstyle_color_panel_strings_visible_flags_get_type    (void);
+
+GstyleColorPanel           *gstyle_color_panel_new                         (void);
+GstylePaletteWidget        *gstyle_color_panel_get_palette_widget          (GstyleColorPanel    *self);
+void                        gstyle_color_panel_get_rgba                    (GstyleColorPanel    *self,
+                                                                            GdkRGBA             *rgba);
+void                        gstyle_color_panel_set_rgba                    (GstyleColorPanel    *self,
+                                                                            const GdkRGBA       *rgba);
+void                        gstyle_color_panel_get_xyz                     (GstyleColorPanel    *self,
+                                                                            GstyleXYZ           *xyz);
+void                        gstyle_color_panel_set_xyz                     (GstyleColorPanel    *self,
+                                                                            const GstyleXYZ     *xyz);
+void                        gstyle_color_panel_set_prefs_pages             (GstyleColorPanel    *self,
+                                                                            GtkWidget           
*components_page,
+                                                                            GtkWidget           
*colorstrings_page,
+                                                                            GtkWidget           
*palettes_page,
+                                                                            GtkWidget           
*palettes_list_page);
+void                        gstyle_color_panel_show_palette                (GstyleColorPanel    *self,
+                                                                            GstylePalette       *palette);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_PANEL_H */
+
diff --git a/contrib/gstyle/gstyle-color-plane.c b/contrib/gstyle/gstyle-color-plane.c
new file mode 100644
index 0000000..93a0bc3
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-plane.c
@@ -0,0 +1,1648 @@
+/* gstyle-color-plane.c
+ *
+ * based on : gtk-color-plane
+ *   GTK - The GIMP Toolkit
+ *   Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-color-plane"
+
+#include <math.h>
+#include <cairo/cairo.h>
+#include <glib/gi18n.h>
+
+#include "gstyle-cielab.h"
+#include "gstyle-color-convert.h"
+#include "gstyle-css-provider.h"
+#include "gstyle-utils.h"
+
+#include "gstyle-color-plane.h"
+
+typedef struct _ComputeData
+{
+  gint     width;
+  gint     height;
+  gint     stride;
+  guint32 *buffer;
+
+  gdouble  x_factor;
+  gdouble  y_factor;
+  gdouble  lab_x_factor;
+  gdouble  lab_y_factor;
+  gdouble  lab_l_factor;
+} ComputeData;
+
+typedef enum _ColorSpaceId
+{
+  COLOR_SPACE_RGB,
+  COLOR_SPACE_CIELAB,
+  COLOR_SPACE_HSV,
+  COLOR_SPACE_NONE
+} ColorSpaceId;
+
+typedef struct _Component
+{
+  GtkAdjustment *adj;
+  gulong         handler;
+  gdouble        val;
+  gdouble        factor;
+  ColorSpaceId   color_space;
+} Component;
+
+typedef struct
+{
+  cairo_surface_t        *surface;
+
+  GstyleCssProvider      *default_provider;
+
+  GtkGesture             *drag_gesture;
+  GtkGesture             *long_press_gesture;
+
+  GtkBorder               cached_margin;
+  GtkBorder               cached_border;
+  GdkRectangle            cached_margin_box;
+  GdkRectangle            cached_border_box;
+
+  GstyleColorPlaneMode    mode;
+  GstyleXYZ               xyz;
+  gdouble                 cursor_x;
+  gdouble                 cursor_y;
+
+  ComputeData             data;
+  GstyleColorFilter       filter;
+  gpointer                filter_user_data;
+
+  Component               comp [N_GSTYLE_COLOR_COMPONENT];
+  GstyleColorComponent    ref_comp;
+  GstyleColorUnit         preferred_unit;
+} GstyleColorPlanePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstyleColorPlane, gstyle_color_plane, GTK_TYPE_DRAWING_AREA)
+
+enum {
+  PROP_0,
+  PROP_MODE,
+  PROP_RGBA,
+  PROP_XYZ,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+/* We return %TRUE if there's no changes in border and margin, %FALSE otherwise.*/
+static gboolean
+update_css_boxes (GstyleColorPlane *self)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GtkWidget *widget = GTK_WIDGET (self);
+  GtkStyleContext *style_context;
+  GtkStateFlags state;
+  GdkRectangle margin_box;
+  GdkRectangle border_box;
+  GtkBorder margin;
+  GtkBorder border;
+  gboolean res;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  state = gtk_style_context_get_state (style_context);
+
+  gtk_style_context_get_margin (style_context, state, &margin);
+  gtk_style_context_get_border (style_context, state, &border);
+  gtk_widget_get_allocation (widget, &margin_box);
+  margin_box.x = margin_box.y = 0;
+
+  gstyle_utils_get_rect_resized_box (margin_box, &margin_box, &margin);
+  gstyle_utils_get_rect_resized_box (margin_box, &border_box, &border);
+
+  res = (gstyle_utils_cmp_border (margin, priv->cached_margin) ||
+         gstyle_utils_cmp_border (border, priv->cached_border));
+
+  priv->cached_margin_box = margin_box;
+  priv->cached_border_box = border_box;
+  priv->cached_margin = margin;
+  priv->cached_border = border;
+
+  return res;
+}
+
+static void
+get_xyz_from_cursor (GstyleColorPlane *self,
+                     GstyleXYZ        *xyz)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hsv_h, hsv_s, hsv_v;
+  GstyleCielab lab;
+  GdkRGBA rgba = {0};
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (xyz != NULL);
+
+  switch (priv->mode)
+    {
+    case GSTYLE_COLOR_PLANE_MODE_HUE:
+      hsv_h = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_H].factor,
+      hsv_s = priv->cursor_x * priv->data.x_factor;
+      hsv_v = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
+      gstyle_color_convert_hsv_to_xyz (hsv_h, hsv_s, hsv_v, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_SATURATION:
+      hsv_s = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_S].factor,
+      hsv_h = priv->cursor_x * priv->data.x_factor;
+      hsv_v = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
+      gstyle_color_convert_hsv_to_xyz (hsv_h, hsv_s, hsv_v, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
+      hsv_v = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_V].factor,
+      hsv_h = priv->cursor_x * priv->data.x_factor;
+      hsv_s = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
+      gstyle_color_convert_hsv_to_xyz (hsv_h, hsv_s, hsv_v, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
+      lab.l = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_L].factor,
+      lab.a = priv->cursor_x * priv->data.lab_x_factor - 128.0;
+      lab.b = (priv->data.height - priv->cursor_y - 1) * priv->data.lab_y_factor - 128.0;
+      gstyle_color_convert_cielab_to_xyz (&lab, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
+      lab.a = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_A].factor,
+      lab.b = priv->cursor_x * priv->data.lab_x_factor - 128.0;
+      lab.l = (priv->data.height - priv->cursor_y - 1) * priv->data.lab_l_factor;
+      gstyle_color_convert_cielab_to_xyz (&lab, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
+      lab.b = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_B].factor,
+      lab.a = priv->cursor_x * priv->data.lab_x_factor - 128.0;
+      lab.l = (priv->data.height - priv->cursor_y - 1) * priv->data.lab_l_factor;
+      gstyle_color_convert_cielab_to_xyz (&lab, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_RED:
+      rgba.red = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_RED].factor,
+      rgba.blue = priv->cursor_x * priv->data.x_factor;
+      rgba.green = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
+      gstyle_color_convert_rgb_to_xyz (&rgba, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_GREEN:
+      rgba.green = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor,
+      rgba.blue = priv->cursor_x * priv->data.x_factor;
+      rgba.red = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
+      gstyle_color_convert_rgb_to_xyz (&rgba, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_BLUE:
+      rgba.blue = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor,
+      rgba.red = priv->cursor_x * priv->data.x_factor;
+      rgba.green = (priv->data.height - priv->cursor_y - 1) * priv->data.y_factor;
+      gstyle_color_convert_rgb_to_xyz (&rgba, xyz);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_NONE:
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
+set_cursor_from_xyz (GstyleColorPlane *self,
+                     GstyleXYZ        *xyz)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hsv_h, hsv_s, hsv_v;
+  GstyleCielab lab;
+  GdkRGBA rgba = {0};
+  gdouble x, y;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (xyz != NULL);
+
+  switch (priv->mode)
+    {
+    case GSTYLE_COLOR_PLANE_MODE_HUE:
+      gstyle_color_convert_xyz_to_hsv (xyz, &hsv_h, &hsv_s, &hsv_v);
+      x = hsv_s / priv->data.x_factor;
+      y = (1.0 - hsv_v) / priv->data.y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_SATURATION:
+      gstyle_color_convert_xyz_to_hsv (xyz, &hsv_h, &hsv_s, &hsv_v);
+      x = hsv_h / priv->data.x_factor;
+      y = (1.0 - hsv_v) / priv->data.y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
+      gstyle_color_convert_xyz_to_hsv (xyz, &hsv_h, &hsv_s, &hsv_v);
+      x = hsv_h / priv->data.x_factor;
+      y = (1.0 - hsv_s) / priv->data.y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
+      gstyle_color_convert_xyz_to_cielab (xyz, &lab);
+      x = (lab.a + 128.0) / priv->data.lab_x_factor;
+      y = (128.0 - lab.b) / priv->data.lab_y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
+      gstyle_color_convert_xyz_to_cielab (xyz, &lab);
+      x = (lab.b + 128.0) / priv->data.lab_x_factor;
+      y = (100.0 - lab.l) / priv->data.lab_l_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
+      gstyle_color_convert_xyz_to_cielab (xyz, &lab);
+      x = (lab.a + 128.0) / priv->data.lab_x_factor;
+      y = (100.0 - lab.l) / priv->data.lab_y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_RED:
+      gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
+      x = rgba.blue / priv->data.x_factor;
+      y = (1.0 - rgba.green) / priv->data.y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_GREEN:
+      gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
+      x = rgba.blue / priv->data.x_factor;
+      y = (1.0 - rgba.red) / priv->data.y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_BLUE:
+      gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
+      x = rgba.red / priv->data.x_factor;
+      y = (1.0 - rgba.green) / priv->data.y_factor;
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_NONE:
+    default:
+      g_assert_not_reached ();
+    }
+
+  priv->cursor_x = CLAMP (x, 0.0, (gdouble)priv->data.width - 1.0);
+  priv->cursor_y = CLAMP (y, 0.0, (gdouble)priv->data.height - 1.0);
+}
+
+static void
+configure_component (GstyleColorPlane     *self,
+                     GstyleColorComponent  comp,
+                     gdouble               upper,
+                     gdouble               factor)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble new_value;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (GTK_IS_ADJUSTMENT (priv->comp [comp].adj));
+
+  new_value = priv->comp [comp].val / priv->comp [comp].factor * factor;
+  priv->comp [comp].factor = factor;
+
+  g_object_freeze_notify (G_OBJECT (priv->comp [comp].adj));
+  gtk_adjustment_set_upper (priv->comp [comp].adj, upper);
+  gtk_adjustment_set_value (priv->comp [comp].adj, new_value);
+  g_object_thaw_notify (G_OBJECT (priv->comp [comp].adj));
+}
+
+static void
+setup_component (GstyleColorPlane     *self,
+                 GstyleColorComponent  comp,
+                 gdouble               origin,
+                 gdouble               lower,
+                 gdouble               upper,
+                 gdouble               step_increment,
+                 gdouble               page_increment,
+                 gdouble               factor,
+                 ColorSpaceId          color_space)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  priv->comp [comp].adj = g_object_ref (gtk_adjustment_new (origin, lower, upper, step_increment, 
page_increment, 0));
+  priv->comp [comp].factor = factor;
+  priv->comp [comp].color_space = color_space;
+}
+
+/**
+ * gstyle_color_plane_set_preferred_unit:
+ * @self: A #GstyleColorPlane
+ * @preferred_unit: A #GstyleColorUnit enum value
+ *
+ * Set percent or value  as the preferred unit for rgb adjustment range.
+ * [0, 100] for percent unit or [0, 255] for value.
+ *
+ */
+void
+gstyle_color_plane_set_preferred_unit (GstyleColorPlane *self,
+                                       GstyleColorUnit   preferred_unit)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble max_range;
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+
+  if (priv->preferred_unit != preferred_unit)
+    {
+      priv->preferred_unit = preferred_unit;
+      if (preferred_unit == GSTYLE_COLOR_UNIT_PERCENT)
+        max_range = 100.0;
+      else if (preferred_unit == GSTYLE_COLOR_UNIT_VALUE)
+        max_range = 255.0;
+      else
+        g_assert_not_reached ();
+
+      configure_component (self, GSTYLE_COLOR_COMPONENT_RGB_RED, max_range, max_range);
+      configure_component (self, GSTYLE_COLOR_COMPONENT_RGB_GREEN, max_range, max_range);
+      configure_component (self, GSTYLE_COLOR_COMPONENT_RGB_BLUE, max_range, max_range);
+    }
+}
+
+/**
+ * gstyle_color_plane_get_filter: (skip):
+ * @self: A #GstyleColorPlane
+ *
+ * Get a pointer to the current filter function or %NULL
+ * if no filter is actually set.
+ *
+ * Returns: (nullable): A GstyleColorFilter function pointer.
+ *
+ */
+GstyleColorFilter
+gstyle_color_plane_get_filter (GstyleColorPlane *self)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR_PLANE (self), NULL);
+
+  return priv->filter;
+}
+
+/**
+ * gstyle_color_plane_set_filter:
+ * @self: A #GstyleColorPlane
+ * @filter_cb: (scope notified) (nullable): A GstyleColorFilter filter function or
+ *   %NULL to unset the current filter. In this case, user_data is ignored
+ * @user_data: (closure) (nullable): user data to pass when calling the filter function
+ *
+ * Set a filter to be used to change the drawing of the color plane.
+ *
+ */
+void
+gstyle_color_plane_set_filter (GstyleColorPlane  *self,
+                               GstyleColorFilter  filter_cb,
+                               gpointer           user_data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+
+  priv->filter = filter_cb;
+  priv->filter_user_data = (filter_cb == NULL) ? NULL : user_data;
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+compute_plane_hue_mode (GstyleColorPlane *self,
+                        ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hue, saturation, value;
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  hue = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      value = CLAMP ((data.height - y) * data.y_factor, 0.0, 1.0);
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          saturation = x * data.x_factor;
+          gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &rgba);
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_saturation_mode (GstyleColorPlane *self,
+                               ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hue, saturation, value;
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  saturation = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_S].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      value = CLAMP ((data.height - y) * data.y_factor, 0.0, 1.0);
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          hue = x * data.x_factor;
+          gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &rgba);
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_brightness_mode (GstyleColorPlane *self,
+                               ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hue, saturation, value;
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  value = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].factor;
+  for (gint y = 0; y < data.height - 1; ++y)
+    {
+      saturation = CLAMP ((data.height - y) * data.y_factor, 0.0, 1.0);
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          hue = x * data.x_factor;
+          gstyle_color_convert_hsv_to_rgb (hue, saturation, value, &rgba);
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_cielab_l_mode (GstyleColorPlane *self,
+                             ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GstyleCielab lab;
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  lab.l = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      lab.b = (data.height - y) * data.lab_y_factor - 128.0;
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          lab.a = x * data.lab_x_factor - 128.0;
+          gstyle_color_convert_cielab_to_rgb (&lab, &rgba);
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_cielab_a_mode (GstyleColorPlane *self,
+                             ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GstyleCielab lab;
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  lab.a = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      lab.l = (data.height - y) * data.lab_l_factor;
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          lab.b = x * data.lab_x_factor - 128.0;
+          gstyle_color_convert_cielab_to_rgb (&lab, &rgba);
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_cielab_b_mode (GstyleColorPlane *self,
+                             ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GstyleCielab lab;
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  lab.b = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val / priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      lab.l = (data.height - y) * data.lab_l_factor;
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          lab.a = x * data.lab_x_factor - 128.0;
+          gstyle_color_convert_cielab_to_rgb (&lab, &rgba);
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_red_mode (GstyleColorPlane *self,
+                        ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  rgba.red = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_RED].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      rgba.green = (data.height - y) * data.y_factor;
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          rgba.blue = x * data.x_factor;
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_green_mode (GstyleColorPlane *self,
+                          ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  rgba.green = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      rgba.red = (data.height - y) * data.y_factor;
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          rgba.blue = x * data.x_factor;
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static void
+compute_plane_blue_mode (GstyleColorPlane *self,
+                         ComputeData       data)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GdkRGBA rgba = {0};
+  guint32 *p;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  rgba.blue = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor;
+  for (gint y = 0; y < data.height; ++y)
+    {
+      rgba.green = (data.height - y) * data.y_factor;
+      p = data.buffer + y * (data.stride / 4);
+      for (gint x = 0; x < data.width; ++x)
+        {
+          rgba.red = x * data.x_factor;
+          if (priv->filter != NULL)
+            priv->filter (&rgba, &rgba, priv->filter_user_data);
+
+          p[x] = pack_rgba24 (&rgba);
+        }
+    }
+}
+
+static gboolean
+create_surface (GstyleColorPlane *self)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GtkWidget *widget = (GtkWidget *)self;
+  cairo_surface_t *surface;
+  cairo_surface_t *tmp;
+  cairo_t *cr;
+  gint adjusted_height;
+  gint adjusted_width;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  if (!gtk_widget_get_realized (widget))
+    return FALSE;
+
+  /* TODO: keep only one of priv->data.width or priv->cached_border_box.width */
+
+  priv->data.width = priv->cached_border_box.width;
+  priv->data.height = priv->cached_border_box.height;
+  adjusted_height = priv->data.height - 1;
+  adjusted_width = priv->data.width - 1;
+
+  priv->data.y_factor = 1.0 / adjusted_height;
+  priv->data.x_factor = 1.0 / adjusted_width;
+  priv->data.lab_y_factor = 255.0 / adjusted_height;
+  priv->data.lab_x_factor = 255.0 / adjusted_width;
+  priv->data.lab_l_factor = 100.0 / adjusted_height;
+
+  surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
+                                               CAIRO_CONTENT_COLOR,
+                                               priv->data.width, priv->data.height);
+
+  if (priv->surface)
+    cairo_surface_destroy (priv->surface);
+
+  priv->surface = surface;
+
+  if (priv->data.width <= 1 || priv->data.height <= 1)
+    return FALSE;
+
+  priv->data.stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, priv->data.width);
+  priv->data.buffer = g_malloc (priv->data.height * priv->data.stride);
+
+  switch (priv->mode)
+    {
+    case GSTYLE_COLOR_PLANE_MODE_HUE:
+      compute_plane_hue_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_SATURATION:
+      compute_plane_saturation_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
+      compute_plane_brightness_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
+      compute_plane_cielab_l_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
+      compute_plane_cielab_a_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
+      compute_plane_cielab_b_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_RED:
+      compute_plane_red_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_GREEN:
+      compute_plane_green_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_BLUE:
+      compute_plane_blue_mode (self, priv->data);
+      break;
+
+    case GSTYLE_COLOR_PLANE_MODE_NONE:
+    default:
+      g_assert_not_reached ();
+    }
+
+  tmp = cairo_image_surface_create_for_data ((guchar *)priv->data.buffer, CAIRO_FORMAT_RGB24,
+                                             priv->data.width, priv->data.height, priv->data.stride);
+  cr = cairo_create (surface);
+  cairo_set_source_surface (cr, tmp, 0, 0);
+  cairo_paint (cr);
+
+  cairo_destroy (cr);
+  cairo_surface_destroy (tmp);
+  g_free (priv->data.buffer);
+
+  return TRUE;
+}
+
+static gboolean
+gstyle_color_plane_draw (GtkWidget *widget,
+                         cairo_t   *cr)
+{
+  GstyleColorPlane *self = (GstyleColorPlane *)widget;
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gint left_spacing;
+  gint top_spacing;
+  gint x, y;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (cr != NULL);
+
+  if (!gtk_widget_get_visible (widget))
+    return GDK_EVENT_PROPAGATE;
+
+  if (update_css_boxes (self) || priv->surface == NULL)
+    create_surface (self);
+
+  left_spacing = priv->cached_margin.left + priv->cached_border.left;
+  top_spacing = priv->cached_margin.top + priv->cached_border.top;
+  x = round (priv->cursor_x) + left_spacing;
+  y = round (priv->cursor_y) + top_spacing;
+
+  cairo_set_source_surface (cr, priv->surface, priv->cached_border_box.x, priv->cached_border_box.y);
+  cairo_paint (cr);
+
+  gtk_render_frame (gtk_widget_get_style_context (widget), cr,
+                    priv->cached_margin_box.x, priv->cached_margin_box.y,
+                    priv->cached_margin_box.width, priv->cached_margin_box.height);
+
+  cairo_move_to (cr, left_spacing, y + 0.5);
+  cairo_line_to (cr, left_spacing + priv->cached_border_box.width, y + 0.5);
+
+  cairo_move_to (cr, x + 0.5, top_spacing);
+  cairo_line_to (cr, x + 0.5, top_spacing + priv->cached_border_box.height);
+
+  if (gtk_widget_has_visible_focus (widget))
+    {
+      cairo_set_line_width (cr, 3.0);
+      cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
+      cairo_stroke_preserve (cr);
+
+      cairo_set_line_width (cr, 1.0);
+      cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
+      cairo_stroke (cr);
+    }
+  else
+    {
+      cairo_set_line_width (cr, 1.0);
+      cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.8);
+      cairo_stroke (cr);
+    }
+
+  return FALSE;
+}
+
+static inline gboolean
+compare_xyz (GstyleXYZ xyz1,
+             GstyleXYZ xyz2)
+{
+  return (xyz1.x == xyz2.x &&
+          xyz1.y == xyz2.y &&
+          xyz1.z == xyz2.z &&
+          xyz1.alpha == xyz2.alpha);
+}
+
+/* Adjustments are updated from the stored xyz */
+static void
+update_adjustments (GstyleColorPlane     *self,
+                    GstyleXYZ            *xyz,
+                    GstyleColorComponent  changed_comp)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hue, saturation, value;
+  GstyleCielab lab;
+  ColorSpaceId color_space;
+  GdkRGBA rgba = {0};
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (xyz != NULL);
+
+  if (!compare_xyz (priv->xyz, *xyz))
+    {
+      color_space = (changed_comp == GSTYLE_COLOR_COMPONENT_NONE) ? COLOR_SPACE_NONE : priv->comp 
[changed_comp].color_space;
+      if (color_space != COLOR_SPACE_RGB)
+        {
+          gstyle_color_convert_xyz_to_rgb (xyz, &rgba);
+          priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val = rgba.red * priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_RED].factor;
+          priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val = rgba.green * priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor;
+          priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val = rgba.blue * priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor;
+        }
+
+      if (color_space != COLOR_SPACE_CIELAB)
+        {
+          gstyle_color_convert_xyz_to_cielab (xyz, &lab);
+          priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val = lab.l * priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_L].factor;
+          priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val = lab.a * priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_A].factor;
+          priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val = lab.b * priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_B].factor;
+        }
+
+      if (color_space != COLOR_SPACE_HSV)
+        {
+          gstyle_color_convert_xyz_to_hsv (xyz, &hue, &saturation, &value);
+          priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val = hue * priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_H].factor;
+          priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val = saturation * priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_S].factor;
+          priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val = value * priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_V].factor;
+        }
+
+      for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
+        if (priv->comp [i].color_space != color_space)
+          {
+            g_signal_handler_block (priv->comp [i].adj, priv->comp [i].handler);
+            gtk_adjustment_set_value (priv->comp [i].adj, priv->comp [i].val);
+            g_signal_handler_unblock (priv->comp [i].adj, priv->comp [i].handler);
+          }
+    }
+}
+
+static void
+update_surface_and_cursor (GstyleColorPlane *self,
+                           gboolean          update_surface)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  if (update_surface)
+    create_surface (self);
+
+  set_cursor_from_xyz (self, &priv->xyz);
+
+  if (gtk_widget_get_realized (GTK_WIDGET (self)))
+    gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+update_cursor (GstyleColorPlane *self,
+               gdouble           x,
+               gdouble           y)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gint left_spacing;
+  gint top_spacing;
+  GstyleXYZ xyz;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  left_spacing = priv->cached_margin.left + priv->cached_border.left;
+  top_spacing = priv->cached_margin.top + priv->cached_border.top;
+  x = CLAMP (x - left_spacing, 0.0, priv->data.width - 1.0);
+  y = CLAMP (y - top_spacing, 0.0, priv->data.height - 1.0);
+
+  if (priv->cursor_x != x || priv->cursor_y != y)
+    {
+      priv->cursor_x = x;
+      priv->cursor_y = y;
+
+      get_xyz_from_cursor (self, &xyz);
+      update_adjustments (self, &xyz, GSTYLE_COLOR_COMPONENT_NONE);
+      priv->xyz = xyz;
+
+      gtk_widget_queue_draw (GTK_WIDGET (self));
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RGBA]);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_XYZ]);
+    }
+}
+
+static void
+move_cursor (GstyleColorPlane *self,
+             gdouble           step_x,
+             gdouble           step_y)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  if (!gtk_widget_get_realized (GTK_WIDGET (self)))
+    return;
+
+  update_cursor (self, priv->cursor_x + step_x, priv->cursor_y - step_y);
+  /* TODO: ring when reaching the border */
+}
+
+static GstyleColorComponent
+get_adj_id (GstyleColorPlane *self,
+            GtkAdjustment    *adj)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (GTK_IS_ADJUSTMENT (adj));
+
+  for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
+    if (adj == priv->comp [i].adj)
+      return i;
+
+  g_assert_not_reached ();
+}
+
+static void
+adjustments_changed (GstyleColorPlane *self,
+                     GtkAdjustment    *adj)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hue, saturation, value;
+  GdkRGBA rgba;
+  GstyleXYZ xyz;
+  GstyleCielab lab;
+  GstyleColorComponent changed_comp;
+  gdouble old_ref_val;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (GTK_IS_ADJUSTMENT (adj));
+
+  old_ref_val = priv->comp [priv->ref_comp].val;
+  changed_comp = get_adj_id (self, adj);
+  priv->comp [changed_comp].val = gtk_adjustment_get_value (priv->comp [changed_comp].adj);
+
+  if (changed_comp == GSTYLE_COLOR_COMPONENT_HSV_H ||
+      changed_comp == GSTYLE_COLOR_COMPONENT_HSV_S ||
+      changed_comp == GSTYLE_COLOR_COMPONENT_HSV_V)
+    {
+      hue = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].val / priv->comp [GSTYLE_COLOR_COMPONENT_HSV_H].factor;
+      saturation = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_S].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_S].factor;
+      value = priv->comp [GSTYLE_COLOR_COMPONENT_HSV_V].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_HSV_V].factor;
+
+      gstyle_color_convert_hsv_to_xyz (hue, saturation, value, &xyz);
+    }
+  else if (changed_comp == GSTYLE_COLOR_COMPONENT_LAB_L ||
+           changed_comp == GSTYLE_COLOR_COMPONENT_LAB_A ||
+           changed_comp == GSTYLE_COLOR_COMPONENT_LAB_B)
+    {
+      lab.l = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_L].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_L].factor;
+      lab.a = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_A].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_A].factor;
+      lab.b = priv->comp [GSTYLE_COLOR_COMPONENT_LAB_B].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_LAB_B].factor;
+
+      gstyle_color_convert_cielab_to_xyz (&lab, &xyz);
+    }
+  else
+    {
+      rgba.red = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_RED].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_RED].factor;
+      rgba.green = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_GREEN].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_GREEN].factor;
+      rgba.blue = priv->comp [GSTYLE_COLOR_COMPONENT_RGB_BLUE].val / priv->comp 
[GSTYLE_COLOR_COMPONENT_RGB_BLUE].factor;
+      gstyle_color_convert_rgb_to_xyz (&rgba, &xyz);
+    }
+
+  xyz.alpha = 1;
+  update_adjustments (self, &xyz, changed_comp);
+  priv->xyz = xyz;
+  update_surface_and_cursor (self, old_ref_val != priv->comp [priv->ref_comp].val);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RGBA]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_XYZ]);
+}
+
+/**
+ * gstyle_color_plane_new:
+ *
+ * Returns: a new #GstyleColorPlane
+ */
+GstyleColorPlane *
+gstyle_color_plane_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_COLOR_PLANE, NULL);
+}
+
+static void
+gstyle_color_plane_size_allocate (GtkWidget     *widget,
+                                  GtkAllocation *allocation)
+{
+  GstyleColorPlane *self = GSTYLE_COLOR_PLANE (widget);
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  GTK_WIDGET_CLASS (gstyle_color_plane_parent_class)->size_allocate (widget, allocation);
+
+  update_css_boxes (self);
+
+  if (create_surface (GSTYLE_COLOR_PLANE (widget)))
+    set_cursor_from_xyz (self, &priv->xyz);
+}
+
+static gboolean
+gstyle_color_plane_key_press (GtkWidget   *widget,
+                              GdkEventKey *event)
+{
+  GstyleColorPlane *self = GSTYLE_COLOR_PLANE (widget);
+  gdouble step;
+
+  g_assert (event != NULL);
+
+  if ((event->state & GDK_MOD1_MASK) != 0)
+    step = 0.1;
+  else
+    step = 0.01;
+
+  if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_KP_Up)
+    move_cursor (self, 0, step);
+  else if (event->keyval == GDK_KEY_Down || event->keyval == GDK_KEY_KP_Down)
+    move_cursor (self, 0, -step);
+  else if (event->keyval == GDK_KEY_Left || event->keyval == GDK_KEY_KP_Left)
+    move_cursor (self, -step, 0);
+  else if (event->keyval == GDK_KEY_Right ||  event->keyval == GDK_KEY_KP_Right)
+    move_cursor (self, step, 0);
+  else
+    return GTK_WIDGET_CLASS (gstyle_color_plane_parent_class)->key_press_event (widget, event);
+
+  return TRUE;
+}
+
+/**
+ * gstyle_color_plane_get_xyz:
+ * @self: A #GstyleColorPlane
+ * @xyz: (out): A #GstyleXYZ adress
+ *
+ * Fill @xyz with value at cursor position.
+ * The alpha component is always equal to 1.
+ *
+ */
+void
+gstyle_color_plane_get_xyz (GstyleColorPlane *self,
+                            GstyleXYZ        *xyz)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+  g_return_if_fail (xyz != NULL);
+
+  *xyz = priv->xyz;
+}
+
+/**
+ * gstyle_color_plane_get_rgba:
+ * @self: A #GstyleColorPlane
+ * @rgba: (out): A #GdkRGBA adress
+ *
+ * Fill @rgba with value at cursor position.
+ * The alpha component is always equal to 1.
+ *
+ */
+void
+gstyle_color_plane_get_rgba (GstyleColorPlane *self,
+                             GdkRGBA          *rgba)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+  g_return_if_fail (rgba != NULL);
+
+  gstyle_color_convert_xyz_to_rgb (&priv->xyz, rgba);
+}
+
+/**
+ * gstyle_color_plane_get_filtered_rgba:
+ * @self: A #GstyleColorPlane
+ * @rgba: (out): A #GdkRGBA adress
+ *
+ * Fill @rgba with filtered value at cursor position.
+ *
+ */
+void
+gstyle_color_plane_get_filtered_rgba (GstyleColorPlane *self,
+                                      GdkRGBA          *rgba)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+  g_return_if_fail (rgba != NULL);
+
+  gstyle_color_convert_xyz_to_rgb (&priv->xyz, rgba);
+  priv->filter (rgba, rgba, priv->filter_user_data);
+}
+
+/**
+ * gstyle_color_plane_get_component_adjustment:
+ * @self: A #GstyleColorPlane
+ * @comp: A #GstyleColorComponent enum value
+ *
+ * Return the color component adjustment designated by
+ * the #GstyleColorComponent value.
+ *
+ * Returns: (transfer none): #GtkAdjustment.
+ *
+ */
+GtkAdjustment *
+gstyle_color_plane_get_component_adjustment (GstyleColorPlane     *self,
+                                             GstyleColorComponent  comp)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR_PLANE (self), NULL);
+  g_return_val_if_fail (comp !=  GSTYLE_COLOR_COMPONENT_NONE, NULL);
+
+  return priv->comp [comp].adj;
+}
+
+/**
+ * gstyle_color_plane_set_rgba:
+ * @self: A #GstyleColorPlane
+ * @rgba: A #GdkRGBA
+ *
+ * Set cursor position from @rgba value.
+ *
+ */
+void
+gstyle_color_plane_set_rgba (GstyleColorPlane *self,
+                             const GdkRGBA    *rgba)
+{
+  GstyleColorPlanePrivate *priv;
+  GstyleXYZ xyz;
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+  g_return_if_fail (rgba != NULL);
+
+  priv = gstyle_color_plane_get_instance_private (self);
+
+  gstyle_color_convert_rgb_to_xyz ((GdkRGBA *)rgba, &xyz);
+  if (compare_xyz (xyz, priv->xyz))
+    return;
+
+  update_adjustments (self, &xyz, GSTYLE_COLOR_COMPONENT_NONE);
+  priv->xyz = xyz;
+  update_surface_and_cursor (self, TRUE);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RGBA]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_XYZ]);
+}
+
+/**
+ * gstyle_color_plane_set_xyz:
+ * @self: A #GstyleColorPlane.
+ * @xyz: A #GstyleXYZ struct.
+ *
+ * Set cursor position from @rgba value.
+ *
+ */
+void
+gstyle_color_plane_set_xyz (GstyleColorPlane *self,
+                            const GstyleXYZ  *xyz)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+  g_return_if_fail (xyz != NULL);
+
+  if (compare_xyz (*xyz, priv->xyz))
+    return;
+
+  update_adjustments (self, (GstyleXYZ *)xyz, GSTYLE_COLOR_COMPONENT_NONE);
+  priv->xyz = *xyz;
+  update_surface_and_cursor (self, TRUE);
+
+  /* TODO: add xyz props */
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RGBA]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_XYZ]);
+}
+
+/**
+ * gstyle_color_plane_set_mode:
+ * @self: a #GstyleColorPlane.
+ * @mode: a #GstylewColorPlaneMode.
+ *
+ * Set the displayed mode to use.
+ *
+ */
+void
+gstyle_color_plane_set_mode (GstyleColorPlane     *self,
+                             GstyleColorPlaneMode  mode)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  gdouble hsv_h, hsv_s, hsv_v;
+  gdouble ref_val;
+  GstyleCielab lab;
+  GdkRGBA rgba = {0};
+
+  g_return_if_fail (GSTYLE_IS_COLOR_PLANE (self));
+
+  if (priv->mode != mode)
+    {
+      priv->mode = mode;
+
+      switch (priv->mode)
+      {
+      case GSTYLE_COLOR_PLANE_MODE_HUE:
+        gstyle_color_convert_xyz_to_hsv (&priv->xyz, &hsv_h, &hsv_s, &hsv_v);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_H;
+        ref_val = hsv_h;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_SATURATION:
+        gstyle_color_convert_xyz_to_hsv (&priv->xyz, &hsv_h, &hsv_s, &hsv_v);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_S;
+        ref_val = hsv_s;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS:
+        gstyle_color_convert_xyz_to_hsv (&priv->xyz, &hsv_h, &hsv_s, &hsv_v);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_V;
+        ref_val = hsv_v;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_CIELAB_L:
+        gstyle_color_convert_xyz_to_cielab (&priv->xyz, &lab);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_LAB_L;
+        ref_val = lab.l;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_CIELAB_A:
+        gstyle_color_convert_xyz_to_cielab (&priv->xyz, &lab);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_LAB_A;
+        ref_val = lab.a;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_CIELAB_B:
+        gstyle_color_convert_xyz_to_cielab (&priv->xyz, &lab);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_LAB_B;
+        ref_val = lab.b;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_RED:
+        gstyle_color_convert_xyz_to_rgb (&priv->xyz, &rgba);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_RGB_RED;
+        ref_val = rgba.red;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_GREEN:
+        gstyle_color_convert_xyz_to_rgb (&priv->xyz, &rgba);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_RGB_GREEN;
+        ref_val = rgba.green;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_BLUE:
+        gstyle_color_convert_xyz_to_rgb (&priv->xyz, &rgba);
+        priv->ref_comp = GSTYLE_COLOR_COMPONENT_RGB_BLUE;
+        ref_val = rgba.blue;
+        break;
+
+      case GSTYLE_COLOR_PLANE_MODE_NONE:
+      default:
+        g_assert_not_reached ();
+      }
+
+      g_signal_handler_block (priv->comp [priv->ref_comp].adj, priv->comp [priv->ref_comp].handler);
+
+      priv->comp [priv->ref_comp].val = ref_val * priv->comp [priv->ref_comp].factor;
+      gtk_adjustment_set_value (priv->comp [priv->ref_comp].adj, priv->comp [priv->ref_comp].val);
+
+      g_signal_handler_unblock (priv->comp [priv->ref_comp].adj, priv->comp [priv->ref_comp].handler);
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MODE]);
+      update_surface_and_cursor (self, TRUE);
+    }
+}
+
+static void
+gstyle_color_plane_finalize (GObject *object)
+{
+  GstyleColorPlane *self = (GstyleColorPlane *)object;
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+
+  if (priv->surface)
+    cairo_surface_destroy (priv->surface);
+
+  g_clear_object (&priv->drag_gesture);
+  g_clear_object (&priv->long_press_gesture);
+  g_clear_object (&priv->default_provider);
+
+  for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
+    g_clear_object (&priv->comp [i].adj);
+
+  G_OBJECT_CLASS (gstyle_color_plane_parent_class)->finalize (object);
+}
+
+static void
+gstyle_color_plane_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  GstyleColorPlane *self = GSTYLE_COLOR_PLANE (object);
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GdkRGBA rgba = {0};
+  GstyleXYZ xyz;
+
+  switch (prop_id)
+    {
+    case PROP_MODE:
+      g_value_set_enum (value, priv->mode);
+      break;
+
+    case PROP_RGBA:
+      gstyle_color_plane_get_rgba (self, &rgba);
+      g_value_set_boxed (value, &rgba);
+      break;
+
+    case PROP_XYZ:
+      gstyle_color_plane_get_xyz (self, &xyz);
+      g_value_set_boxed (value, &xyz);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_plane_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GstyleColorPlane *self = GSTYLE_COLOR_PLANE (object);
+  GdkRGBA *rgba_p;
+  GstyleXYZ *xyz_p;
+  GstyleXYZ xyz = {0};
+  GdkRGBA rgba = {0.5, 0.3, 0.3, 0.0};
+
+  switch (prop_id)
+    {
+    case PROP_MODE:
+      gstyle_color_plane_set_mode (self, g_value_get_enum (value));
+      break;
+
+    case PROP_RGBA:
+      rgba_p = (GdkRGBA *)g_value_get_boxed (value);
+      if (rgba_p == NULL)
+        rgba_p = &rgba;
+
+      gstyle_color_plane_set_rgba (self, rgba_p);
+
+    case PROP_XYZ:
+      xyz_p = (GstyleXYZ *)g_value_get_boxed (value);
+      if (xyz_p == NULL)
+        {
+          gstyle_color_convert_rgb_to_xyz (&rgba, &xyz);
+          gstyle_color_plane_set_xyz (self, &xyz);
+        }
+      else
+        gstyle_color_plane_set_xyz (self, xyz_p);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_plane_class_init (GstyleColorPlaneClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gstyle_color_plane_finalize;
+  object_class->get_property = gstyle_color_plane_get_property;
+  object_class->set_property = gstyle_color_plane_set_property;
+
+  widget_class->draw = gstyle_color_plane_draw;
+  widget_class->size_allocate = gstyle_color_plane_size_allocate;
+  widget_class->key_press_event = gstyle_color_plane_key_press;
+
+  properties [PROP_MODE] =
+    g_param_spec_enum ("mode",
+                       "Mode",
+                       "The mode displayed",
+                       GSTYLE_TYPE_COLOR_PLANE_MODE,
+                       GSTYLE_COLOR_PLANE_MODE_HUE,
+                       (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_RGBA] =
+    g_param_spec_boxed ("rgba",
+                        "rgba",
+                        "Color pointed by the cursor",
+                        GDK_TYPE_RGBA,
+                        (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_XYZ] =
+    g_param_spec_boxed ("xyz",
+                        "xyz",
+                        "Color pointed by the cursor",
+                        GSTYLE_TYPE_XYZ,
+                        (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS));
+
+  /* TODO: add *_adjustment properties */
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_set_css_name (widget_class, "gstylecolorplane");
+}
+
+static void
+set_cross_cursor (GtkWidget *widget,
+                  gboolean   enabled)
+{
+  GstyleColorPlane *self = (GstyleColorPlane *)widget;
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GdkCursor *cursor = NULL;
+  GdkWindow *window;
+  GdkDevice *device;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  window = gtk_widget_get_window (widget);
+  device = gtk_gesture_get_device (priv->drag_gesture);
+
+  if (!window || !device)
+    return;
+
+  if (enabled)
+    cursor = gdk_cursor_new_from_name (gtk_widget_get_display (GTK_WIDGET (widget)), "crosshair");
+
+  gdk_window_set_device_cursor (window, device, cursor);
+
+  if (cursor)
+    g_object_unref (cursor);
+}
+
+static void
+hold_action (GtkGestureLongPress *gesture,
+             gdouble              x,
+             gdouble              y,
+             GstyleColorPlane    *self)
+{
+  gboolean handled;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  g_signal_emit_by_name (self, "popup-menu", &handled);
+}
+
+static void
+drag_gesture_begin (GtkGestureDrag   *gesture,
+                    gdouble           start_x,
+                    gdouble           start_y,
+                    GstyleColorPlane *self)
+{
+  /* GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self); */
+  guint button;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+  if (button == GDK_BUTTON_SECONDARY)
+    {
+      gboolean handled;
+      g_signal_emit_by_name (self, "popup-menu", &handled);
+    }
+
+  if (button != GDK_BUTTON_PRIMARY)
+    {
+      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
+      return;
+    }
+
+  set_cross_cursor (GTK_WIDGET (self), TRUE);
+  update_cursor (self, start_x, start_y);
+
+  gtk_widget_grab_focus (GTK_WIDGET (self));
+  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+}
+
+static void
+drag_gesture_update (GtkGestureDrag   *gesture,
+                     gdouble           offset_x,
+                     gdouble           offset_y,
+                     GstyleColorPlane *self)
+{
+  /* GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self); */
+  gdouble start_x, start_y;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  gtk_gesture_drag_get_start_point (GTK_GESTURE_DRAG (gesture),
+                                    &start_x, &start_y);
+
+  update_cursor (self, start_x + offset_x, start_y + offset_y);
+}
+
+static void
+drag_gesture_end (GtkGestureDrag   *gesture,
+                  gdouble           offset_x,
+                  gdouble           offset_y,
+                  GstyleColorPlane *self)
+{
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  set_cross_cursor (GTK_WIDGET (self), FALSE);
+}
+
+static void
+gstyle_color_plane_init (GstyleColorPlane *self)
+{
+  GstyleColorPlanePrivate *priv = gstyle_color_plane_get_instance_private (self);
+  GtkStyleContext *context;
+  AtkObject *atk_obj;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+
+  gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
+  gtk_widget_set_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK |
+                                            GDK_TOUCH_MASK |
+                                            GDK_BUTTON_PRESS_MASK |
+                                            GDK_BUTTON_RELEASE_MASK |
+                                            GDK_POINTER_MOTION_MASK);
+
+  atk_obj = gtk_widget_get_accessible (GTK_WIDGET (self));
+  if (GTK_IS_ACCESSIBLE (atk_obj))
+    {
+      atk_object_set_name (atk_obj, _("Color Plane"));
+      atk_object_set_role (atk_obj, ATK_ROLE_COLOR_CHOOSER);
+    }
+
+  setup_component (self, GSTYLE_COLOR_COMPONENT_HSV_H, 0.0, 0.0, 360.0, 1.0, 1.0, 360.0, COLOR_SPACE_HSV);
+  setup_component (self, GSTYLE_COLOR_COMPONENT_HSV_S, 0.0, 0.0, 100.0, 1.0, 1.0, 100.0, COLOR_SPACE_HSV);
+  setup_component (self, GSTYLE_COLOR_COMPONENT_HSV_V, 0.0, 0.0, 100.0, 1.0, 1.0, 100.0, COLOR_SPACE_HSV);
+
+  setup_component (self, GSTYLE_COLOR_COMPONENT_LAB_L, 0.0, 0.0, 100.0, 1.0, 1.0, 1.0, COLOR_SPACE_CIELAB);
+  setup_component (self, GSTYLE_COLOR_COMPONENT_LAB_A, 0.0, -128.0, 128.0, 1.0, 1.0, 1.0, 
COLOR_SPACE_CIELAB);
+  setup_component (self, GSTYLE_COLOR_COMPONENT_LAB_B, 0.0, -128.0, 128.0, 1.0, 1.0, 1.0, 
COLOR_SPACE_CIELAB);
+
+  setup_component (self, GSTYLE_COLOR_COMPONENT_RGB_RED, 0.0, 0.0, 255.0, 1.0, 1.0, 255.0, COLOR_SPACE_RGB);
+  setup_component (self, GSTYLE_COLOR_COMPONENT_RGB_GREEN, 0.0, 0.0, 255.0, 1.0, 1.0, 255.0, 
COLOR_SPACE_RGB);
+  setup_component (self, GSTYLE_COLOR_COMPONENT_RGB_BLUE, 0.0, 0.0, 255.0, 1.0, 1.0, 255.0, COLOR_SPACE_RGB);
+
+  priv->preferred_unit = GSTYLE_COLOR_UNIT_VALUE;
+
+  for (gint i = 0; i < N_GSTYLE_COLOR_COMPONENT; ++i)
+    priv->comp [i].handler = g_signal_connect_swapped (priv->comp [i].adj,
+                                                       "value-changed",
+                                                       G_CALLBACK (adjustments_changed), self);
+
+  priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (self));
+  g_signal_connect (priv->drag_gesture, "drag-begin", G_CALLBACK (drag_gesture_begin), self);
+  g_signal_connect (priv->drag_gesture, "drag-update", G_CALLBACK (drag_gesture_update), self);
+  g_signal_connect (priv->drag_gesture, "drag-end", G_CALLBACK (drag_gesture_end), self);
+
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->drag_gesture), 0);
+
+  priv->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (self));
+  g_signal_connect (priv->long_press_gesture, "pressed", G_CALLBACK (hold_action), self);
+
+  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->long_press_gesture), TRUE);
+
+  priv->mode = GSTYLE_COLOR_PLANE_MODE_HUE;
+  priv->ref_comp = GSTYLE_COLOR_COMPONENT_HSV_H;
+  priv->xyz.alpha = 1;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  priv->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
+}
+
+GType
+gstyle_color_plane_mode_get_type (void)
+{
+  static GType type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_COLOR_PLANE_MODE_HUE, "GSTYLE_COLOR_PLANE_MODE_HUE", "hue" },
+    { GSTYLE_COLOR_PLANE_MODE_SATURATION, "GSTYLE_COLOR_PLANE_MODE_SATURATION", "saturation" },
+    { GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS, "GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS", "brightness" },
+    { GSTYLE_COLOR_PLANE_MODE_CIELAB_L, "GSTYLE_COLOR_PLANE_MODE_CIELAB_L", "cielab-l" },
+    { GSTYLE_COLOR_PLANE_MODE_CIELAB_A, "GSTYLE_COLOR_PLANE_MODE_CIELAB_A", "cielab-a" },
+    { GSTYLE_COLOR_PLANE_MODE_CIELAB_B, "GSTYLE_COLOR_PLANE_MODE_CIELAB_B", "cielab-b" },
+    { GSTYLE_COLOR_PLANE_MODE_RED, "GSTYLE_COLOR_PLANE_MODE_RED", "red" },
+    { GSTYLE_COLOR_PLANE_MODE_GREEN, "GSTYLE_COLOR_PLANE_MODE_GREEN", "green" },
+    { GSTYLE_COLOR_PLANE_MODE_BLUE, "GSTYLE_COLOR_PLANE_MODE_BLUE", "blue" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstyleColorPlaneMode", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/gstyle/gstyle-color-plane.h b/contrib/gstyle/gstyle-color-plane.h
new file mode 100644
index 0000000..01d2559
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-plane.h
@@ -0,0 +1,89 @@
+/* gstyle-color-plane.h
+ *
+ * based on : gtk-color-plane
+ *   GTK - The GIMP Toolkit
+ *   Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_PLANE_H
+#define GSTYLE_COLOR_PLANE_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "gstyle-color.h"
+#include "gstyle-color-component.h"
+#include "gstyle-color-convert.h"
+#include "gstyle-color-filter.h"
+#include "gstyle-xyz.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_COLOR_PLANE (gstyle_color_plane_get_type())
+#define GSTYLE_TYPE_COLOR_PLANE_MODE (gstyle_color_plane_mode_get_type())
+
+G_DECLARE_DERIVABLE_TYPE (GstyleColorPlane, gstyle_color_plane, GSTYLE, COLOR_PLANE, GtkDrawingArea)
+
+typedef enum
+{
+  GSTYLE_COLOR_PLANE_MODE_HUE,
+  GSTYLE_COLOR_PLANE_MODE_SATURATION,
+  GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS,
+  GSTYLE_COLOR_PLANE_MODE_CIELAB_L,
+  GSTYLE_COLOR_PLANE_MODE_CIELAB_A,
+  GSTYLE_COLOR_PLANE_MODE_CIELAB_B,
+  GSTYLE_COLOR_PLANE_MODE_RED,
+  GSTYLE_COLOR_PLANE_MODE_GREEN,
+  GSTYLE_COLOR_PLANE_MODE_BLUE,
+  GSTYLE_COLOR_PLANE_MODE_NONE
+} GstyleColorPlaneMode;
+
+struct _GstyleColorPlaneClass
+{
+  GtkDrawingAreaClass parent;
+};
+
+GType                gstyle_color_plane_mode_get_type                 (void);
+
+GstyleColorPlane    *gstyle_color_plane_new                           (void);
+GtkAdjustment       *gstyle_color_plane_get_component_adjustment      (GstyleColorPlane       *self,
+                                                                       GstyleColorComponent    comp);
+GstyleColorFilter    gstyle_color_plane_get_filter                    (GstyleColorPlane       *self);
+void                 gstyle_color_plane_get_filtered_rgba             (GstyleColorPlane       *self,
+                                                                       GdkRGBA                *rgba);
+void                 gstyle_color_plane_get_rgba                      (GstyleColorPlane       *self,
+                                                                       GdkRGBA                *rgba);
+void                 gstyle_color_plane_get_xyz                       (GstyleColorPlane       *self,
+                                                                       GstyleXYZ              *xyz);
+void                 gstyle_color_plane_set_filter                    (GstyleColorPlane       *self,
+                                                                       GstyleColorFilter       filter_cb,
+                                                                       gpointer                user_data);
+void                 gstyle_color_plane_set_mode                      (GstyleColorPlane       *self,
+                                                                       GstyleColorPlaneMode    mode);
+void                 gstyle_color_plane_set_preferred_unit            (GstyleColorPlane       *self,
+                                                                       GstyleColorUnit         
preferred_unit);
+void                 gstyle_color_plane_set_rgba                      (GstyleColorPlane       *self,
+                                                                       const GdkRGBA          *rgba);
+void                 gstyle_color_plane_set_xyz                       (GstyleColorPlane       *self,
+                                                                       const GstyleXYZ        *xyz);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_PLANE_H */
+
diff --git a/contrib/gstyle/gstyle-color-predefined.h b/contrib/gstyle/gstyle-color-predefined.h
new file mode 100644
index 0000000..6573d77
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-predefined.h
@@ -0,0 +1,189 @@
+/* gstyle-color-predefined.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_PREDEFINED_H
+#define GSTYLE_COLOR_PREDEFINED_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+  gchar  *name;
+  guint8  red;
+  guint8  green;
+  guint8  blue;
+  guint8  index;
+} NamedColor;
+
+G_GNUC_UNUSED
+static NamedColor predefined_colors_table[] =
+{
+  { "aliceblue", 240, 248, 255 },
+  { "antiquewhite", 250, 235, 215 },
+  { "aqua", 0, 255, 255 },
+  { "aquamarine", 127, 255, 212 },
+  { "azure", 240, 255, 255 },
+  { "beige", 245, 245, 220 },
+  { "bisque", 255, 228, 196 },
+  { "black", 0, 0, 0 },
+  { "blanchedalmond", 255, 235, 205 },
+  { "blue", 0, 0, 255 },
+  { "blueviolet", 138, 43, 226 },
+  { "brown", 165, 42, 42 },
+  { "burlywood", 222, 184, 135 },
+  { "cadetblue", 95, 158, 160 },
+  { "chartreuse", 127, 255, 0 },
+  { "chocolate", 210, 105, 30 },
+  { "coral", 255, 127, 80 },
+  { "cornflowerblue", 100, 149, 237 },
+  { "cornsilk", 255, 248, 220 },
+  { "crimson", 220, 20, 60 },
+  { "cyan", 0, 255, 255 },
+  { "darkblue", 0, 0, 139 },
+  { "darkcyan", 0, 139, 139 },
+  { "darkgoldenrod", 184, 134, 11 },
+  { "darkgray", 169, 169, 169 },
+  { "darkgreen", 0, 100, 0 },
+  { "darkgrey", 169, 169, 169 },
+  { "darkkhaki", 189, 183, 107 },
+  { "darkmagenta", 139, 0, 139 },
+  { "darkolivegreen", 85, 107, 47 },
+  { "darkorange", 255, 140, 0 },
+  { "darkorchid", 153, 50, 204 },
+  { "darkred", 139, 0, 0 },
+  { "darksalmon", 233, 150, 122 },
+  { "darkseagreen", 143, 188, 143 },
+  { "darkslateblue", 72, 61, 139 },
+  { "darkslategray", 47, 79, 79 },
+  { "darkslategrey", 47, 79, 79 },
+  { "darkturquoise", 0, 206, 209 },
+  { "darkviolet", 148, 0, 211 },
+  { "deeppink", 255, 20, 147 },
+  { "deepskyblue", 0, 191, 255 },
+  { "dimgray", 105, 105, 105 },
+  { "dimgrey", 105, 105, 105 },
+  { "dodgerblue", 30, 144, 255 },
+  { "firebrick", 178, 34, 34 },
+  { "floralwhite", 255, 250, 240 },
+  { "forestgreen", 34, 139, 34 },
+  { "fuchsia", 255, 0, 255 },
+  { "gainsboro", 220, 220, 220 },
+  { "ghostwhite", 248, 248, 255 },
+  { "gold", 255, 215, 0 },
+  { "goldenrod", 218, 165, 32 },
+  { "gray", 128, 128, 128 },
+  { "green", 0, 128, 0 },
+  { "greenyellow", 173, 255, 47 },
+  { "grey", 128, 128, 128 },
+  { "honeydew", 240, 255, 240 },
+  { "hotpink", 255, 105, 180 },
+  { "indianred", 205, 92, 92 },
+  { "indigo", 75, 0, 130 },
+  { "ivory", 255, 255, 240 },
+  { "khaki", 240, 230, 140 },
+  { "lavender", 230, 230, 250 },
+  { "lavenderblush", 255, 240, 245 },
+  { "lawngreen", 124, 252, 0 },
+  { "lemonchiffon", 255, 250, 205 },
+  { "lightblue", 173, 216, 230 },
+  { "lightcoral", 240, 128, 128 },
+  { "lightcyan", 224, 255, 255 },
+  { "lightgoldenrodyellow", 250, 250, 210 },
+  { "lightgray", 211, 211, 211 },
+  { "lightgreen", 144, 238, 144 },
+  { "lightgrey", 211, 211, 211 },
+  { "lightpink", 255, 182, 193 },
+  { "lightsalmon", 255, 160, 122 },
+  { "lightseagreen",  32, 178, 170 },
+  { "lightskyblue", 135, 206, 250 },
+  { "lightslategray", 119, 136, 153 },
+  { "lightslategrey", 119, 136, 153 },
+  { "lightsteelblue", 176, 196, 222 },
+  { "lightyellow", 255, 255, 224 },
+  { "lime", 0, 255, 0 },
+  { "limegreen", 50, 205, 50 },
+  { "linen", 250, 240, 230 },
+  { "magenta", 255, 0, 255 },
+  { "maroon", 128, 0, 0 },
+  { "mediumaquamarine", 102, 205, 170 },
+  { "mediumblue", 0, 0, 205 },
+  { "mediumorchid", 186, 85, 211 },
+  { "mediumpurple", 147, 112, 219 },
+  { "mediumseagreen", 60, 179, 113 },
+  { "mediumslateblue", 123, 104, 238 },
+  { "mediumspringgreen", 0, 250, 154 },
+  { "mediumturquoise", 72, 209, 204 },
+  { "mediumvioletred", 199, 21, 133 },
+  { "midnightblue", 25, 25, 112 },
+  { "mintcream", 245, 255, 250 },
+  { "mistyrose", 255, 228, 225 },
+  { "moccasin", 255, 228, 181 },
+  { "navajowhite", 255, 222, 173 },
+  { "navy", 0, 0, 128 },
+  { "oldlace", 253, 245, 230 },
+  { "olive", 128, 128, 0 },
+  { "olivedrab", 107, 142, 35 },
+  { "orange", 255, 165, 0 },
+  { "orangered", 255, 69, 0 },
+  { "orchid", 218, 112, 214 },
+  { "palegoldenrod", 238, 232, 170 },
+  { "palegreen", 152, 251, 152 },
+  { "paleturquoise", 175, 238, 238 },
+  { "palevioletred", 219, 112, 147 },
+  { "papayawhip", 255, 239, 213 },
+  { "peachpuff", 255, 218, 185 },
+  { "peru", 205, 133, 63 },
+  { "pink", 255, 192, 203 },
+  { "plum", 221, 160, 221 },
+  { "powderblue", 176, 224, 230 },
+  { "purple", 128, 0, 128 },
+  { "red", 255, 0, 0 },
+  { "rosybrown", 188, 143, 143 },
+  { "royalblue", 65, 105, 225 },
+  { "saddlebrown", 139, 69, 19 },
+  { "salmon", 250, 128, 114 },
+  { "sandybrown", 244, 164, 96 },
+  { "seagreen", 46, 139, 87 },
+  { "seashell", 255, 245, 238 },
+  { "sienna", 160, 82, 45 },
+  { "silver", 192, 192, 192 },
+  { "skyblue", 135, 206, 235 },
+  { "slateblue", 106, 90, 205 },
+  { "slategray", 112, 128, 144 },
+  { "slategrey", 112, 128, 144 },
+  { "snow", 255, 250, 250 },
+  { "springgreen", 0, 255, 127 },
+  { "steelblue", 70, 130, 180 },
+  { "tan", 210, 180, 140 },
+  { "teal", 0, 128, 128 },
+  { "thistle", 216, 191, 216 },
+  { "tomato", 255, 99, 71 },
+  { "turquoise", 64, 224, 208 },
+  { "violet", 238, 130, 238 },
+  { "wheat", 245, 222, 179 },
+  { "white", 255, 255, 255 },
+  { "whitesmoke", 245, 245, 245 },
+  { "yellow", 255, 255, 0 },
+  { "yellowgreen", 154, 205, 50 },
+};
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_PREDEFINED_H */
diff --git a/contrib/gstyle/gstyle-color-scale.c b/contrib/gstyle/gstyle-color-scale.c
new file mode 100644
index 0000000..7197b34
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-scale.c
@@ -0,0 +1,738 @@
+/* gstyle-color-scale.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-color-scale"
+
+#include <math.h>
+#include <cairo/cairo.h>
+#include <glib/gi18n.h>
+
+#include "gstyle-css-provider.h"
+#include "gstyle-utils.h"
+
+#include "gstyle-color-scale.h"
+
+static glong id_count = 1;
+
+typedef struct _ColorStop
+{
+  gint    id;
+  gdouble offset;
+  GdkRGBA rgba;
+} ColorStop;
+
+struct _GstyleColorScale
+{
+  GtkScale              parent_instance;
+
+  GstyleCssProvider    *default_provider;
+
+  GstyleColorFilter     filter;
+  gpointer              filter_user_data;
+
+  GtkGesture           *long_press_gesture;
+  GstyleColorScaleKind  kind;
+  GSequence            *custom_color_stops;
+  cairo_pattern_t      *pattern;
+  cairo_pattern_t      *checkered_pattern;
+
+  cairo_surface_t      *data_surface;
+  guint32              *data_raw;
+  guint32              *data_raw_filtered;
+  gint                  data_stride;
+};
+
+G_DEFINE_TYPE (GstyleColorScale, gstyle_color_scale, GTK_TYPE_SCALE)
+
+enum {
+  PROP_0,
+  PROP_KIND,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+hold_action (GtkGestureLongPress *gesture,
+             gdouble              x,
+             gdouble              y,
+             GstyleColorScale    *self)
+{
+  gboolean handled;
+
+  g_assert (GSTYLE_IS_COLOR_SCALE (self));
+
+  g_signal_emit_by_name (self, "popup-menu", &handled);
+}
+
+static void
+filter_data (GstyleColorScale *self)
+{
+  guint32 *src_data = self->data_raw;
+  guint32 *dst_data = self->data_raw_filtered;
+  GdkRGBA src_rgba;
+  GdkRGBA dst_rgba;
+
+  g_assert (GSTYLE_IS_COLOR_SCALE (self));
+  g_assert (self->filter != NULL);
+
+  for (gint i = 0; i < GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE; ++i)
+    {
+      unpack_rgba24 (src_data [i], &src_rgba);
+      self->filter (&src_rgba, &dst_rgba, self->filter_user_data);
+      dst_data [i] = pack_rgba24 (&dst_rgba);
+    }
+}
+
+/**
+ * gstyle_color_scale_get_filter: (skip):
+ * @self: A #GstyleColorScale
+ *
+ * Get a pointer to the current filter function or %NULL
+ * if no filter is actually set.
+ *
+ * Returns: (nullable): A GstyleColorFilter function pointer.
+ *
+ */
+GstyleColorFilter
+gstyle_color_scale_get_filter (GstyleColorScale *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR_SCALE (self), NULL);
+
+  return self->filter;
+}
+
+/* TODO: do a copy of orignal data so that we can remove or change the filter
+ * keeping the original datas */
+/**
+ * gstyle_color_scale_set_filter:
+ * @self: A #GstyleColorScale
+ * @filter_cb: (scope notified) (nullable): A GstyleColorFilter filter function or
+ *   %NULL to unset the current filter. In this case, user_data is ignored.
+ * @user_data: (closure) (nullable): user data to pass when calling the filter function
+ *
+ * Set a filter to be used to change the drawing of the color scale
+ * when kind is set to custom-data (GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA)
+ * The data are filtered just after calling gstyle_color_scale_set_custom_data.
+ * So that if you remove or change the filter, you need to call it again.
+ *
+ */
+void
+gstyle_color_scale_set_filter (GstyleColorScale  *self,
+                               GstyleColorFilter  filter_cb,
+                               gpointer           user_data)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_SCALE (self));
+
+  if (self->filter != filter_cb)
+    {
+      self->filter = filter_cb;
+      self->filter_user_data = (filter_cb == NULL) ? NULL : user_data;
+
+      if (self->kind != GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA)
+        return;
+
+      cairo_surface_flush (self->data_surface);
+      if (filter_cb == NULL)
+        memcpy (self->data_raw_filtered, self->data_raw, self->data_stride);
+      else
+        filter_data (self);
+
+      cairo_surface_mark_dirty (self->data_surface);
+      gtk_widget_queue_draw (GTK_WIDGET (self));
+    }
+}
+
+/**
+ * gstyle_color_scale_clear_color_stops:
+ * @self: A #GstyleColorScale
+ *
+ * CLear all the color stops from the color scale.
+ *
+ */
+void
+gstyle_color_scale_clear_color_stops (GstyleColorScale *self)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_SCALE (self));
+
+  g_sequence_free (self->custom_color_stops);
+  self->custom_color_stops = g_sequence_new (NULL);
+}
+
+static gint
+compare_color_stop_by_offset (ColorStop        *a,
+                              ColorStop        *b,
+                              GstyleColorScale *self)
+{
+  gdouble delta;
+
+  g_assert (GSTYLE_IS_COLOR_SCALE (self));
+  g_assert (b != NULL && a != NULL);
+
+  delta = a->offset - b->offset;
+  if (delta < 0)
+    return -1;
+  else if (delta > 0)
+    return 1;
+  else
+    return 0;
+}
+
+/**
+ * gstyle_color_scale_remove_color_stop:
+ * @self: A #GstyleColorScale
+ * @id: id of a color stop as returned by gstyle_color_scale_add_* functions
+ *
+ * Remove an existing color stop for the color scale.
+ *
+ * Returns:  %TRUE if the color stop exist and is removed, %FALSE otherwise.
+ *
+ */
+gboolean
+gstyle_color_scale_remove_color_stop (GstyleColorScale *self,
+                                      gint              id)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR_SCALE (self), FALSE);
+  g_return_val_if_fail (id <= 0, FALSE);
+
+  /* TODO: function code */
+  return TRUE;
+}
+
+/* TODO: use color stops with the data_raw instead of gradient pattern
+ * so that we can use filter on that too */
+
+/**
+ * gstyle_color_scale_add_rgba_color_stop:
+ * @self: A #GstyleColorScale
+ * @offset: position in the range [0, 1] of the color stop
+ * @rgba: A #GdkRGBA
+ *
+ * Set a color stop for the color scale.
+ * If there's no color stop at offset 0, a black opaque color stop is automatically added.
+ * If there's no color stop at offset 1, a white opaque color stop is automatically added.
+ *
+ * Returns: the id of the color stop or -1 if there's an existing
+ * stop color at the same offset
+ *
+ */
+gint
+gstyle_color_scale_add_rgba_color_stop (GstyleColorScale *self,
+                                        gdouble           offset,
+                                        GdkRGBA          *rgba)
+{
+  ColorStop *color_stop;
+  GSequenceIter *iter = NULL;
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR_SCALE (self), -1);
+  g_return_val_if_fail (0.0 <= offset && offset <= 1.0, -1);
+  g_return_val_if_fail (rgba != NULL, -1);
+
+  color_stop = g_slice_new0 (ColorStop);
+  color_stop->id = id_count;
+  color_stop->offset = offset;
+  color_stop->rgba = *rgba;
+
+  if (!g_sequence_is_empty (self->custom_color_stops))
+    iter = g_sequence_lookup (self->custom_color_stops, color_stop,
+                              (GCompareDataFunc)compare_color_stop_by_offset,
+                              self);
+
+  if (iter != NULL)
+    {
+      g_slice_free (ColorStop, color_stop);
+      return -1;
+    }
+  else
+    {
+      g_sequence_insert_sorted (self->custom_color_stops, color_stop,
+                                (GCompareDataFunc)compare_color_stop_by_offset,
+                                self);
+      id_count += 1;
+
+      if (self->pattern != NULL)
+        cairo_pattern_destroy (self->pattern);
+
+      self->pattern = NULL;
+
+      if (gtk_widget_get_realized (GTK_WIDGET (self)))
+        gtk_widget_queue_draw (GTK_WIDGET (self));
+
+      return color_stop->id;
+    }
+}
+
+/**
+ * gstyle_color_scale_set_custom_data:
+ * @self: A #GstyleColorScale
+ * @data: data location
+ *
+ * Set the data used to draw the color ramp if your have
+ * GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA kind selected.
+ *
+ * the location point to a memory array of 256 contiguous pixels
+ * using the CAIRO_FORMAT_RGB24 format (so 256 * 4 bytes)
+ * This result in using an guint32 for each pixel.
+ *
+ */
+void
+gstyle_color_scale_set_custom_data (GstyleColorScale *self,
+                                    guint32          *data)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_SCALE (self));
+  g_return_if_fail (data != NULL);
+
+  if (self->kind != GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA)
+    {
+      g_warning ("You need to set the kind to custom-data (GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA)"
+                 " to use this function.");
+      return;
+    }
+
+  g_assert (self->data_surface != NULL);
+
+  cairo_surface_flush (self->data_surface);
+  memcpy (self->data_raw, data, self->data_stride);
+
+  if (self->filter == NULL)
+    memcpy (self->data_raw_filtered, self->data_raw, self->data_stride);
+  else
+    filter_data (self);
+
+  cairo_surface_mark_dirty (self->data_surface);
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+/**
+ * gstyle_color_scale_add_color_stop:
+ * @self: A #GstyleColorScale
+ * @offset: position in the range [0, 1] of the color stop
+ * @red: red component of the color stop
+ * @green: red component of the color stop
+ * @blue: red component of the color stop
+ * @alpha: red component of the color stop
+ *
+ * Set a color stop for the #GstyleColorScale.
+ * If there's no color stop at offset 0, a black opaque color stop is automatically added.
+ * If there's no color stop at offset 1, a white opaque color stop is automatically added.
+ *
+ * Returns: the id of the color stop or -1 if there's an existing
+ * stop color at the same offset
+ *
+ */
+gint
+gstyle_color_scale_add_color_stop (GstyleColorScale *self,
+                                   gdouble           offset,
+                                   gdouble           red,
+                                   gdouble           green,
+                                   gdouble           blue,
+                                   gdouble           alpha)
+{
+  GdkRGBA rgba = {red, green, blue, alpha};
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR_SCALE (self), -1);
+
+  return gstyle_color_scale_add_rgba_color_stop (self, offset, &rgba);
+}
+
+/**
+ * gstyle_color_scale_get_kind:
+ * @self: A #GstyleColorScale
+ *
+ * Get the kind of gradient displayed in the scale.
+ *
+ * Returns: a #GstyleColorKind.
+ *
+ */
+GstyleColorScaleKind
+gstyle_color_scale_get_kind (GstyleColorScale *self)
+{
+  g_assert (GSTYLE_IS_COLOR_SCALE (self));
+
+  return self->kind;
+}
+
+/**
+ * gstyle_color_scale_set_kind:
+ * @self: A #GstyleColorScale
+ * @kind: A #GstyleColorKind
+ *
+ * Set the kind of gradient displayed in the scale.
+ * If you set the kind to GSTYLE_COLOR_SCALE_KIND_CUSTOM_STOPS,
+ * all the previously added color stops are cleared.
+ *
+ * if you set the kind to GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA,
+ * the previous data are freed.
+ *
+ */
+void
+gstyle_color_scale_set_kind (GstyleColorScale     *self,
+                             GstyleColorScaleKind  kind)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_SCALE (self));
+
+  if (self->kind != kind)
+    {
+      self->kind = kind;
+      if (kind == GSTYLE_COLOR_SCALE_KIND_CUSTOM_STOPS)
+        gstyle_color_scale_clear_color_stops (self);
+      else if (kind == GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA)
+        {
+          self->data_stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24,
+                                                             GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE);
+          self->data_raw = g_malloc0 (self->data_stride);
+          self->data_raw_filtered = g_malloc0 (self->data_stride);
+          self->data_surface = cairo_image_surface_create_for_data ((guchar *)self->data_raw_filtered,
+                                                                    CAIRO_FORMAT_RGB24,
+                                                                    
GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE, 1,
+                                                                    self->data_stride);
+        }
+
+      if (self->pattern != NULL)
+        {
+          cairo_pattern_destroy (self->pattern);
+          self->pattern = NULL;
+        }
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_KIND]);
+
+      if (gtk_widget_get_realized (GTK_WIDGET (self)))
+        gtk_widget_queue_draw (GTK_WIDGET (self));
+    }
+}
+
+static void
+update_pattern (GstyleColorScale *self)
+{
+  cairo_pattern_t *pattern;
+
+  g_assert (GSTYLE_IS_COLOR_SCALE (self));
+
+  if (self->kind == GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA)
+    return;
+
+  pattern = cairo_pattern_create_linear (0, 0, 1, 0);
+  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
+
+  if (self->kind != GSTYLE_COLOR_SCALE_KIND_CUSTOM_STOPS)
+    {
+      switch (self->kind)
+        {
+        case GSTYLE_COLOR_SCALE_KIND_HUE:
+          cairo_pattern_add_color_stop_rgba (pattern, 0.0000, 1.0, 0.0, 0.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 0.1666, 1.0, 1.0, 0.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 0.3333, 0.0, 1.0, 0.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 0.5000, 0.0, 1.0, 1.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 0.6666, 0.0, 0.0, 1.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 0.8333, 1.0, 0.0, 1.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 1.0000, 1.0, 0.0, 0.0, 1.0);
+          break;
+
+        case GSTYLE_COLOR_SCALE_KIND_GREY:
+          cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 0.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1.0, 1.0, 1.0, 1.0);
+          break;
+
+        case GSTYLE_COLOR_SCALE_KIND_ALPHA:
+          cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 0.0, 0.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 0.0, 0.0, 1.0);
+          break;
+
+        case GSTYLE_COLOR_SCALE_KIND_RED:
+          cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 0.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 1.0, 1.0, 0.0, 0.0, 1.0);
+          break;
+
+        case GSTYLE_COLOR_SCALE_KIND_GREEN:
+          cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 0.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 1.0, 0.0, 1.0);
+          break;
+
+        case GSTYLE_COLOR_SCALE_KIND_BLUE:
+          cairo_pattern_add_color_stop_rgba (pattern, 0.0, 0.0, 0.0, 0.0, 1.0);
+          cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0.0, 0.0, 1.0, 1.0);
+          break;
+
+        case GSTYLE_COLOR_SCALE_KIND_CUSTOM_STOPS:
+        case GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA:
+        default:
+          g_assert_not_reached ();
+        }
+    }
+  else
+    {
+      GSequenceIter *iter;
+      GSequenceIter *iter_offset_zero = NULL;
+      GSequenceIter *iter_offset_one = NULL;
+      ColorStop local_color_stop;
+      gint len;
+
+      if (!g_sequence_is_empty (self->custom_color_stops))
+        {
+          local_color_stop.offset = 0.0;
+          iter_offset_zero = g_sequence_lookup (self->custom_color_stops, &local_color_stop,
+                                                (GCompareDataFunc)compare_color_stop_by_offset,
+                                                self);
+
+          local_color_stop.offset = 1.0;
+          iter_offset_one = g_sequence_lookup (self->custom_color_stops, &local_color_stop,
+                                               (GCompareDataFunc)compare_color_stop_by_offset,
+                                               self);
+        }
+
+      if (iter_offset_zero == NULL)
+        cairo_pattern_add_color_stop_rgba (pattern, 0, 0.0, 0.0, 0.0, 1.0);
+
+      if (iter_offset_one == NULL)
+        cairo_pattern_add_color_stop_rgba (pattern, 0, 0.0, 0.0, 0.0, 1.0);
+
+      len = g_sequence_get_length (self->custom_color_stops);
+      for (gint i = 0; i < len; ++i)
+        {
+          ColorStop *color_stop;
+          GdkRGBA rgba;
+
+          iter = g_sequence_get_iter_at_pos (self->custom_color_stops, i);
+          color_stop = g_sequence_get (iter);
+          rgba = color_stop->rgba;
+          cairo_pattern_add_color_stop_rgba (pattern, color_stop->offset,
+                                             rgba.red, rgba.green, rgba.blue, rgba.alpha);
+        }
+    }
+
+  cairo_pattern_destroy (self->pattern);
+  self->pattern = pattern;
+}
+
+static gboolean
+gstyle_color_scale_draw (GtkWidget *widget,
+                         cairo_t   *cr)
+{
+  GstyleColorScale *self = (GstyleColorScale *)widget;
+  GtkAllocation alloc;
+  gboolean inverted;
+  GdkRectangle rect;
+  cairo_matrix_t matrix;
+  cairo_pattern_t *data_pattern;
+
+  g_assert (GSTYLE_IS_COLOR_SCALE (self));
+  g_assert (cr != NULL);
+
+  gtk_widget_get_allocation (widget, &alloc);
+  gtk_range_get_range_rect (GTK_RANGE (self), &rect);
+
+  cairo_save (cr);
+  cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
+  cairo_clip (cr);
+
+  cairo_set_source_rgb (cr, 0.20, 0.20, 0.20);
+  cairo_paint (cr);
+  cairo_set_source_rgb (cr, 0.80, 0.80, 0.80);
+
+  cairo_matrix_init_scale (&matrix, 0.1, 0.1);
+  cairo_matrix_translate (&matrix, -rect.x - 1, -rect.y - 1);
+  cairo_pattern_set_matrix (self->checkered_pattern, &matrix);
+  cairo_mask (cr, self->checkered_pattern);
+
+  cairo_translate (cr, rect.x, rect.y);
+  cairo_scale (cr, rect.width, rect.height);
+
+  if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_VERTICAL)
+    {
+      cairo_rotate (cr, -G_PI_2);
+      cairo_scale (cr, -1, 1);
+    }
+
+ inverted = gtk_range_get_inverted (GTK_RANGE (self));
+  if (inverted)
+    {
+      cairo_translate (cr, 1, 0);
+      cairo_scale (cr, -1, 1);
+    }
+
+  if (self->kind != GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA)
+    {
+      if (self->pattern == NULL)
+        update_pattern (self);
+
+      cairo_set_source (cr, self->pattern);
+      cairo_paint (cr);
+    }
+  else
+    {
+      cairo_set_source_surface (cr, self->data_surface, 0.0, 0.0);
+      data_pattern = cairo_get_source (cr);
+      cairo_pattern_set_extend (data_pattern, CAIRO_EXTEND_NONE);
+      cairo_pattern_set_filter (data_pattern, CAIRO_FILTER_NEAREST);
+      cairo_matrix_init_scale (&matrix, 256.0, 1.0);
+      cairo_pattern_set_matrix (data_pattern, &matrix);
+      cairo_paint (cr);
+    }
+
+  cairo_restore (cr);
+
+  GTK_WIDGET_CLASS (gstyle_color_scale_parent_class)->draw (widget, cr);
+  return GDK_EVENT_PROPAGATE;
+}
+
+GstyleColorScale *
+gstyle_color_scale_new (GtkAdjustment *adjustment)
+{
+  return g_object_new (GSTYLE_TYPE_COLOR_SCALE,
+                       "adjustment", adjustment,
+                       NULL);
+}
+
+static void
+gstyle_color_scale_finalize (GObject *object)
+{
+  GstyleColorScale *self = (GstyleColorScale *)object;
+
+  G_OBJECT_CLASS (gstyle_color_scale_parent_class)->finalize (object);
+
+  g_clear_object (&self->long_press_gesture);
+  g_clear_object (&self->default_provider);
+  g_sequence_free (self->custom_color_stops);
+
+  cairo_pattern_destroy (self->checkered_pattern);
+  if (self->pattern != NULL)
+    cairo_pattern_destroy (self->pattern);
+
+  if (self->data_surface != NULL)
+    cairo_surface_destroy (self->data_surface);
+
+  g_free (self->data_raw);
+  g_free (self->data_raw_filtered);
+}
+
+static void
+gstyle_color_scale_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+  GstyleColorScale *self = GSTYLE_COLOR_SCALE (object);
+
+  switch (prop_id)
+    {
+    case PROP_KIND:
+      g_value_set_enum (value, gstyle_color_scale_get_kind (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_scale_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  GstyleColorScale *self = GSTYLE_COLOR_SCALE (object);
+
+  switch (prop_id)
+    {
+    case PROP_KIND:
+      gstyle_color_scale_set_kind (self, g_value_get_enum (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_scale_class_init (GstyleColorScaleClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gstyle_color_scale_finalize;
+  object_class->get_property = gstyle_color_scale_get_property;
+  object_class->set_property = gstyle_color_scale_set_property;
+  widget_class->draw = gstyle_color_scale_draw;
+
+  properties [PROP_KIND] =
+    g_param_spec_enum ("kind",
+                       "Kind",
+                       "The kind of gradient used",
+                       GSTYLE_TYPE_COLOR_SCALE_KIND,
+                       GSTYLE_COLOR_SCALE_KIND_HUE,
+                       (G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | 
G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_set_css_name (widget_class, "gstylecolorscale");
+}
+
+static void
+free_color_stop (ColorStop *color_stop)
+{
+  g_slice_free (ColorStop, color_stop);
+}
+
+static void
+gstyle_color_scale_init (GstyleColorScale *self)
+{
+  GtkStyleContext *context;
+
+  gtk_widget_add_events (GTK_WIDGET (self), GDK_TOUCH_MASK);
+
+  self->long_press_gesture = gtk_gesture_long_press_new (GTK_WIDGET (self));
+  g_signal_connect (self->long_press_gesture, "pressed", G_CALLBACK (hold_action), self);
+
+  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->long_press_gesture),
+                                              GTK_PHASE_TARGET);
+
+  self->custom_color_stops = g_sequence_new ((GDestroyNotify)free_color_stop);
+  self->checkered_pattern = gstyle_utils_get_checkered_pattern ();
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  self->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
+
+  gtk_scale_set_draw_value (GTK_SCALE (self), FALSE);
+}
+
+GType
+gstyle_color_scale_kind_get_type (void)
+{
+  static GType type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_COLOR_SCALE_KIND_HUE,          "GSTYLE_COLOR_SCALE_KIND_HUE",    "hue"    },
+    { GSTYLE_COLOR_SCALE_KIND_GREY,         "GSTYLE_COLOR_SCALE_KIND_GREY",   "grey"   },
+    { GSTYLE_COLOR_SCALE_KIND_ALPHA,        "GSTYLE_COLOR_SCALE_KIND_ALPHA",  "alpha"  },
+    { GSTYLE_COLOR_SCALE_KIND_RED,          "GSTYLE_COLOR_SCALE_KIND_RED",    "red"    },
+    { GSTYLE_COLOR_SCALE_KIND_GREEN,        "GSTYLE_COLOR_SCALE_KIND_GREEN",  "green"  },
+    { GSTYLE_COLOR_SCALE_KIND_BLUE,         "GSTYLE_COLOR_SCALE_KIND_BLUE",   "blue"   },
+    { GSTYLE_COLOR_SCALE_KIND_CUSTOM_STOPS, "GSTYLE_COLOR_SCALE_KIND_CUSTOM", "custom-stops" },
+    { GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA,  "GSTYLE_COLOR_SCALE_KIND_CUSTOM", "custom-data" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstyleColorScaleKind", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/gstyle/gstyle-color-scale.h b/contrib/gstyle/gstyle-color-scale.h
new file mode 100644
index 0000000..67825c3
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-scale.h
@@ -0,0 +1,78 @@
+/* gstyle-color-scale.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_SCALE_H
+#define GSTYLE_COLOR_SCALE_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "gstyle-color-filter.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE (256)
+#define GSTYLE_COLOR_SCALE_CUSTOM_DATA_BYTE_SIZE (GSTYLE_COLOR_SCALE_CUSTOM_DATA_PIXEL_SIZE * 4)
+
+typedef enum
+{
+  GSTYLE_COLOR_SCALE_KIND_HUE,
+  GSTYLE_COLOR_SCALE_KIND_GREY,
+  GSTYLE_COLOR_SCALE_KIND_ALPHA,
+  GSTYLE_COLOR_SCALE_KIND_RED,
+  GSTYLE_COLOR_SCALE_KIND_GREEN,
+  GSTYLE_COLOR_SCALE_KIND_BLUE,
+  GSTYLE_COLOR_SCALE_KIND_CUSTOM_STOPS,
+  GSTYLE_COLOR_SCALE_KIND_CUSTOM_DATA
+} GstyleColorScaleKind;
+
+#define GSTYLE_TYPE_COLOR_SCALE_KIND (gstyle_color_scale_kind_get_type())
+#define GSTYLE_TYPE_COLOR_SCALE      (gstyle_color_scale_get_type())
+
+G_DECLARE_FINAL_TYPE (GstyleColorScale, gstyle_color_scale, GSTYLE, COLOR_SCALE, GtkScale)
+
+GType                   gstyle_color_scale_kind_get_type               (void);
+
+GstyleColorScale       *gstyle_color_scale_new                         (GtkAdjustment        *adjustment);
+gint                    gstyle_color_scale_add_rgba_color_stop         (GstyleColorScale     *self,
+                                                                        gdouble               offset,
+                                                                        GdkRGBA              *rgba);
+gint                    gstyle_color_scale_add_color_stop              (GstyleColorScale     *self,
+                                                                        gdouble               offset,
+                                                                        gdouble               red,
+                                                                        gdouble               green,
+                                                                        gdouble               blue,
+                                                                        gdouble               alpha);
+void                    gstyle_color_scale_clear_color_stops           (GstyleColorScale     *self);
+GstyleColorFilter       gstyle_color_scale_get_filter                  (GstyleColorScale     *self);
+GstyleColorScaleKind    gstyle_color_scale_get_kind                    (GstyleColorScale     *self);
+
+gboolean                gstyle_color_scale_remove_color_stop           (GstyleColorScale     *self,
+                                                                        gint                  id);
+void                    gstyle_color_scale_set_custom_data             (GstyleColorScale     *self,
+                                                                        guint32              *data);
+void                    gstyle_color_scale_set_filter                  (GstyleColorScale     *self,
+                                                                        GstyleColorFilter     filter_cb,
+                                                                        gpointer              user_data);
+void                    gstyle_color_scale_set_kind                    (GstyleColorScale     *self,
+                                                                        GstyleColorScaleKind  kind);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_SCALE_H */
diff --git a/contrib/gstyle/gstyle-color-widget.c b/contrib/gstyle/gstyle-color-widget.c
new file mode 100644
index 0000000..1cca1a8
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-widget.c
@@ -0,0 +1,1252 @@
+/* gstyle-color-widget.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-color-widget"
+
+#include <cairo.h>
+#include <string.h>
+#include <gdk/gdk.h>
+
+#include "gstyle-css-provider.h"
+#include "gstyle-palette-widget.h"
+#include "gstyle-private.h"
+
+#include "gstyle-color-widget.h"
+
+struct _GstyleColorWidget
+{
+  GtkBin                         parent_instance;
+
+  GstyleCssProvider             *default_provider;
+
+  GtkLabel                      *label;
+  GstyleColor                   *color;
+  GstyleColorKind                fallback_name_kind;
+
+  GtkBorder                      cached_margin;
+  GtkBorder                      cached_border;
+
+  cairo_pattern_t               *checkered_pattern;
+
+  GtkTargetList                 *target_list;
+  GstyleColorWidget             *dnd_color_widget;
+  GtkWidget                     *dnd_window;
+  gboolean                       is_on_drag;
+
+  GtkGesture                    *drag_gesture;
+
+  GstylePaletteWidgetViewMode    container_view_mode;
+  GstyleColorWidgetDndLockFlags  dnd_lock : 4;
+  guint                          is_in_palette_widget : 1;
+  guint                          is_name_visible : 1;
+  guint                          is_fallback_name_visible : 1;
+};
+
+G_DEFINE_TYPE (GstyleColorWidget, gstyle_color_widget, GTK_TYPE_BIN)
+
+#define GSTYLE_COLOR_WIDGET_DROP_BORDER_PERCENT 0.20
+#define GSTYLE_COLOR_WIDGET_DRAG_ICON_OPACITY 0.8
+
+enum {
+  PROP_0,
+  PROP_COLOR,
+  PROP_DND_LOCK,
+  PROP_NAME_VISIBLE,
+  PROP_FALLBACK_NAME_KIND,
+  PROP_FALLBACK_NAME_VISIBLE,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static gboolean
+is_in_drop_zone (GstyleColorWidget *self,
+                 gint               x,
+                 gint               y)
+{
+  GtkAllocation alloc;
+  gint start_limit;
+  gint stop_limit;
+  gint dest_ref;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+  if (self->is_in_palette_widget)
+    {
+      if (self->container_view_mode == GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST)
+        {
+          start_limit = alloc.height * GSTYLE_COLOR_WIDGET_DROP_BORDER_PERCENT;
+          stop_limit = alloc.height * (1.0 - GSTYLE_COLOR_WIDGET_DROP_BORDER_PERCENT);
+          dest_ref = y;
+        }
+      else
+        {
+          start_limit = alloc.width * GSTYLE_COLOR_WIDGET_DROP_BORDER_PERCENT;
+          stop_limit = alloc.width * (1.0 - GSTYLE_COLOR_WIDGET_DROP_BORDER_PERCENT);
+          dest_ref = x;
+        }
+    }
+  else
+    {
+      /* dest_ref doesn't matter here, we just need to allow for the whole widget size */
+      start_limit = 0;
+      stop_limit = alloc.width;
+      dest_ref = x;
+    }
+
+  return (start_limit < dest_ref && dest_ref < stop_limit);
+}
+
+static gboolean
+gstyle_color_widget_on_drag_motion (GtkWidget      *widget,
+                                    GdkDragContext *context,
+                                    gint            x,
+                                    gint            y,
+                                    guint           time)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GdkAtom target;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  target = gtk_drag_dest_find_target (widget, context, NULL);
+
+  if ((target == gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET") ||
+       target == gdk_atom_intern_static_string ("application/x-color") ||
+       gtk_targets_include_text (&target, 1)) &&
+      is_in_drop_zone (self, x, y))
+    {
+      gtk_drag_highlight (widget);
+      gdk_drag_status (context, GDK_ACTION_COPY, time);
+      return TRUE;
+    }
+
+  gdk_drag_status (context, 0, time);
+  return FALSE;
+}
+
+static void
+gstyle_color_widget_on_drag_leave (GtkWidget      *widget,
+                                   GdkDragContext *context,
+                                   guint           time)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  gtk_drag_unhighlight (widget);
+}
+
+static gboolean
+gstyle_color_widget_on_drag_drop (GtkWidget        *widget,
+                                  GdkDragContext   *context,
+                                  gint              x,
+                                  gint              y,
+                                  guint             time)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GdkAtom target;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  target = gtk_drag_dest_find_target (widget, context, NULL);
+  if ((target == gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET") ||
+       target == gdk_atom_intern_static_string ("application/x-color") ||
+       gtk_targets_include_text (&target, 1)) &&
+      is_in_drop_zone (self, x, y))
+    {
+      gtk_drag_get_data (widget, context, target, time);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+dnd_color_fill (GstyleColorWidget *self,
+                GstyleColor       *src_color,
+                GstyleColor       *dst_color)
+{
+  const gchar *name;
+  GdkRGBA src_rgba;
+  GdkRGBA dst_rgba;
+
+  g_assert (GSTYLE_COLOR_WIDGET (self));
+  g_assert (GSTYLE_COLOR (src_color));
+  g_assert (GSTYLE_COLOR (dst_color));
+
+  gstyle_color_fill_rgba (src_color, &src_rgba);
+  gstyle_color_fill_rgba (dst_color, &dst_rgba);
+  if (!(self->dnd_lock & GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_COLOR))
+    {
+      dst_rgba.red = src_rgba.red;
+      dst_rgba.green = src_rgba.green;
+      dst_rgba.blue = src_rgba.blue;
+    }
+
+  if (!(self->dnd_lock & GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALPHA))
+    dst_rgba.alpha = src_rgba.alpha;
+
+  gstyle_color_set_rgba (self->color, &dst_rgba);
+
+  if (!(self->dnd_lock & GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_KIND))
+    gstyle_color_set_kind (dst_color, gstyle_color_get_kind (src_color));
+
+  if (!(self->dnd_lock & GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NAME))
+  {
+    name = gstyle_color_get_name (src_color);
+    gstyle_color_set_name (dst_color, name);
+  }
+}
+
+static void
+gstyle_color_widget_on_drag_data_received (GtkWidget        *widget,
+                                           GdkDragContext   *context,
+                                           gint              x,
+                                           gint              y,
+                                           GtkSelectionData *data,
+                                           guint             info,
+                                           guint             time)
+{
+  GstyleColorWidget *self = GSTYLE_COLOR_WIDGET (widget);
+  GstyleColor * const *src_color;
+  g_autofree gchar *color_string = NULL;
+  GstyleColorKind kind;
+  GdkAtom target;
+  guint16 *data_rgba;
+  GdkRGBA rgba;
+  gint len;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  target = gtk_selection_data_get_target (data);
+  if (target == gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET"))
+    {
+      /* TODO: check if the color widget is coming from a PaletteWidget container */
+      src_color = (void*)gtk_selection_data_get_data (data);
+      if (*src_color != self->color)
+        dnd_color_fill (self, *src_color, self->color);
+
+      gtk_drag_finish (context, TRUE, FALSE, time);
+
+      return;
+    }
+  else if (target == gdk_atom_intern_static_string ("application/x-color"))
+    {
+      len = gtk_selection_data_get_length (data);
+      if (len < 0 )
+        goto failed;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+      data_rgba = (guint16 *)gtk_selection_data_get_data (data);
+
+#pragma GCC diagnostic pop
+
+      rgba.red = data_rgba[0] / 65535.;
+      rgba.green = data_rgba[1] / 65535.;
+      rgba.blue = data_rgba[2] / 65535.;
+      rgba.alpha = data_rgba[3] / 65535.;
+
+      gstyle_color_set_rgba (self->color, &rgba);
+      gtk_drag_finish (context, TRUE, FALSE, time);
+
+      return;
+    }
+  else if (gtk_targets_include_text (&target, 1))
+    {
+      color_string = (gchar *)gtk_selection_data_get_text (data);
+      if (!gstyle_str_empty0 (color_string))
+        {
+          if (!gstyle_color_parse_color_string (color_string, &rgba, &kind))
+            goto failed;
+
+          gstyle_color_set_rgba (self->color, &rgba);
+          gtk_drag_finish (context, TRUE, FALSE, time);
+        }
+    }
+
+failed:
+  gtk_drag_finish (context, FALSE, FALSE, time);
+}
+
+static void
+gstyle_color_widget_on_drag_begin (GtkWidget      *widget,
+                                   GdkDragContext *context)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GtkAllocation allocation;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  gtk_widget_get_allocation (GTK_WIDGET (widget), &allocation);
+  self->dnd_color_widget = gstyle_color_widget_copy (GSTYLE_COLOR_WIDGET (widget));
+  self->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
+
+  gtk_widget_set_size_request (self->dnd_window, allocation.width, allocation.height);
+  gtk_window_set_screen (GTK_WINDOW (self->dnd_window), gtk_widget_get_screen (widget));
+
+  gtk_container_add (GTK_CONTAINER (self->dnd_window), GTK_WIDGET (self->dnd_color_widget));
+  gtk_widget_show_all (self->dnd_window);
+  gtk_widget_set_opacity (self->dnd_window, GSTYLE_COLOR_WIDGET_DRAG_ICON_OPACITY);
+
+  gtk_drag_set_icon_widget (context, self->dnd_window, 0, 0);
+}
+
+/* The multi-press gesture used by the flowbox to select a child
+ * forbid us to use dnd so we need to catch it here and select yourself
+ * the child
+ */
+static void
+gstyle_color_widget_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
+                                                guint                 n_press,
+                                                gdouble               x,
+                                                gdouble               y,
+                                                GstyleColorWidget    *self)
+{
+  GtkWidget *container;
+  GtkWidget *child;
+
+  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+
+  child = gtk_widget_get_parent (GTK_WIDGET (self));
+  if (child != NULL)
+    {
+      if (GTK_IS_LIST_BOX_ROW (child))
+        {
+          container = gtk_widget_get_parent (GTK_WIDGET (child));
+          if (container != NULL && GTK_IS_LIST_BOX (container))
+            {
+              gtk_list_box_select_row (GTK_LIST_BOX (container), GTK_LIST_BOX_ROW (child));
+              if (n_press == 2)
+                g_signal_emit_by_name (container, "row-activated", child);
+            }
+        }
+      else if (GTK_IS_FLOW_BOX_CHILD (child))
+        {
+          container = gtk_widget_get_parent (GTK_WIDGET (child));
+          if (container != NULL && GTK_IS_FLOW_BOX (container))
+            {
+              gtk_flow_box_select_child (GTK_FLOW_BOX (container), GTK_FLOW_BOX_CHILD (child));
+              if (n_press == 2)
+                g_signal_emit_by_name (container, "child-activated", child);
+            }
+        }
+    }
+}
+
+static void
+gstyle_color_widget_on_drag_data_get (GtkWidget        *widget,
+                                      GdkDragContext   *context,
+                                      GtkSelectionData *data,
+                                      guint             info,
+                                      guint             time)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GdkAtom target = gtk_selection_data_get_target (data);
+  guint16 data_rgba[4];
+  GdkRGBA rgba;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  if (target == gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET"))
+    gtk_selection_data_set (data, target, 8, (void*)&self->color, sizeof (gpointer));
+  else if (target == gdk_atom_intern_static_string ("application/x-color"))
+    {
+      gstyle_color_fill_rgba (self->color, &rgba);
+      data_rgba[0] = (guint16) (rgba.red * 65535);
+      data_rgba[1] = (guint16) (rgba.green * 65535);
+      data_rgba[2] = (guint16) (rgba.blue * 65535);
+      data_rgba[3] = (guint16) (rgba.alpha * 65535);
+
+      gtk_selection_data_set (data, target, 16, (void*)&data_rgba, 8);
+    }
+  else if (gtk_targets_include_text (&target, 1))
+    {
+      g_autofree gchar *name = NULL;
+
+      name = gstyle_color_to_string (self->color, GSTYLE_COLOR_KIND_ORIGINAL);
+      if (name == NULL)
+        name = gstyle_color_to_string (self->color, GSTYLE_COLOR_KIND_RGB_HEX6);
+
+      gtk_selection_data_set_text (data, name, -1);
+    }
+}
+
+static void
+gstyle_color_widget_on_drag_end (GtkWidget      *widget,
+                                 GdkDragContext *context)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  gtk_widget_destroy (self->dnd_window);
+  self->dnd_window = NULL;
+  self->dnd_color_widget = NULL;
+  self->is_on_drag = FALSE;
+}
+
+static gboolean
+gstyle_color_widget_on_drag_failed (GtkWidget      *widget,
+                                    GdkDragContext *context,
+                                    GtkDragResult   result)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  return FALSE;
+}
+
+static void
+update_border_and_margin (GstyleColorWidget *self)
+{
+  GtkStyleContext *style_context;
+  GtkStateFlags state;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  state = gtk_style_context_get_state (style_context);
+
+  gtk_style_context_get_margin (style_context, state, &self->cached_margin);
+  gtk_style_context_get_border (style_context, state, &self->cached_border);
+}
+
+static void
+gstyle_color_widget_size_allocate (GtkWidget     *widget,
+                                   GtkAllocation *allocation)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GtkAllocation child_allocation;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  if (self->label && gtk_widget_get_visible (GTK_WIDGET (self->label)))
+  {
+    child_allocation.x = 0;
+    child_allocation.y = 0;
+    child_allocation.width = allocation->width;
+    child_allocation.height = allocation->height;
+
+    gtk_widget_size_allocate (GTK_WIDGET (self->label), &child_allocation);
+  }
+
+  if (gtk_widget_get_realized (widget))
+    gdk_window_move_resize (gtk_widget_get_window (widget),
+                            allocation->x,
+                            allocation->y,
+                            allocation->width,
+                            allocation->height);
+}
+
+static void
+gstyle_color_widget_get_preferred_width (GtkWidget *widget,
+                                         gint      *min_width,
+                                         gint      *nat_width)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GtkWidget *child;
+  gint spacing;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  *min_width = 1;
+  *nat_width = 1;
+
+  update_border_and_margin (self);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child && gtk_widget_get_visible (child))
+    gtk_widget_get_preferred_width (child, min_width, nat_width);
+
+  spacing = self->cached_border.left +
+            self->cached_border.right +
+            self->cached_margin.left +
+            self->cached_margin.right;
+
+  *min_width += spacing;
+  *nat_width += spacing;
+}
+
+static void
+gstyle_color_widget_get_preferred_height (GtkWidget *widget,
+                                          gint      *min_height,
+                                          gint      *nat_height)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GtkWidget *child;
+  gint spacing;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  *min_height = 1;
+  *nat_height = 1;
+
+  update_border_and_margin (self);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child && gtk_widget_get_visible (child))
+    gtk_widget_get_preferred_height (child, min_height, nat_height);
+
+  spacing = self->cached_border.top +
+            self->cached_border.bottom +
+            self->cached_margin.top +
+            self->cached_margin.bottom;
+
+  *min_height += spacing;
+  *nat_height += spacing;
+}
+
+static gboolean
+gstyle_color_widget_draw (GtkWidget *widget,
+                          cairo_t   *cr)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+  GtkStyleContext *style_context;
+  GdkRectangle margin_box;
+  GdkRectangle border_box;
+  cairo_matrix_t matrix;
+  GdkRGBA bg_color = {0};
+  gint radius;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (cr != NULL);
+
+  style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  gtk_widget_get_allocation (widget, &margin_box);
+  margin_box.x = margin_box.y = 0;
+
+  gstyle_utils_get_rect_resized_box (margin_box, &margin_box, &self->cached_margin);
+  gstyle_utils_get_rect_resized_box (margin_box, &border_box, &self->cached_border);
+  cairo_save (cr);
+
+  if (self->color != NULL)
+    {
+      gtk_style_context_get (style_context,
+                            gtk_style_context_get_state (style_context),
+                            "border-radius", &radius,
+                            NULL);
+
+      gstyle_color_fill_rgba (self->color, &bg_color);
+
+      cairo_new_path (cr);
+      draw_cairo_round_box (cr, border_box, radius, radius, radius, radius);
+    }
+  else
+    cairo_rectangle (cr, border_box.x, border_box.y, border_box.width, border_box.height);
+
+  cairo_clip_preserve (cr);
+
+  cairo_set_source_rgb (cr, 0.20, 0.20, 0.20);
+  cairo_paint (cr);
+  cairo_set_source_rgb (cr, 0.80, 0.80, 0.80);
+
+  cairo_matrix_init_scale (&matrix, 0.1, 0.1);
+  cairo_matrix_translate (&matrix, -border_box.x, -border_box.y);
+  cairo_pattern_set_matrix (self->checkered_pattern, &matrix);
+  cairo_mask (cr, self->checkered_pattern);
+
+  if (self->color != NULL)
+    {
+      gdk_cairo_set_source_rgba (cr, &bg_color);
+      cairo_fill (cr);
+    }
+  else
+    gtk_render_background (style_context, cr, border_box.x, border_box.y, border_box.width, 
border_box.height);
+
+  cairo_restore (cr);
+  gtk_render_frame (gtk_widget_get_style_context (widget), cr,
+                    margin_box.x, margin_box.y, margin_box.width, margin_box.height);
+
+  return GTK_WIDGET_CLASS (gstyle_color_widget_parent_class)->draw (widget, cr);
+}
+
+static void
+update_label_visibility (GstyleColorWidget *self)
+{
+  const gchar *color_name;
+  g_autofree gchar *fallback_name = NULL;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  if (self->color == NULL)
+    {
+      if (gtk_widget_is_visible (GTK_WIDGET (self->label)))
+        gtk_widget_hide (GTK_WIDGET (self->label));
+
+      return;
+    }
+
+  if (self->is_name_visible)
+    {
+      color_name = gstyle_color_get_name (self->color);
+      if (color_name != NULL)
+        {
+          gtk_label_set_text (self->label, color_name);
+          if (!gtk_widget_is_visible (GTK_WIDGET (self->label)))
+            gtk_widget_show (GTK_WIDGET (self->label));
+
+          return;
+        }
+    }
+
+  if (self->is_fallback_name_visible)
+    {
+      fallback_name = gstyle_color_to_string (self->color, self->fallback_name_kind);
+      gtk_label_set_text (self->label, fallback_name);
+      if (!gtk_widget_is_visible (GTK_WIDGET (self->label)))
+        gtk_widget_show (GTK_WIDGET (self->label));
+    }
+  else
+    gtk_widget_hide (GTK_WIDGET (self->label));
+}
+
+static void
+match_label_color (GstyleColorWidget *self,
+                   GstyleColor       *color)
+{
+  PangoLayout *layout;
+  PangoAttrList *attr_list;
+  PangoAttribute *attr;
+  GdkRGBA rgba;
+  GdkRGBA dst_rgba;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GSTYLE_IS_COLOR (color));
+
+  layout = gtk_label_get_layout (self->label);
+  attr_list = pango_layout_get_attributes (layout);
+  if (attr_list == NULL)
+    {
+      attr_list = pango_attr_list_new ();
+      gtk_label_set_attributes (self->label, attr_list);
+      pango_attr_list_unref (attr_list);
+    }
+
+  gstyle_color_fill_rgba (color, &rgba);
+  gstyle_utils_get_contrasted_rgba (rgba, &dst_rgba);
+  attr = pango_attr_foreground_new (dst_rgba.red * 0xffff, dst_rgba.green * 0xffff, dst_rgba.blue * 0xffff);
+  pango_attr_list_change (attr_list, attr);
+  attr = pango_attr_background_new (rgba.red * 0xffff, rgba.green * 0xffff, rgba.blue * 0xffff);
+  pango_attr_list_change (attr_list, attr);
+}
+
+static void
+gstyle_color_widget_rgba_notify_cb (GstyleColorWidget *self,
+                                    GParamSpec        *pspec,
+                                    GstyleColor       *color)
+{
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (G_IS_PARAM_SPEC (pspec));
+  g_assert (GSTYLE_IS_COLOR (color));
+
+  update_label_visibility (self);
+  match_label_color (self, color);
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+gstyle_color_widget_name_notify_cb (GstyleColorWidget *self,
+                                    GParamSpec        *pspec,
+                                    GstyleColor       *color)
+{
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (G_IS_PARAM_SPEC (pspec));
+  g_assert (GSTYLE_IS_COLOR (color));
+
+  update_label_visibility (self);
+}
+
+static void
+gstyle_color_widget_disconnect_color (GstyleColorWidget *self)
+{
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+  g_assert (GSTYLE_IS_COLOR (self->color));
+
+  g_signal_handlers_disconnect_by_func (self->color,
+                                        G_CALLBACK (gstyle_color_widget_rgba_notify_cb),
+                                        self);
+
+ g_signal_handlers_disconnect_by_func (self->color,
+                                       G_CALLBACK (gstyle_color_widget_name_notify_cb),
+                                       self);
+}
+
+/**
+ * gstyle_color_widget_copy:
+ * @self: A #GstyleColorWidget
+ *
+ * Copy the given ##GstyleColorWidget.
+ * Notice that the underlaying #GstyleColor is shared
+ * between the two widgets (the copy increase the ref count)
+ *
+ * Returns: (transfer full): a new #GstyleColorWidget.
+ *
+ */
+GstyleColorWidget *
+gstyle_color_widget_copy (GstyleColorWidget *self)
+{
+  GstyleColorWidget *color_widget;
+  GstyleColor *color;
+  gboolean name_visible;
+  GstyleColorKind fallback_name_kind;
+  gboolean fallback_name_visible;
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR_WIDGET (self), NULL);
+
+  color = gstyle_color_widget_get_color (self);
+  name_visible = gstyle_color_widget_get_name_visible (self);
+  fallback_name_visible = gstyle_color_widget_get_name_visible (self);
+  fallback_name_kind = gstyle_color_widget_get_fallback_name_kind (self);
+
+  color_widget = gstyle_color_widget_new_with_color (color);
+  gstyle_color_widget_set_name_visible (color_widget, name_visible);
+  gstyle_color_widget_set_name_visible (color_widget, fallback_name_visible);
+  gstyle_color_widget_set_fallback_name_kind (color_widget, fallback_name_kind);
+
+  return color_widget;
+}
+
+/**
+ * gstyle_color_widget_set_color:
+ * @self: A #GstyleColorWidget
+ * @color: (nullable): A #GstyleColor or %NULL
+ *
+ * Set the #GstyleColor for the #GstyleColorWidget.
+ *
+ */
+void
+gstyle_color_widget_set_color (GstyleColorWidget *self,
+                               GstyleColor       *color)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_WIDGET (self));
+  g_return_if_fail (GSTYLE_IS_COLOR (color) || color == NULL);
+
+  if (self->color != color)
+    {
+      if (self->color != NULL)
+        {
+          gstyle_color_widget_disconnect_color (self);
+          g_clear_object (&self->color);
+        }
+
+      if (color != NULL)
+        {
+          self->color = g_object_ref (color);
+
+          g_signal_connect_object (self->color,
+                                   "notify::rgba",
+                                   G_CALLBACK (gstyle_color_widget_rgba_notify_cb),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+
+          g_signal_connect_object (self->color,
+                                   "notify::name",
+                                   G_CALLBACK (gstyle_color_widget_name_notify_cb),
+                                   self,
+                                   G_CONNECT_SWAPPED);
+
+          match_label_color (self, color);
+        }
+
+      update_label_visibility (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR]);
+    }
+}
+
+/**
+ * gstyle_color_widget_get_name_visible:
+ * @self: a #GstyleColorWidget
+ *
+ * Get the visibily of the #GstyleColorWidget name.
+ *
+ * Returns: %TRUE if the name should be visible, %FALSE otherwise.
+ *
+ */
+gboolean
+gstyle_color_widget_get_name_visible (GstyleColorWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR_WIDGET (self), FALSE);
+
+  return self->is_name_visible;
+}
+
+/**
+ * gstyle_color_widget_get_fallback_name_visible:
+ * @self: a #GstyleColorWidget
+ *
+ * Get the visibily of the #GstyleColorWidget fallback name.
+ *
+ * Returns: %TRUE if the name should be visible, %FALSE otherwise.
+ *
+ */
+gboolean
+gstyle_color_widget_get_fallback_name_visible (GstyleColorWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR_WIDGET (self), FALSE);
+
+  return self->is_fallback_name_visible;
+}
+
+/**
+ * gstyle_color_widget_get_fallback_name_kind:
+ * @self: a #GstyleColorWidget
+ *
+ * Get the kind of the #GstyleColorWidget fallback name.
+ *
+ * Returns: the #GstyleColorKind used for the fallback name.
+ *
+ */
+GstyleColorKind
+gstyle_color_widget_get_fallback_name_kind (GstyleColorWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR_WIDGET (self), GSTYLE_COLOR_KIND_UNKNOW);
+
+  return self->fallback_name_kind;
+}
+
+/**
+ * gstyle_color_widget_set_name_visible:
+ * @self: a #GstyleColorWidget
+ * @visible: name visibility
+ *
+ * Set the visibily of the #GstyleColorWidget name.
+ *
+ */
+void
+gstyle_color_widget_set_name_visible (GstyleColorWidget *self,
+                                      gboolean           visible)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_WIDGET (self));
+
+  self->is_name_visible = visible;
+  update_label_visibility (self);
+}
+
+/**
+ * gstyle_color_widget_set_fallback_name_visible:
+ * @self: a #GstyleColorWidget
+ * @visible: fallback name visibility
+ *
+ * Set the visibily of the #GstyleColorWidget fallback name.
+ *
+ */
+void
+gstyle_color_widget_set_fallback_name_visible (GstyleColorWidget *self,
+                                               gboolean           visible)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_WIDGET (self));
+
+  self->is_fallback_name_visible = visible;
+  update_label_visibility (self);
+}
+
+/**
+ * gstyle_color_widget_set_fallback_name_kind:
+ * @self: a #GstyleColorWidget
+ * @kind: a #GstyleColorKind
+ *
+ * Set the kind of the #GstyleColorWidget fallback name.
+ *
+ */
+void
+gstyle_color_widget_set_fallback_name_kind (GstyleColorWidget *self,
+                                            GstyleColorKind    kind)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR_WIDGET (self));
+
+  self->fallback_name_kind = kind;
+  update_label_visibility (self);
+}
+
+/**
+ * gstyle_color_widget_get_color:
+ * @self: a #GstyleColorWidget
+ *
+ * Get the #GstyleColor of the #GstyleColorWidget.
+ *
+ * Returns: (transfer none): The current affected #GstyleColor.
+ *
+ */
+GstyleColor *
+gstyle_color_widget_get_color (GstyleColorWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR_WIDGET (self), NULL);
+
+  return self->color;
+}
+
+/**
+ * gstyle_color_widget_new:
+ *
+ * Returns: A new #GstyleColorWidget.
+ *
+ */
+GstyleColorWidget *
+gstyle_color_widget_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_COLOR_WIDGET, NULL);
+}
+
+/**
+ * gstyle_color_widget_new_with_color:
+ * @color: A #GstyleColor
+ *
+ * Returns: A new #GstyleColorWidget.with @color affected.
+ *
+ */
+GstyleColorWidget *
+gstyle_color_widget_new_with_color (GstyleColor *color)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR (color), NULL);
+
+  return g_object_new (GSTYLE_TYPE_COLOR_WIDGET,
+                       "color", color,
+                       NULL);
+}
+
+static void
+update_container_parent_informations (GstyleColorWidget *self)
+{
+  GtkWidget *parent;
+  GtkWidget *grand_parent;
+  GtkWidget *container;
+  GstylePaletteWidget *palette_widget;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  parent = gtk_widget_get_parent (GTK_WIDGET (self));
+  if (GTK_IS_LIST_BOX_ROW (parent) || GTK_IS_FLOW_BOX_CHILD (parent))
+    {
+      grand_parent = gtk_widget_get_parent (GTK_WIDGET (parent));
+      if (grand_parent != NULL && g_str_has_prefix (gtk_widget_get_name (grand_parent), "palette"))
+        {
+          self->is_in_palette_widget = TRUE;
+          container = gtk_widget_get_ancestor (grand_parent, GSTYLE_TYPE_PALETTE_WIDGET);
+          if (container != NULL && GSTYLE_IS_PALETTE_WIDGET (container))
+            {
+              palette_widget = GSTYLE_PALETTE_WIDGET (container);
+              self->container_view_mode = gstyle_palette_widget_get_view_mode (GSTYLE_PALETTE_WIDGET 
(palette_widget));
+
+              return;
+            }
+        }
+    }
+
+  self->is_in_palette_widget = FALSE;
+}
+
+static void
+gstyle_color_widget_hierarchy_changed (GtkWidget *widget,
+                                       GtkWidget *previous_toplevel)
+{
+  GstyleColorWidget *self = (GstyleColorWidget *)widget;
+
+  g_assert (GSTYLE_IS_COLOR_WIDGET (self));
+
+  update_container_parent_informations (self);
+}
+
+static void
+gstyle_color_widget_realize (GtkWidget *widget)
+{
+  GtkAllocation allocation;
+  GdkWindow *window;
+  GdkWindowAttr attributes = {0};
+
+  g_assert (GTK_IS_WIDGET (widget));
+
+  gtk_widget_get_allocation (widget, &allocation);
+  gtk_widget_set_realized (widget, TRUE);
+
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.event_mask = gtk_widget_get_events (widget)
+                        | GDK_BUTTON_MOTION_MASK
+                        | GDK_BUTTON_PRESS_MASK
+                        | GDK_BUTTON_RELEASE_MASK
+                        | GDK_POINTER_MOTION_MASK
+                        | GDK_ENTER_NOTIFY_MASK
+                        | GDK_LEAVE_NOTIFY_MASK;
+
+  window = gdk_window_new (gtk_widget_get_parent_window (widget),
+                           &attributes, GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL);
+  gtk_widget_set_window (widget, g_object_ref (window));
+  gtk_widget_register_window (widget, window);
+  gdk_window_show (window);
+}
+
+static void
+gstyle_color_widget_finalize (GObject *object)
+{
+  GstyleColorWidget *self = GSTYLE_COLOR_WIDGET (object);
+
+  if (self->color)
+    gstyle_color_widget_disconnect_color (self);
+
+  g_clear_object (&self->dnd_window);
+  g_clear_object (&self->color);
+  g_clear_object (&self->default_provider);
+  cairo_pattern_destroy (self->checkered_pattern);
+  gtk_target_list_unref (self->target_list);
+
+  G_OBJECT_CLASS (gstyle_color_widget_parent_class)->finalize (object);
+}
+
+static void
+gstyle_color_widget_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  GstyleColorWidget *self = GSTYLE_COLOR_WIDGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_COLOR:
+      g_value_set_object (value, gstyle_color_widget_get_color (self));
+      break;
+
+    case PROP_DND_LOCK:
+      g_value_set_flags (value, self->dnd_lock);
+      break;
+
+    case PROP_NAME_VISIBLE:
+      g_value_set_boolean (value, gstyle_color_widget_get_name_visible (self));
+      break;
+
+    case PROP_FALLBACK_NAME_KIND:
+      g_value_set_enum (value, gstyle_color_widget_get_fallback_name_kind (self));
+      break;
+
+    case PROP_FALLBACK_NAME_VISIBLE:
+      g_value_set_boolean (value, gstyle_color_widget_get_fallback_name_visible (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_widget_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  GstyleColorWidget *self = GSTYLE_COLOR_WIDGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_COLOR:
+      gstyle_color_widget_set_color (self, g_value_get_object (value));
+      break;
+
+    case PROP_DND_LOCK:
+      self->dnd_lock = g_value_get_flags (value);
+      break;
+
+    case PROP_NAME_VISIBLE:
+      gstyle_color_widget_set_name_visible (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_FALLBACK_NAME_KIND:
+      gstyle_color_widget_set_fallback_name_kind (self, g_value_get_enum (value));
+      break;
+
+    case PROP_FALLBACK_NAME_VISIBLE:
+      gstyle_color_widget_set_fallback_name_visible (self, g_value_get_boolean (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_widget_class_init (GstyleColorWidgetClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkContainerClass *container_class = (GtkContainerClass*) klass;
+
+  object_class->finalize = gstyle_color_widget_finalize;
+  object_class->get_property = gstyle_color_widget_get_property;
+  object_class->set_property = gstyle_color_widget_set_property;
+
+  widget_class->size_allocate = gstyle_color_widget_size_allocate;
+  widget_class->realize = gstyle_color_widget_realize;
+  widget_class->get_preferred_width = gstyle_color_widget_get_preferred_width;
+  widget_class->get_preferred_height = gstyle_color_widget_get_preferred_height;
+  widget_class->hierarchy_changed = gstyle_color_widget_hierarchy_changed;
+  widget_class->draw = gstyle_color_widget_draw;
+
+  widget_class->drag_begin = gstyle_color_widget_on_drag_begin;
+  widget_class->drag_end = gstyle_color_widget_on_drag_end;
+  widget_class->drag_failed = gstyle_color_widget_on_drag_failed;
+  widget_class->drag_data_get = gstyle_color_widget_on_drag_data_get;
+
+  widget_class->drag_motion = gstyle_color_widget_on_drag_motion;
+  widget_class->drag_leave = gstyle_color_widget_on_drag_leave;
+  widget_class->drag_drop = gstyle_color_widget_on_drag_drop;
+  widget_class->drag_data_received = gstyle_color_widget_on_drag_data_received;
+
+  properties[PROP_COLOR] =
+    g_param_spec_object ("color",
+                         "color",
+                         "A GstyleColor to use name and color from",
+                         GSTYLE_TYPE_COLOR,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_NAME_VISIBLE] =
+    g_param_spec_boolean ("name-visible",
+                          "name-visible",
+                          "set the color name visibility",
+                          TRUE,
+                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_FALLBACK_NAME_VISIBLE] =
+    g_param_spec_boolean ("fallback-name-visible",
+                          "fallback-name-visible",
+                          "set the fallback name visibility",
+                          TRUE,
+                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_FALLBACK_NAME_KIND] =
+    g_param_spec_enum ("fallback-name-kind",
+                       "fallback-name-kind",
+                       "if there's no name, the fallback kind displayed",
+                       GSTYLE_TYPE_COLOR_KIND,
+                       GSTYLE_COLOR_KIND_ORIGINAL,
+                       (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_DND_LOCK] =
+    g_param_spec_flags ("dnd-lock",
+                        "dnd-lock",
+                        "Dnd lockability",
+                        GSTYLE_TYPE_COLOR_WIDGET_DND_LOCK_FLAGS,
+                        GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NONE,
+                        (G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_container_class_handle_border_width (container_class);
+  gtk_widget_class_set_css_name (widget_class, "gstylecolorwidget");
+}
+
+static void
+gstyle_color_widget_init (GstyleColorWidget *self)
+{
+  GtkStyleContext *context;
+  GtkWidget *widget = GTK_WIDGET (self);
+
+  static const GtkTargetEntry dnd_targets [] = {
+    {"GSTYLE_COLOR_WIDGET", GTK_TARGET_SAME_APP, 0},
+    {"application/x-color", 0, 0},
+  };
+
+  gtk_widget_set_has_window (GTK_WIDGET (self), TRUE);
+
+  self->label = GTK_LABEL (g_object_new (GTK_TYPE_LABEL,
+                                         "ellipsize", PANGO_ELLIPSIZE_END,
+                                         "visible", TRUE,
+                                         "halign", GTK_ALIGN_CENTER,
+                                         "valign", GTK_ALIGN_CENTER,
+                                         NULL));
+
+  gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->label));
+  self->is_name_visible = TRUE;
+  self->is_fallback_name_visible = TRUE;
+  self->fallback_name_kind = GSTYLE_COLOR_KIND_RGB_HEX6;
+
+  self->checkered_pattern = gstyle_utils_get_checkered_pattern ();
+
+  gtk_widget_set_valign (widget, GTK_ALIGN_FILL);
+  gtk_widget_set_halign (widget, GTK_ALIGN_FILL);
+  gtk_widget_set_hexpand (widget, TRUE);
+  gtk_widget_set_vexpand (widget, TRUE);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  self->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
+
+  self->target_list = gtk_target_list_new (dnd_targets, G_N_ELEMENTS (dnd_targets));
+  gtk_target_list_add_text_targets (self->target_list, 0);
+
+  gtk_drag_source_set (widget, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY);
+  gtk_drag_source_set_target_list (widget, self->target_list);
+
+  gtk_drag_dest_set (widget, 0, NULL, 0, GDK_ACTION_COPY);
+  gtk_drag_dest_set_target_list (widget, self->target_list);
+  gtk_drag_dest_set_track_motion (GTK_WIDGET (self), TRUE);
+
+  update_container_parent_informations (self);
+
+  self->drag_gesture = gtk_gesture_multi_press_new (widget);
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (self->drag_gesture),
+                                 GDK_BUTTON_PRIMARY);
+  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->drag_gesture),
+                                              GTK_PHASE_BUBBLE);
+
+  g_signal_connect (self->drag_gesture, "pressed",
+                    G_CALLBACK (gstyle_color_widget_multipress_gesture_pressed), widget);
+}
+
+GType
+gstyle_color_widget_dnd_lock_flags_get_type (void)
+{
+  static GType type_id;
+  static const GFlagsValue values[] = {
+    { GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NONE,  "GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NONE",  "none" },
+    { GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_KIND,  "GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_KIND",  "kind" },
+    { GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NAME,  "GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NAME",  "name" },
+    { GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALPHA, "GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALPHA", "alpha" },
+    { GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_COLOR, "GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_COLOR", "COLOR" },
+    { GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALL,   "GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALL",   "all" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_flags_register_static ("GstyleColorWidgetDndLockFlags", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/gstyle/gstyle-color-widget.h b/contrib/gstyle/gstyle-color-widget.h
new file mode 100644
index 0000000..f6a4ae6
--- /dev/null
+++ b/contrib/gstyle/gstyle-color-widget.h
@@ -0,0 +1,71 @@
+/* gstyle-color-widget.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_WIDGET_H
+#define GSTYLE_COLOR_WIDGET_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-color.h"
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NONE = 0,
+  GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_KIND = 1 << 0,
+  GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NAME = 1 << 1,
+  GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALPHA = 1 << 2,
+  GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_COLOR = 1 << 3,
+  GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALL  =
+    (GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_KIND |
+     GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_NAME |
+     GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_ALPHA |
+     GSTYLE_COLOR_WIDGET_DND_LOCK_FLAGS_COLOR)
+} GstyleColorWidgetDndLockFlags;
+
+#define GSTYLE_TYPE_COLOR_WIDGET (gstyle_color_widget_get_type())
+#define GSTYLE_TYPE_COLOR_WIDGET_DND_LOCK_FLAGS (gstyle_color_widget_dnd_lock_flags_get_type ())
+
+G_DECLARE_FINAL_TYPE (GstyleColorWidget, gstyle_color_widget, GSTYLE, COLOR_WIDGET, GtkBin)
+
+GType                  gstyle_color_widget_dnd_lock_flags_get_type   (void);
+
+GstyleColorWidget     *gstyle_color_widget_new                       (void);
+GstyleColorWidget     *gstyle_color_widget_copy                      (GstyleColorWidget *self);
+GstyleColorWidget     *gstyle_color_widget_new_with_color            (GstyleColor       *color);
+
+gboolean               gstyle_color_widget_get_name_visible          (GstyleColorWidget *self);
+gboolean               gstyle_color_widget_get_fallback_name_visible (GstyleColorWidget *self);
+GstyleColorKind        gstyle_color_widget_get_fallback_name_kind    (GstyleColorWidget *self);
+GstyleColor           *gstyle_color_widget_get_color                 (GstyleColorWidget *self);
+
+void                   gstyle_color_widget_set_fallback_name_visible (GstyleColorWidget *self,
+                                                                      gboolean           visible);
+void                   gstyle_color_widget_set_fallback_name_kind    (GstyleColorWidget *self,
+                                                                      GstyleColorKind    kind);
+void                   gstyle_color_widget_set_name_visible          (GstyleColorWidget *self,
+                                                                      gboolean           visible);
+void                   gstyle_color_widget_set_color                 (GstyleColorWidget *self,
+                                                                      GstyleColor       *color);
+
+G_END_DECLS
+
+#endif /* GSTYLE_TYPE_COLOR_WIDGET */
+
diff --git a/contrib/gstyle/gstyle-color.c b/contrib/gstyle/gstyle-color.c
new file mode 100644
index 0000000..bc35219
--- /dev/null
+++ b/contrib/gstyle/gstyle-color.c
@@ -0,0 +1,1305 @@
+/* gstyle-color.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This file 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 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-color"
+
+#include <math.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <fuzzy.h>
+
+#include "gstyle-private.h"
+#include "gstyle-colorlexer.h"
+#include "gstyle-color-convert.h"
+#include "gstyle-color-item.h"
+#include "gstyle-color-predefined.h"
+
+#include "gstyle-color.h"
+
+/**
+ * SECTION: GstyleColor
+ * @title: Color container.
+ * @short_description: A color container.
+ *
+ * The purpose of GstyleColor is having a container for
+ * color strings representation.
+ */
+
+/* TODO: add operations on the color: darker lighter mix...*/
+
+#define GET_COMP(ar, i) (g_array_index(ar, GstyleColorComponent, i))
+#define FMOD_360(val)   ({ double a; return ((a = x / 360.0)-(int)a)*y; })
+
+#define GSTYLE_COLOR_FUZZY_SEARCH_MAX_LEN 20
+
+typedef struct
+{
+  gdouble         value;
+  GstyleColorUnit unit;
+} GstyleColorComponent;
+
+struct _GstyleColor
+{
+  GObject           parent_instance;
+
+  GstyleColorKind   kind;
+  gchar            *name;
+  gint              name_index;
+  GdkRGBA           rgba;
+};
+
+typedef enum
+{
+  RANGE_PERCENT,
+  RANGE_PERCENT_OR_1MAX,
+  RANGE_PERCENT_OR_255MAX
+} ComponentRange;
+
+G_DEFINE_TYPE (GstyleColor, gstyle_color, G_TYPE_OBJECT)
+
+enum {
+  PROP_0,
+  PROP_KIND,
+  PROP_RGBA,
+  PROP_NAME,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static gchar TRUNCATE_BUF[6];
+
+/**
+ * gstyle_color_to_hsla:
+ * @self: A #GstyleColor
+ * @hue: (out): The hue component of a hsla color in range [0.0-360.0[
+ * @saturation: (out): The saturation component of a hsla color in range [0.0-100.0]
+ * @lightness: (out): The lightness component of a hsla color in range [0.0-100.0]
+ * @alpha: (out) (nullable): The alpha component of a hsla color in range [0.0-100.0]
+ *
+ * Get the hsla components from a #GstyleColor.
+ *
+ */
+void
+gstyle_color_to_hsla (GstyleColor *self,
+                      gdouble     *hue,
+                      gdouble     *saturation,
+                      gdouble     *lightness,
+                      gdouble     *alpha)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR (self));
+  g_return_if_fail (hue != NULL);
+  g_return_if_fail (saturation != NULL);
+  g_return_if_fail (lightness != NULL);
+
+  gstyle_color_convert_rgb_to_hsl (&self->rgba, hue, saturation, lightness);
+  if (alpha != NULL)
+    *alpha = self->rgba.alpha;
+}
+
+static gchar *
+truncate_trailing_zeros (gdouble number)
+{
+  gint c = g_snprintf(TRUNCATE_BUF, 6, "%.2f", number);
+
+  --c;
+  while(TRUNCATE_BUF[c] == '0')
+    c--;
+
+  if (TRUNCATE_BUF[c] == '.')
+    c--;
+
+  TRUNCATE_BUF[c + 1] = '\0';
+  return TRUNCATE_BUF;
+}
+
+/**
+ * gstyle_color_to_string:
+ * @self: A #GstyleColor
+ * @kind: The kind of representation as a #GstyleColorKind
+ *
+ * Get the string representation of a #GstyleColor.
+ *
+ * Notice that:
+ *  - asking for an HEX3 format take only the 4 left bits of each components into account.
+ *  - asking for a predefined named color format return the closest color according to
+ *    CIE2000 deltaE calculation, unless the original kind is already a named color.
+ *
+ * Returns: A null-terminated string.
+ *
+ */
+gchar *
+gstyle_color_to_string (GstyleColor     *self,
+                        GstyleColorKind  kind)
+{
+  gchar *string = NULL;
+  gchar *alpha_str = NULL;
+  gdouble hue = 0.0;
+  gdouble saturation = 0.0;
+  gdouble lightness = 0.0;
+  guint red = 0.0;
+  guint green = 0.0;
+  guint blue = 0.0;
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR (self), NULL);
+
+  if (kind == GSTYLE_COLOR_KIND_ORIGINAL)
+    kind = self->kind;
+
+  switch (kind)
+    {
+    case GSTYLE_COLOR_KIND_RGB_HEX3:
+    case GSTYLE_COLOR_KIND_RGB_HEX6:
+    case GSTYLE_COLOR_KIND_RGB:
+    case GSTYLE_COLOR_KIND_RGBA:
+      red = (guint)(0.5 + CLAMP (self->rgba.red, 0.0, 1.0) * 255.0);
+      green = (guint)(0.5 + CLAMP (self->rgba.green, 0.0, 1.0) * 255.0);
+      blue = (guint)(0.5 + CLAMP (self->rgba.blue, 0.0, 1.0) * 255.0);
+      break;
+
+    case GSTYLE_COLOR_KIND_RGB_PERCENT:
+    case GSTYLE_COLOR_KIND_RGBA_PERCENT:
+      red = (guint)(0.5 + CLAMP (self->rgba.red, 0.0, 1.0) * 100.0);
+      green = (guint)(0.5 + CLAMP (self->rgba.green, 0.0, 1.0) * 100.0);
+      blue = (guint)(0.5 + CLAMP (self->rgba.blue, 0.0, 1.0) * 100.0);
+      break;
+
+    case GSTYLE_COLOR_KIND_HSL:
+    case GSTYLE_COLOR_KIND_HSLA:
+      gstyle_color_convert_rgb_to_hsl (&self->rgba, &hue, &saturation, &lightness);
+      break;
+
+    case GSTYLE_COLOR_KIND_PREDEFINED:
+      /* TODO: get closest color using deltaE formula unless the original kind is already a named color */
+      break;
+
+    case GSTYLE_COLOR_KIND_UNKNOW:
+      g_warning ("UNKNOW #GstyleColorKind is not meant to be used for color string output");
+      return NULL;
+      break;
+
+    case GSTYLE_COLOR_KIND_ORIGINAL:
+    default:
+      g_assert_not_reached ();
+    }
+
+  /* alpha_str is a pointer to a static buffer, DO NOT free it */
+  alpha_str = truncate_trailing_zeros (self->rgba.alpha);
+
+    switch (kind)
+    {
+    case GSTYLE_COLOR_KIND_RGB_HEX3:
+      string = g_strdup_printf ("#%01X%01X%01X", red / 16, green / 16, blue / 16);
+      break;
+
+    case GSTYLE_COLOR_KIND_RGB_HEX6:
+      string = g_strdup_printf ("#%02X%02X%02X", red, green, blue);
+      break;
+
+    case GSTYLE_COLOR_KIND_RGB:
+      string = g_strdup_printf ("rgb(%i, %i, %i)", red, green, blue);
+      break;
+
+    case GSTYLE_COLOR_KIND_RGBA:
+      string = g_strdup_printf ("rgba(%i, %i, %i, %s)", red, green, blue, alpha_str);
+      break;
+
+    case GSTYLE_COLOR_KIND_RGB_PERCENT:
+      string = g_strdup_printf ("rgb(%i%%, %i%%, %i%%)", red, green, blue);
+      break;
+
+    case GSTYLE_COLOR_KIND_RGBA_PERCENT:
+      string = g_strdup_printf ("rgba(%i%%, %i%%, %i%%, %s)", red, green, blue, alpha_str);
+      break;
+
+    case GSTYLE_COLOR_KIND_HSL:
+      string = g_strdup_printf ("hsl(%i, %i%%, %i%%)", (gint)hue, (gint)(saturation + 0.5), (gint)(lightness 
+ 0.5));
+      break;
+
+    case GSTYLE_COLOR_KIND_HSLA:
+      string = g_strdup_printf ("hsla(%i, %i%%, %i%%, %s)", (gint)hue, (gint)(saturation + 0.5), 
(gint)(lightness + 0.5), alpha_str);
+      break;
+
+    case GSTYLE_COLOR_KIND_PREDEFINED:
+      if (self->name_index != -1)
+        string = g_strdup (predefined_colors_table [self->name_index].name);
+      else
+        {
+          /* TODO: get similar color using cie2000 */
+        }
+      break;
+
+    case GSTYLE_COLOR_KIND_ORIGINAL:
+    case GSTYLE_COLOR_KIND_UNKNOW:
+    default:
+      g_assert_not_reached ();
+    }
+
+  return string;
+}
+
+/**
+ * gstyle_color_get_rgba:
+ * @self: A #GstyleColor
+ *
+ * Get a #GdkRGBA object from a #GstyleColor.
+ *
+ * Returns: A #GdkRGBA.
+ *
+ */
+GdkRGBA *
+gstyle_color_get_rgba (GstyleColor *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR (self), NULL);
+
+  return gdk_rgba_copy (&self->rgba);
+}
+
+/**
+ * gstyle_color_fill_rgba:
+ * @self: A #GstyleColor
+ * @rgba: (out): the #GdkRGBA to fill in
+ *
+ * Fill a #GdkRGBA object from a #GstyleColor.
+ *
+ */
+void
+gstyle_color_fill_rgba (GstyleColor *self,
+                        GdkRGBA     *rgba)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR (self));
+  g_return_if_fail (rgba != NULL);
+
+  rgba->red = self->rgba.red;
+  rgba->green = self->rgba.green;
+  rgba->blue = self->rgba.blue;
+  rgba->alpha = self->rgba.alpha;
+}
+
+/**
+ * gstyle_color_parse:
+ * @string: A null terminated string to parse.
+ *
+ * Get an pointer array of #GstyleColorItem indicating the color and position.
+ * of color strings in the parsed string.
+ *
+ * Returns: (nullable) (element-type GstyleColorItem) (transfer full): A newly allocated
+ *   #GPtrArray containing #GstyleColorItem elements. This should be freed when
+ *   the caller is done with it using g_ptr_array_free().
+ *
+ */
+GPtrArray *
+gstyle_color_parse (const gchar *string)
+{
+  GPtrArray *ar;
+  gint n = 0;
+
+  g_return_val_if_fail (!gstyle_str_empty0 (string), NULL);
+
+  /* TODO: try doing full parsing in the parser */
+
+  /* First pass to get color strings */
+  ar = gstyle_colorlexer_parse (string);
+  while (n < ar->len)
+    {
+      g_autofree gchar *str = NULL;
+      GstyleColorItem *item;
+      GstyleColor *color;
+
+      item = g_ptr_array_index (ar, n);
+      str = g_strndup (string + gstyle_color_item_get_start (item),
+                       gstyle_color_item_get_len (item));
+
+      /* Second pass to get rgba and kind */
+      color = gstyle_color_new_from_string (NULL, str);
+      if (color != NULL)
+        {
+          gstyle_color_item_set_color (item, color);
+          g_object_unref (color);
+          ++n;
+        }
+      else
+        g_ptr_array_remove_index (ar, n);
+    }
+
+  return ar;
+}
+
+/* TODO: support for a minus in front of values */
+/* format is [0-9]*.*[0-9]* */
+static gboolean
+str_to_float (GstyleColorScanner *s,
+              gdouble            *number)
+{
+  const gchar *cursor;
+  guint left = 0;
+  guint right = 0;
+  guint precision = 0;
+
+  cursor = s->start = s->cursor;
+
+  if (g_ascii_isdigit (*cursor) || *cursor == '.')
+    {
+      while (g_ascii_isdigit (*cursor))
+        {
+          left = left * 10 + (*cursor - '0');
+          ++cursor;
+        }
+
+      if (*cursor != '.')
+        goto finish;
+      else
+        ++cursor;
+
+      while (g_ascii_isdigit (*cursor))
+        {
+          right = right * 10 + (*cursor - '0');
+          ++precision;
+          ++cursor;
+        }
+    }
+  else
+    {
+      s->cursor = cursor;
+      return FALSE;
+    }
+
+finish:
+  s->cursor = cursor;
+
+  if ((cursor - s->start) == 1 && *(s->start) == '.')
+    return FALSE;
+
+  *number = left + (right / pow (10, precision));
+  return TRUE;
+}
+
+/* parse hex_len hexadecimal digits into value */
+static gboolean
+get_hex_digit (const gchar *str,
+               guint        hex_len,
+               guint       *value)
+{
+  gint xdigit;
+  gint num = 0;
+
+  for (; hex_len > 0; --hex_len)
+    {
+      num <<= 4;
+
+      xdigit = g_ascii_xdigit_value (*str);
+      if (xdigit == -1)
+        return FALSE;
+
+      num += xdigit;
+      ++str;
+    }
+
+  *value = num;
+  return TRUE;
+}
+
+/* String need at least to start with '#'
+ * format #[0-9A-Fa-f]{3} or #[0-9A-Fa-f]{6}
+ */
+static gboolean
+_parse_hex_string (const gchar     *str,
+                   GdkRGBA         *rgba,
+                   GstyleColorKind *kind)
+{
+  gint len;
+  guint r, g, b;
+
+  g_return_val_if_fail (*str == '#', FALSE);
+
+  rgba->alpha = 1.0;
+
+  len = strlen (str);
+  if (len == 4)
+    {
+      if (get_hex_digit (str + 1, 1, &r) &&
+          get_hex_digit (str + 2, 1, &g) &&
+          get_hex_digit (str + 3, 1, &b))
+        {
+          rgba->red = (r | r << 4) / 255.0;
+          rgba->green = (g | g << 4) / 255.0;
+          rgba->blue = (b | b << 4) / 255.0;
+
+          *kind = GSTYLE_COLOR_KIND_RGB_HEX3;
+          return TRUE;
+        }
+    }
+  else if (len == 7)
+    {
+      if (get_hex_digit (str + 1, 2, &r) &&
+          get_hex_digit (str + 3, 2, &g) &&
+          get_hex_digit (str + 5, 2, &b))
+        {
+          rgba->red = r / 255.0;
+          rgba->green = g / 255.0;
+          rgba->blue = b / 255.0;
+
+          *kind = GSTYLE_COLOR_KIND_RGB_HEX6;
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+static inline gboolean
+check_char (GstyleColorScanner *s,
+            gchar               ch)
+{
+  if (*(s->cursor) == ch)
+    {
+      ++(s->cursor);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static inline gboolean
+skip_spaces (GstyleColorScanner *s)
+{
+  const gchar *cursor = s->cursor;
+  gunichar c;
+
+  while (g_unichar_isspace (c = g_utf8_get_char (cursor)))
+    cursor = g_utf8_next_char (cursor);
+
+  s->cursor = cursor;
+  return (c != '\0');
+}
+
+static GArray *
+parse_components (GstyleColorScanner *s)
+{
+  GstyleColorComponent comp;
+  gdouble value;
+  gboolean need_more = FALSE;
+  GArray *ar = g_array_sized_new (FALSE, FALSE, sizeof (GstyleColorComponent), 4);
+
+  skip_spaces (s);
+  while (str_to_float (s, &value))
+    {
+      need_more = FALSE;
+      comp.unit = GSTYLE_COLOR_UNIT_NONE;
+
+      if (check_char (s, '%'))
+        comp.unit = GSTYLE_COLOR_UNIT_PERCENT;
+
+      comp.value = value;
+      g_array_append_val (ar, comp);
+
+      skip_spaces (s);
+      if (check_char (s, ','))
+        {
+          skip_spaces (s);
+          need_more = TRUE;
+        }
+      else if (!(*s->cursor == ')'))
+        {
+          g_array_free (ar, TRUE);
+          return NULL;
+        }
+    }
+
+  if (need_more == TRUE)
+    {
+      g_array_free (ar, TRUE);
+      return NULL;
+    }
+  else
+    return ar;
+}
+
+static gboolean
+convert_component (GstyleColorComponent  comp,
+                   ComponentRange        range,
+                   gdouble              *number)
+{
+  gdouble n = comp.value;
+
+  if (comp.unit == GSTYLE_COLOR_UNIT_PERCENT)
+    {
+      *number = CLAMP (n, 0.0, 100.0) / 100.0;
+    }
+  else
+    {
+      if (range == RANGE_PERCENT)
+       return FALSE;
+
+      if (range == RANGE_PERCENT_OR_1MAX)
+        *number = CLAMP (n, 0.0, 1.0);
+      else if (range == RANGE_PERCENT_OR_255MAX)
+        *number = CLAMP (n, 0.0, 255.0) / 255.0;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+convert_hue_component (GstyleColorComponent  comp,
+                       gdouble              *hue)
+{
+  gdouble num = comp.value;
+
+  if (comp.unit == GSTYLE_COLOR_UNIT_PERCENT)
+    return FALSE;
+
+  if (num == 360.0)
+    num = 0.0;
+  else if (num > 360.0)
+    num = fmod (num, 360.0);
+  else if (num < 0.0)
+    num = fmod (num, 360.0) + 360.0;
+
+  *hue = num;
+  return TRUE;
+}
+
+/* String need at least to start with 'rgb' */
+static gboolean
+_parse_rgba_string (const gchar      *string,
+                    GdkRGBA          *rgba,
+                    GstyleColorKind  *kind)
+{
+  GstyleColorScanner s;
+  g_autoptr (GArray) ar = NULL;
+  gboolean has_alpha;
+  gboolean is_percent;
+  gboolean ret;
+
+  g_return_val_if_fail (*string == 'r' && *(string + 1) == 'g' && *(string + 2) == 'b', FALSE);
+
+  s.start = string;
+  s.cursor = string + 3;
+
+  has_alpha = check_char (&s, 'a');
+  if (check_char (&s, '(') && (ar = parse_components (&s)))
+    {
+      is_percent = (GET_COMP (ar, 0).unit == GSTYLE_COLOR_UNIT_PERCENT);
+      if ((ar->len == 3 && !has_alpha) || (ar->len == 4 && has_alpha))
+        {
+          ret = convert_component (GET_COMP (ar, 0), RANGE_PERCENT_OR_255MAX, &rgba->red) &&
+                convert_component (GET_COMP (ar, 1), RANGE_PERCENT_OR_255MAX, &rgba->green) &&
+                convert_component (GET_COMP (ar, 2), RANGE_PERCENT_OR_255MAX, &rgba->blue);
+
+          if (has_alpha)
+            {
+              ret = ret && convert_component (GET_COMP (ar, 3), RANGE_PERCENT_OR_1MAX, &rgba->alpha);
+              *kind = is_percent ? GSTYLE_COLOR_KIND_RGBA_PERCENT : GSTYLE_COLOR_KIND_RGBA;
+            }
+          else
+            {
+              rgba->alpha = 1.0;
+              *kind = is_percent ? GSTYLE_COLOR_KIND_RGB_PERCENT : GSTYLE_COLOR_KIND_RGB;
+            }
+
+          if (ret && check_char (&s, ')'))
+            return TRUE;
+        }
+    }
+
+  *kind = GSTYLE_COLOR_KIND_UNKNOW;
+
+  return FALSE;
+}
+
+/* String need at least to start with 'hsl' */
+static gboolean
+_parse_hsla_string (const gchar      *string,
+                    GdkRGBA          *rgba,
+                    GstyleColorKind  *kind)
+{
+  GstyleColorScanner s;
+  g_autoptr (GArray) ar = NULL;
+  gdouble hue;
+  gdouble saturation;
+  gdouble lightness;
+  gboolean has_alpha = FALSE;
+  gboolean ret;
+
+  g_return_val_if_fail (*string == 'h' && *(string + 1) == 's' && *(string + 2) == 'l', FALSE);
+
+  s.start = string;
+  s.cursor = string + 3;
+
+  has_alpha = check_char (&s, 'a');
+  if (check_char (&s, '(') && (ar = parse_components (&s)))
+    {
+      if ((ar->len == 3 && !has_alpha) || (ar->len == 4 && has_alpha))
+        {
+          ret = convert_hue_component (GET_COMP (ar, 0), &hue) &&
+                convert_component (GET_COMP (ar, 1), RANGE_PERCENT, &saturation) &&
+                convert_component (GET_COMP (ar, 2), RANGE_PERCENT, &lightness);
+
+          if (has_alpha)
+            {
+              ret = ret && convert_component (GET_COMP (ar, 3), RANGE_PERCENT_OR_1MAX, &rgba->alpha);
+              *kind = GSTYLE_COLOR_KIND_HSLA;
+            }
+          else
+            {
+              rgba->alpha = 1.0;
+              *kind = GSTYLE_COLOR_KIND_HSL;
+            }
+
+          if (ret && check_char (&s, ')'))
+            {
+              gstyle_color_convert_hsl_to_rgb (hue, saturation, lightness, rgba);
+              return TRUE;
+            }
+        }
+    }
+
+  *kind = GSTYLE_COLOR_KIND_UNKNOW;
+
+  return FALSE;
+}
+
+/* TODO: add a public func to init so we can control the initial starting time ? */
+static Fuzzy *
+_init_predefined_table (void)
+{
+  static Fuzzy *predefined_table;
+  NamedColor *item;
+
+  if (predefined_table == NULL)
+    {
+      predefined_table = fuzzy_new (TRUE);
+
+      fuzzy_begin_bulk_insert (predefined_table);
+      for (guint i = 0; i < G_N_ELEMENTS (predefined_colors_table); ++i)
+        {
+          item = &predefined_colors_table [i];
+          item->index = i;
+          fuzzy_insert (predefined_table, item->name, (gpointer)item);
+        }
+
+      fuzzy_end_bulk_insert (predefined_table);
+    }
+
+  return predefined_table;
+}
+
+static gboolean
+_parse_predefined_color (const gchar  *color_string,
+                         GdkRGBA      *rgba,
+                         gint         *name_index)
+{
+  g_autoptr (GArray) results = NULL;
+  NamedColor *item = NULL;
+  FuzzyMatch *match;
+  gint len;
+  Fuzzy *predefined_table = _init_predefined_table ();
+
+  results = fuzzy_match (predefined_table, color_string, 10);
+  len = results->len;
+  for (gint i = 0; i < len; ++i)
+    {
+      match = &g_array_index (results, FuzzyMatch, i);
+      if (g_strcmp0 (color_string, match->key) == 0)
+        {
+          item = match->value;
+          *name_index = (gint)(item - predefined_colors_table);
+          rgba->alpha = 1.0;
+          rgba->red = item->red /255.0;
+          rgba->green = item->green / 255.0;
+          rgba->blue = item->blue / 255.0;
+
+          return TRUE;
+        }
+    }
+
+  *name_index = -1;
+  return FALSE;
+}
+
+/**
+ * gstyle_color_fuzzy_parse_color_string:
+ * @color_string: color name to search for
+ *
+ * Returns: (transfer full) (element-type GstyleColor): A #GPtrArray of #GstyleColor for a fuzzy search.
+ */
+GPtrArray *
+gstyle_color_fuzzy_parse_color_string (const gchar *color_string)
+{
+  g_autoptr (GArray) fuzzy_results = NULL;
+  GPtrArray *results;
+  FuzzyMatch *match;
+  NamedColor *item;
+  GstyleColor *color;
+  GdkRGBA rgba;
+  gint len;
+
+  Fuzzy *predefined_table = _init_predefined_table ();
+
+  results = g_ptr_array_new_with_free_func (g_object_unref);
+  fuzzy_results = fuzzy_match (predefined_table, color_string, GSTYLE_COLOR_FUZZY_SEARCH_MAX_LEN);
+  len = MIN (GSTYLE_COLOR_FUZZY_SEARCH_MAX_LEN, fuzzy_results->len);
+  for (gint i = 0; i < len; ++i)
+    {
+      match = &g_array_index (fuzzy_results, FuzzyMatch, i);
+      item = match->value;
+      rgba.red = item->red / 255.0;
+      rgba.green = item->green / 255.0;
+      rgba.blue = item->blue / 255.0;
+      rgba.alpha = 1.0;
+
+      color = gstyle_color_new_from_rgba (g_strdup (match->key), GSTYLE_COLOR_KIND_PREDEFINED, &rgba);
+      color->name_index = item->index;
+
+      g_ptr_array_add (results, color);
+    }
+
+  return results;
+}
+
+/* TODO: add hsv/hwb colorspace */
+static gboolean
+_parse_color_string (const gchar      *color_string,
+                     GdkRGBA          *rgba,
+                     GstyleColorKind  *kind,
+                     gint             *name_index)
+{
+  gboolean ret;
+
+  g_assert (!gstyle_str_empty0 (color_string));
+  g_assert (rgba != NULL);
+
+  *name_index = -1;
+
+  if (color_string[0] == '#')
+    ret = _parse_hex_string (color_string, rgba, kind);
+  else if (g_str_has_prefix (color_string, "rgb"))
+    ret = _parse_rgba_string (color_string, rgba, kind);
+  else if (g_str_has_prefix (color_string, "hsl"))
+    ret = _parse_hsla_string (color_string, rgba, kind);
+  else
+    {
+      if ((ret = _parse_predefined_color (color_string, rgba, name_index)))
+        *kind =GSTYLE_COLOR_KIND_PREDEFINED;
+      else
+        *kind =GSTYLE_COLOR_KIND_UNKNOW;
+    }
+
+  return ret;
+}
+
+/**
+ * gstyle_color_parse_color_string:
+ * @color_string: A null-terminated color string to parse
+ * @rgba: (out): The #GdkRGBA to fill in
+ * @kind: (out): The kind of representation as a #GstyleColorKind
+ *
+ * Get a #GdkRGBA and a #GstyleColorKind from a color string.
+ * If you want to keep the args unit format,
+ * use gstyle_color_new_from_string instead.
+ *
+ * Returns: %TRUE on success, %FALSE if an error occurred.
+ *
+ */
+gboolean
+gstyle_color_parse_color_string (const gchar     *color_string,
+                                 GdkRGBA         *rgba,
+                                 GstyleColorKind *kind)
+{
+  G_GNUC_UNUSED gint name_index;
+  gboolean ret;
+
+  g_return_val_if_fail (!gstyle_str_empty0 (color_string), FALSE);
+  g_return_val_if_fail (rgba != NULL, FALSE);
+
+  ret = _parse_color_string (color_string, rgba, kind, &name_index);
+  if (*kind == GSTYLE_COLOR_KIND_UNKNOW)
+    *kind = GSTYLE_COLOR_KIND_RGB_HEX6;
+
+  return ret;
+}
+
+/**
+ * gstyle_color_fill:
+ * @src_color: Source #GstyleColor
+ * @dst_color: Destination #GstyleColor to fill with @src_color data
+ *
+ * Fill @dst_color with the rgba, name and kind of @src_color.
+ *
+ */
+void
+gstyle_color_fill (GstyleColor *src_color,
+                   GstyleColor *dst_color)
+{
+  GdkRGBA rgba;
+
+  g_assert (GSTYLE_IS_COLOR (src_color));
+  g_assert (GSTYLE_IS_COLOR (dst_color));
+
+  gstyle_color_fill_rgba (src_color, &rgba);
+  gstyle_color_set_rgba (dst_color, &rgba);
+  gstyle_color_set_name (dst_color, gstyle_color_get_name (src_color));
+  gstyle_color_set_kind (dst_color, gstyle_color_get_kind (src_color));
+  dst_color->name_index = src_color->name_index;
+}
+
+/**
+ * gstyle_color_copy:
+ * @self: A #GstyleColor
+ *
+ * A full copy of a #GstyleColor.
+ *
+ * Returns: (transfer full): A #GstyleColor.
+ *
+ */
+GstyleColor *
+gstyle_color_copy (GstyleColor *self)
+{
+  GstyleColor *color;
+  GdkRGBA rgba;
+
+  g_return_val_if_fail (GSTYLE_IS_COLOR (self), NULL);
+
+  gstyle_color_fill_rgba (self, &rgba);
+  color = g_object_new (GSTYLE_TYPE_COLOR,
+                        "name", gstyle_color_get_name (self),
+                        "kind", gstyle_color_get_kind (self),
+                        "rgba", &rgba,
+                        NULL);
+
+  color->name_index = self->name_index;
+
+  return color;
+}
+
+/**
+ * gstyle_color_new:
+ * @name: (nullable): The name of the color. Can be %NULL
+ * @kind: The kind of representation as a #GstyleColorKind
+ * @red: The red component in a [0-255] range
+ * @green: The green component in a [0-255] range
+ * @blue: The blue component in a [0-255] range
+ * @alpha: The alpha component in a [0-100] range
+ *
+ * A #GstyleColor object from #GstyleColorKind and rgba components.
+ *
+ * Returns: A #GstyleColor.
+ *
+ */
+GstyleColor *
+gstyle_color_new (const gchar     *name,
+                  GstyleColorKind  kind,
+                  guint            red,
+                  guint            green,
+                  guint            blue,
+                  guint            alpha)
+{
+  GdkRGBA rgba;
+
+  rgba.red = red / 255.0;
+  rgba.green = green / 255.0;
+  rgba.blue = blue / 255.0;
+  rgba.alpha = alpha / 100.0;
+
+  return g_object_new (GSTYLE_TYPE_COLOR,
+                       "name", name,
+                       "kind", kind,
+                       "rgba", &rgba,
+                       NULL);
+}
+
+/**
+ * gstyle_color_new_from_rgba:
+ * @name: (nullable): The name of the color. Can be %NULL
+ * @kind: The kind of representation as a #GstyleColorKind
+ * @rgba: A #GdkRGBA
+ *
+ * A #GstyleColor object from a #GstyleColorKind and a #GdkRGBA object.
+ *
+ * Returns: A #GstyleColor.
+ *
+ */
+GstyleColor *
+gstyle_color_new_from_rgba (const gchar     *name,
+                            GstyleColorKind  kind,
+                            GdkRGBA         *rgba)
+{
+  return g_object_new (GSTYLE_TYPE_COLOR,
+                       "name", name,
+                       "kind", kind,
+                       "rgba", rgba,
+                       NULL);
+}
+
+/**
+ * gstyle_color_from_hsla:
+ * @name: (nullable): The name of the color. Can be %NULL
+ * @kind: The kind of representation as a #GstyleColorKind
+ * @hue: The hue component of a hsla color in range [0.0-360.0[
+ * @saturation: The saturation component in range [0.0-1.0]
+ * @lightness: The lightness component in range [0.0-1.0]
+ * @alpha: The alpha component in range [0.0-1.0]
+ *
+ * A #GstyleColor from #GstyleColorKind and rgba components.
+ *
+ * Returns: A #GstyleColor.
+ *
+ */
+GstyleColor *
+gstyle_color_new_from_hsla (const gchar     *name,
+                            GstyleColorKind  kind,
+                            gdouble          hue,
+                            gdouble          saturation,
+                            gdouble          lightness,
+                            gdouble          alpha)
+{
+  GdkRGBA rgba;
+
+  gstyle_color_convert_hsl_to_rgb (hue, saturation, lightness, &rgba);
+  rgba.alpha = alpha;
+
+  return g_object_new (GSTYLE_TYPE_COLOR,
+                       "name", name,
+                       "kind", kind,
+                       "rgba", &rgba,
+                       NULL);
+}
+
+/**
+ * gstyle_color_new_from_string:
+ * @name: (nullable): The name of the color. Can be NULL
+ * @color_string: A null terminated string to parse
+ *
+ * A #GstyleColor object from a color string.
+ *
+ * Returns: A #GstyleColor or %NULL if the string can't be parsed.
+ *
+ */
+GstyleColor *
+gstyle_color_new_from_string (const gchar *name,
+                              const gchar *color_string)
+{
+  GstyleColor *self;
+  gint name_index;
+  GdkRGBA rgba;
+  GstyleColorKind kind;
+
+  g_return_val_if_fail (!gstyle_str_empty0 (color_string), NULL);
+
+  if (!_parse_color_string (color_string, &rgba, &kind, &name_index))
+    return NULL;
+
+  if (gstyle_str_empty0 (name))
+    name = NULL;
+
+  self = g_object_new (GSTYLE_TYPE_COLOR,
+                       "name", name,
+                       "kind", kind,
+                       "rgba", &rgba,
+                       NULL);
+
+  if (kind == GSTYLE_COLOR_KIND_PREDEFINED)
+    self->name_index = name_index;
+
+  return self;
+}
+
+/**
+ * gstyle_color_get_name:
+ * @self: A #GstyleColor
+ *
+ * Get the name of a #GstyleColor.
+ *
+ * Returns: A string own by the callee.
+ *
+ */
+const gchar *
+gstyle_color_get_name (GstyleColor *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR (self), NULL);
+
+  return self->name;
+}
+
+/**
+ * gstyle_color_set_name:
+ * @self: A #GstyleColor.
+ * @name: (nullable): A string
+ *
+ * Set the name of a #GstyleColor.
+ *
+ */
+void
+gstyle_color_set_name (GstyleColor *self,
+                       const gchar *name)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR (self));
+
+  if (g_strcmp0 (name, self->name) != 0)
+    {
+      g_free (self->name);
+      if (!gstyle_str_empty0 (name))
+        self->name = g_strdup (name);
+      else
+        self->name = NULL;
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_NAME]);
+    }
+}
+
+/**
+ * gstyle_color_get_kind:
+ * @self: A #GstyleColor
+ *
+ * Get the #GstyleColorKind of a #GstyleColor.
+ *
+ * Returns: A #GstyleColorKind.
+ *
+ */
+GstyleColorKind
+gstyle_color_get_kind (GstyleColor *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_COLOR (self), 0);
+
+  return self->kind;
+}
+
+/**
+ * gstyle_color_set_kind:
+ * @self: A #GstyleColor
+ * @kind: A #GstyleColorKind
+ *
+ * Set the #GstyleColorKind of a #GstyleColor.
+ *
+ */
+void
+gstyle_color_set_kind (GstyleColor     *self,
+                       GstyleColorKind  kind)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR (self));
+
+  if (self->kind != kind)
+    {
+      self->kind = kind;
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_KIND]);
+    }
+}
+
+/**
+ * gstyle_color_set_rgba:
+ * @self: A #GstyleColor
+ * @rgba: A #GdkRGBA
+ *
+ * Set #GstyleColor color from a #GdkRGBA.
+ *
+ */
+void
+gstyle_color_set_rgba (GstyleColor *self,
+                       GdkRGBA     *rgba)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR (self));
+  g_return_if_fail (rgba != NULL);
+
+  if (!gdk_rgba_equal (&self->rgba, &rgba))
+    {
+      self->rgba = *rgba;
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RGBA]);
+    }
+}
+
+/**
+ * gstyle_color_set_alpha:
+ * @self: A #GstyleColor
+ * @alpha: the new alpha value in [0,1] range
+ *
+ * Set the alpha value the the #GstyleColor.
+ *
+ */
+void
+gstyle_color_set_alpha (GstyleColor *self,
+                        gdouble      alpha)
+{
+  g_return_if_fail (GSTYLE_IS_COLOR (self));
+
+  if (self->rgba.alpha != alpha)
+    {
+      self->rgba.alpha = alpha;
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RGBA]);
+    }
+}
+
+static void
+gstyle_color_get_property (GObject    *object,
+                           guint       prop_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  GstyleColor *self = GSTYLE_COLOR (object);
+
+  switch (prop_id)
+    {
+    case PROP_KIND:
+      g_value_set_enum (value, self->kind);
+      break;
+
+    case PROP_RGBA:
+      g_value_set_boxed (value, &self->rgba);
+      break;
+
+    case PROP_NAME:
+      g_value_set_string (value, self->name);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_set_property (GObject      *object,
+                           guint         prop_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+  GdkRGBA *rgba;
+  GstyleColor *self = GSTYLE_COLOR (object);
+
+  switch (prop_id)
+    {
+    case PROP_KIND:
+      gstyle_color_set_kind (self, g_value_get_enum (value));
+      break;
+
+    case PROP_RGBA:
+      rgba = g_value_get_boxed (value);
+      gstyle_color_set_rgba (self, rgba);
+      break;
+
+    case PROP_NAME:
+      gstyle_color_set_name (self, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_color_finalize (GObject *object)
+{
+  GstyleColor *self = GSTYLE_COLOR (object);
+
+  g_clear_pointer (&self->name, g_free);
+
+  G_OBJECT_CLASS (gstyle_color_parent_class)->finalize (object);
+}
+
+static void
+gstyle_color_class_init (GstyleColorClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gstyle_color_finalize;
+  object_class->get_property = gstyle_color_get_property;
+  object_class->set_property = gstyle_color_set_property;
+
+  properties [PROP_KIND] =
+    g_param_spec_enum ("kind",
+                       "Kind",
+                       "The kind of color representation",
+                       GSTYLE_TYPE_COLOR_KIND,
+                       GSTYLE_COLOR_KIND_RGBA,
+                       (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_RGBA] =
+    g_param_spec_boxed ("rgba",
+                        "rgba",
+                        "Adress of an GdkRGBA color struct",
+                        GDK_TYPE_RGBA,
+                        (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_NAME] =
+    g_param_spec_string ("name",
+                         "Color name",
+                         "The name of the color.",
+                         NULL,
+                         (G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gstyle_color_init (GstyleColor *self)
+{
+  self->name_index = -1;
+}
+
+GType
+gstyle_color_kind_get_type (void)
+{
+  static GType type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_COLOR_KIND_UNKNOW, "GSTYLE_COLOR_KIND_UNKNOW", "unknow" },
+    { GSTYLE_COLOR_KIND_ORIGINAL, "GSTYLE_COLOR_KIND_ORIGINAL", "original" },
+    { GSTYLE_COLOR_KIND_RGB_HEX6, "GSTYLE_COLOR_KIND_RGB_HEX6", "rgbhex6" },
+    { GSTYLE_COLOR_KIND_RGB_HEX3, "GSTYLE_COLOR_KIND_RGB_HEX3", "rgbhex3" },
+    { GSTYLE_COLOR_KIND_RGB, "GSTYLE_COLOR_KIND_RGB", "rgb" },
+    { GSTYLE_COLOR_KIND_RGB_PERCENT, "GSTYLE_COLOR_KIND_RGB_PERCENT", "rgbpercent" },
+    { GSTYLE_COLOR_KIND_RGBA, "GSTYLE_COLOR_KIND_RGBA", "rgba" },
+    { GSTYLE_COLOR_KIND_RGBA_PERCENT, "GSTYLE_COLOR_KIND_RGBA_PERCENT", "rgbapercent" },
+    { GSTYLE_COLOR_KIND_HSL, "GSTYLE_COLOR_KIND_HSL", "hsl" },
+    { GSTYLE_COLOR_KIND_HSLA, "GSTYLE_COLOR_KIND_HSLA", "hsla" },
+    { GSTYLE_COLOR_KIND_PREDEFINED, "GSTYLE_COLOR_KIND_PREDEFINED", "predefined" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstyleColorKind", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
+
+GType
+gstyle_color_unit_get_type (void)
+{
+  static GType type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_COLOR_UNIT_NONE, "GSTYLE_COLOR_UNIT_NONE", "none" },
+    { GSTYLE_COLOR_UNIT_PERCENT, "GSTYLE_COLOR_UNIT_PERCENT", "percent" },
+    { GSTYLE_COLOR_UNIT_VALUE, "GSTYLE_COLOR_UNIT_VALUE", "value" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstyleColorUnit", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/gstyle/gstyle-color.h b/contrib/gstyle/gstyle-color.h
new file mode 100644
index 0000000..49d1bed
--- /dev/null
+++ b/contrib/gstyle/gstyle-color.h
@@ -0,0 +1,110 @@
+/* gstyle-color.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This file 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 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLOR_H
+#define GSTYLE_COLOR_H
+
+#include <glib-object.h>
+#include <gdk/gdk.h>
+
+#include "gstyle-types.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_COLOR (gstyle_color_get_type())
+#define GSTYLE_TYPE_COLOR_KIND (gstyle_color_kind_get_type())
+#define GSTYLE_TYPE_COLOR_UNIT (gstyle_color_unit_get_type())
+
+G_DECLARE_FINAL_TYPE (GstyleColor, gstyle_color, GSTYLE, COLOR, GObject)
+
+typedef enum
+{
+  GSTYLE_COLOR_KIND_UNKNOW,
+  GSTYLE_COLOR_KIND_ORIGINAL,
+  GSTYLE_COLOR_KIND_RGB_HEX6,
+  GSTYLE_COLOR_KIND_RGB_HEX3,
+  GSTYLE_COLOR_KIND_RGB,
+  GSTYLE_COLOR_KIND_RGB_PERCENT,
+  GSTYLE_COLOR_KIND_RGBA,
+  GSTYLE_COLOR_KIND_RGBA_PERCENT,
+  GSTYLE_COLOR_KIND_HSL,
+  GSTYLE_COLOR_KIND_HSLA,
+  GSTYLE_COLOR_KIND_PREDEFINED
+} GstyleColorKind;
+
+typedef enum
+{
+  GSTYLE_COLOR_UNIT_NONE,
+  GSTYLE_COLOR_UNIT_PERCENT,
+  GSTYLE_COLOR_UNIT_VALUE
+} GstyleColorUnit;
+
+GType                gstyle_color_kind_get_type               (void);
+GType                gstyle_color_unit_get_type               (void);
+
+GstyleColor         *gstyle_color_copy                        (GstyleColor      *self);
+void                 gstyle_color_fill                        (GstyleColor      *src_color,
+                                                               GstyleColor      *dst_color);
+GstyleColor         *gstyle_color_new                         (const gchar      *name,
+                                                               GstyleColorKind   kind,
+                                                               guint             red,
+                                                               guint             green,
+                                                               guint             blue,
+                                                               guint             alpha);
+GstyleColor         *gstyle_color_new_from_rgba               (const gchar      *name,
+                                                               GstyleColorKind   kind,
+                                                               GdkRGBA          *rgba);
+GstyleColor         *gstyle_color_new_from_hsla               (const gchar      *name,
+                                                               GstyleColorKind   kind,
+                                                               gdouble           hue,
+                                                               gdouble           saturation,
+                                                               gdouble           lightness,
+                                                               gdouble           alpha);
+GstyleColor         *gstyle_color_new_from_string             (const gchar      *name,
+                                                               const gchar      *color_string);
+
+/* TODO: add an async functions */
+GPtrArray           *gstyle_color_fuzzy_parse_color_string    (const gchar      *color_string);
+GPtrArray           *gstyle_color_parse                       (const gchar      *string);
+gboolean             gstyle_color_parse_color_string          (const gchar      *color_string,
+                                                               GdkRGBA          *rgba,
+                                                               GstyleColorKind  *kind);
+void                 gstyle_color_to_hsla                     (GstyleColor      *self,
+                                                               gdouble          *hue,
+                                                               gdouble          *saturation,
+                                                               gdouble          *lightness,
+                                                               gdouble          *alpha);
+gchar               *gstyle_color_to_string                   (GstyleColor      *self,
+                                                               GstyleColorKind   kind);
+GstyleColorKind      gstyle_color_get_kind                    (GstyleColor      *self);
+const gchar         *gstyle_color_get_name                    (GstyleColor      *self);
+GdkRGBA             *gstyle_color_get_rgba                    (GstyleColor      *self);
+void                 gstyle_color_set_kind                    (GstyleColor      *self,
+                                                               GstyleColorKind   kind);
+void                 gstyle_color_set_name                    (GstyleColor      *self,
+                                                               const gchar      *name);
+void                 gstyle_color_set_rgba                    (GstyleColor      *self,
+                                                               GdkRGBA          *rgba);
+void                 gstyle_color_set_alpha                   (GstyleColor      *self,
+                                                               gdouble           alpha);
+void                 gstyle_color_fill_rgba                   (GstyleColor      *self,
+                                                               GdkRGBA          *rgba);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLOR_H */
diff --git a/contrib/gstyle/gstyle-colorlexer.c b/contrib/gstyle/gstyle-colorlexer.c
new file mode 100644
index 0000000..e1db50b
--- /dev/null
+++ b/contrib/gstyle/gstyle-colorlexer.c
@@ -0,0 +1,3002 @@
+/* Generated by re2c 0.16 on Wed Jun 29 18:01:24 2016 */
+/* gstyle-colorlexer.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-colorlexer"
+
+#include <glib.h>
+
+#include "gstyle-color.h"
+#include "gstyle-color-item.h"
+#include "gstyle-types.h"
+#include "gstyle-utils.h"
+
+#include "gstyle-colorlexer.h"
+
+#define PARSE_ARRAY_INITIAL_SIZE  32
+
+#define YYCTYPE     guchar
+#define YYCURSOR    cursor
+#define YYMARKER    s->ptr
+#define YYCTXMARKER s->ptr_ctx
+
+static void
+gstyle_colorlexer_init (GstyleColorScanner *s,
+                        const gchar        *data)
+{
+  s->start = data;
+  s->cursor = data;
+}
+
+static gint
+gstyle_colorlexer_scan (GstyleColorScanner *s)
+{
+  const gchar *cursor = s->cursor;
+
+standard:
+  s->start = cursor;
+
+
+               {
+                       guchar yych;
+                       static const unsigned char yybm[] = {
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0, 128,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                               128,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                       };
+                       yych = *YYCURSOR;
+                       if (yych <= '.') {
+                               if (yych <= '!') {
+                                       if (yych <= '\t') {
+                                               if (yych <= 0x00) goto yy3;
+                                               if (yych <= 0x08) goto yy5;
+                                               goto yy7;
+                                       } else {
+                                               if (yych == ' ') goto yy7;
+                                               goto yy5;
+                                       }
+                               } else {
+                                       if (yych <= '(') {
+                                               if (yych <= '"') goto yy7;
+                                               if (yych <= '&') goto yy5;
+                                               goto yy7;
+                                       } else {
+                                               if (yych == ',') goto yy7;
+                                               goto yy5;
+                                       }
+                               }
+                       } else {
+                               if (yych <= 0xDF) {
+                                       if (yych <= ':') {
+                                               if (yych <= '/') goto yy10;
+                                               if (yych <= '9') goto yy5;
+                                               goto yy7;
+                                       } else {
+                                               if (yych <= 0x7F) goto yy5;
+                                               if (yych >= 0xC2) goto yy11;
+                                       }
+                               } else {
+                                       if (yych <= 0xF0) {
+                                               if (yych <= 0xE0) goto yy12;
+                                               if (yych <= 0xEF) goto yy13;
+                                               goto yy14;
+                                       } else {
+                                               if (yych <= 0xF3) goto yy15;
+                                               if (yych <= 0xF4) goto yy16;
+                                       }
+                               }
+                       }
+yy2:
+yy3:
+                       ++YYCURSOR;
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_EOF;}
+yy5:
+                       ++YYCURSOR;
+yy6:
+                       { goto standard; }
+yy7:
+                       ++YYCURSOR;
+                       yych = *YYCURSOR;
+                       if (yybm[0+yych] & 128) {
+                               goto yy7;
+                       }
+                       { s->start = cursor;goto color; }
+yy10:
+                       yych = *++YYCURSOR;
+                       if (yych == '*') goto yy17;
+                       goto yy6;
+yy11:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy2;
+                       if (yych <= 0xBF) goto yy5;
+                       goto yy2;
+yy12:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x9F) goto yy2;
+                       if (yych <= 0xBF) goto yy11;
+                       goto yy2;
+yy13:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy2;
+                       if (yych <= 0xBF) goto yy11;
+                       goto yy2;
+yy14:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x8F) goto yy2;
+                       if (yych <= 0xBF) goto yy13;
+                       goto yy2;
+yy15:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy2;
+                       if (yych <= 0xBF) goto yy13;
+                       goto yy2;
+yy16:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy2;
+                       if (yych <= 0x8F) goto yy13;
+                       goto yy2;
+yy17:
+                       ++YYCURSOR;
+                       { goto comment; }
+               }
+
+
+color:
+
+               {
+                       guchar yych;
+                       unsigned int yyaccept = 0;
+                       static const unsigned char yybm[] = {
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0, 128,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                               128,   0,   0,   0,   0, 128,   0,   0, 
+                                 0,   0,   0,   0, 128,   0, 128,   0, 
+                               128, 128, 128, 128, 128, 128, 128, 128, 
+                               128, 128,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                                 0,   0,   0,   0,   0,   0,   0,   0, 
+                       };
+                       yych = *YYCURSOR;
+                       if (yych <= 'o') {
+                               if (yych <= 'e') {
+                                       if (yych <= '`') {
+                                               if (yych <= 0x00) goto yy22;
+                                               if (yych == '#') goto yy26;
+                                               goto yy24;
+                                       } else {
+                                               if (yych <= 'b') {
+                                                       if (yych <= 'a') goto yy27;
+                                                       goto yy28;
+                                               } else {
+                                                       if (yych <= 'c') goto yy29;
+                                                       if (yych <= 'd') goto yy30;
+                                                       goto yy24;
+                                               }
+                                       }
+                               } else {
+                                       if (yych <= 'j') {
+                                               if (yych <= 'g') {
+                                                       if (yych <= 'f') goto yy31;
+                                                       goto yy32;
+                                               } else {
+                                                       if (yych <= 'h') goto yy33;
+                                                       if (yych <= 'i') goto yy34;
+                                                       goto yy24;
+                                               }
+                                       } else {
+                                               if (yych <= 'l') {
+                                                       if (yych <= 'k') goto yy35;
+                                                       goto yy36;
+                                               } else {
+                                                       if (yych <= 'm') goto yy37;
+                                                       if (yych <= 'n') goto yy38;
+                                                       goto yy39;
+                                               }
+                                       }
+                               }
+                       } else {
+                               if (yych <= 'x') {
+                                       if (yych <= 's') {
+                                               if (yych <= 'p') goto yy40;
+                                               if (yych <= 'q') goto yy24;
+                                               if (yych <= 'r') goto yy41;
+                                               goto yy42;
+                                       } else {
+                                               if (yych <= 'u') {
+                                                       if (yych <= 't') goto yy43;
+                                                       goto yy24;
+                                               } else {
+                                                       if (yych <= 'v') goto yy44;
+                                                       if (yych <= 'w') goto yy45;
+                                                       goto yy24;
+                                               }
+                                       }
+                               } else {
+                                       if (yych <= 0xE0) {
+                                               if (yych <= 0x7F) {
+                                                       if (yych <= 'y') goto yy46;
+                                                       goto yy24;
+                                               } else {
+                                                       if (yych <= 0xC1) goto yy21;
+                                                       if (yych <= 0xDF) goto yy47;
+                                                       goto yy48;
+                                               }
+                                       } else {
+                                               if (yych <= 0xF0) {
+                                                       if (yych <= 0xEF) goto yy49;
+                                                       goto yy50;
+                                               } else {
+                                                       if (yych <= 0xF3) goto yy51;
+                                                       if (yych <= 0xF4) goto yy52;
+                                               }
+                                       }
+                               }
+                       }
+yy21:
+                       YYCURSOR = YYMARKER;
+                       if (yyaccept == 0) {
+                               goto yy25;
+                       } else {
+                               goto yy229;
+                       }
+yy22:
+                       ++YYCURSOR;
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_EOF;}
+yy24:
+                       ++YYCURSOR;
+yy25:
+                       { goto standard; }
+yy26:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                       case 'A':
+                       case 'B':
+                       case 'C':
+                       case 'D':
+                       case 'E':
+                       case 'F':
+                       case 'e':       goto yy53;
+                       case 'a':       goto yy54;
+                       case 'b':       goto yy55;
+                       case 'c':       goto yy56;
+                       case 'd':       goto yy57;
+                       case 'f':       goto yy58;
+                       case 'g':       goto yy59;
+                       case 'h':       goto yy60;
+                       case 'i':       goto yy61;
+                       case 'k':       goto yy62;
+                       case 'l':       goto yy63;
+                       case 'm':       goto yy64;
+                       case 'n':       goto yy65;
+                       case 'o':       goto yy66;
+                       case 'p':       goto yy67;
+                       case 'r':       goto yy68;
+                       case 's':       goto yy69;
+                       case 't':       goto yy70;
+                       case 'v':       goto yy71;
+                       case 'w':       goto yy72;
+                       case 'y':       goto yy73;
+                       default:        goto yy25;
+                       }
+yy27:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'l':       goto yy74;
+                       case 'n':       goto yy75;
+                       case 'q':       goto yy76;
+                       case 'z':       goto yy77;
+                       default:        goto yy25;
+                       }
+yy28:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'e':       goto yy78;
+                       case 'i':       goto yy79;
+                       case 'l':       goto yy80;
+                       case 'r':       goto yy81;
+                       case 'u':       goto yy82;
+                       default:        goto yy25;
+                       }
+yy29:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'a':       goto yy83;
+                       case 'h':       goto yy84;
+                       case 'o':       goto yy85;
+                       case 'r':       goto yy86;
+                       case 'y':       goto yy87;
+                       default:        goto yy25;
+                       }
+yy30:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'a':       goto yy88;
+                       case 'e':       goto yy89;
+                       case 'i':       goto yy90;
+                       case 'o':       goto yy91;
+                       default:        goto yy25;
+                       }
+yy31:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'i':       goto yy92;
+                       case 'l':       goto yy93;
+                       case 'o':       goto yy94;
+                       case 'u':       goto yy95;
+                       default:        goto yy25;
+                       }
+yy32:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'a':       goto yy96;
+                       case 'h':       goto yy97;
+                       case 'o':       goto yy98;
+                       case 'r':       goto yy99;
+                       default:        goto yy25;
+                       }
+yy33:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'o') goto yy100;
+                       if (yych == 's') goto yy101;
+                       goto yy25;
+yy34:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'n') goto yy102;
+                       if (yych == 'v') goto yy103;
+                       goto yy25;
+yy35:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'h') goto yy104;
+                       goto yy25;
+yy36:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych <= 'd') {
+                               if (yych == 'a') goto yy105;
+                               goto yy25;
+                       } else {
+                               if (yych <= 'e') goto yy106;
+                               if (yych == 'i') goto yy107;
+                               goto yy25;
+                       }
+yy37:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'a':       goto yy108;
+                       case 'e':       goto yy109;
+                       case 'i':       goto yy110;
+                       case 'o':       goto yy111;
+                       default:        goto yy25;
+                       }
+yy38:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'a') goto yy112;
+                       goto yy25;
+yy39:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'l') goto yy113;
+                       if (yych == 'r') goto yy114;
+                       goto yy25;
+yy40:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'a':       goto yy115;
+                       case 'e':       goto yy116;
+                       case 'i':       goto yy117;
+                       case 'l':       goto yy118;
+                       case 'o':       goto yy119;
+                       case 'u':       goto yy120;
+                       default:        goto yy25;
+                       }
+yy41:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych <= 'f') {
+                               if (yych == 'e') goto yy121;
+                               goto yy25;
+                       } else {
+                               if (yych <= 'g') goto yy122;
+                               if (yych == 'o') goto yy123;
+                               goto yy25;
+                       }
+yy42:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'a':       goto yy124;
+                       case 'e':       goto yy125;
+                       case 'i':       goto yy126;
+                       case 'k':       goto yy127;
+                       case 'l':       goto yy128;
+                       case 'n':       goto yy129;
+                       case 'p':       goto yy130;
+                       case 't':       goto yy131;
+                       default:        goto yy25;
+                       }
+yy43:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       switch (yych) {
+                       case 'a':       goto yy132;
+                       case 'e':       goto yy133;
+                       case 'h':       goto yy134;
+                       case 'o':       goto yy135;
+                       case 'u':       goto yy136;
+                       default:        goto yy25;
+                       }
+yy44:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'i') goto yy137;
+                       goto yy25;
+yy45:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'h') goto yy138;
+                       goto yy25;
+yy46:
+                       yyaccept = 0;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych == 'e') goto yy139;
+                       goto yy25;
+yy47:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy21;
+                       if (yych <= 0xBF) goto yy24;
+                       goto yy21;
+yy48:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x9F) goto yy21;
+                       if (yych <= 0xBF) goto yy47;
+                       goto yy21;
+yy49:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy21;
+                       if (yych <= 0xBF) goto yy47;
+                       goto yy21;
+yy50:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x8F) goto yy21;
+                       if (yych <= 0xBF) goto yy49;
+                       goto yy21;
+yy51:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy21;
+                       if (yych <= 0xBF) goto yy49;
+                       goto yy21;
+yy52:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy21;
+                       if (yych <= 0x8F) goto yy49;
+                       goto yy21;
+yy53:
+                       yych = *++YYCURSOR;
+                       if (yych <= '@') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy140;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'F') goto yy140;
+                               if (yych <= '`') goto yy21;
+                               if (yych <= 'f') goto yy140;
+                               goto yy21;
+                       }
+yy54:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'k') {
+                               if (yych <= '@') {
+                                       if (yych <= '/') goto yy21;
+                                       if (yych <= '9') goto yy140;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= 'F') goto yy140;
+                                       if (yych <= '`') goto yy21;
+                                       if (yych <= 'f') goto yy140;
+                                       goto yy21;
+                               }
+                       } else {
+                               if (yych <= 'p') {
+                                       if (yych <= 'l') goto yy74;
+                                       if (yych == 'n') goto yy75;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= 'q') goto yy76;
+                                       if (yych == 'z') goto yy77;
+                                       goto yy21;
+                               }
+                       }
+yy55:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'f') {
+                               if (yych <= 'F') {
+                                       if (yych <= '/') goto yy21;
+                                       if (yych <= '9') goto yy140;
+                                       if (yych <= '@') goto yy21;
+                                       goto yy140;
+                               } else {
+                                       if (yych <= '`') goto yy21;
+                                       if (yych == 'e') goto yy141;
+                                       goto yy140;
+                               }
+                       } else {
+                               if (yych <= 'l') {
+                                       if (yych == 'i') goto yy79;
+                                       if (yych <= 'k') goto yy21;
+                                       goto yy80;
+                               } else {
+                                       if (yych <= 'r') {
+                                               if (yych <= 'q') goto yy21;
+                                               goto yy81;
+                                       } else {
+                                               if (yych == 'u') goto yy82;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy56:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'g') {
+                               if (yych <= 'F') {
+                                       if (yych <= '/') goto yy21;
+                                       if (yych <= '9') goto yy140;
+                                       if (yych <= '@') goto yy21;
+                                       goto yy140;
+                               } else {
+                                       if (yych <= '`') goto yy21;
+                                       if (yych <= 'a') goto yy142;
+                                       if (yych <= 'f') goto yy140;
+                                       goto yy21;
+                               }
+                       } else {
+                               if (yych <= 'q') {
+                                       if (yych <= 'h') goto yy84;
+                                       if (yych == 'o') goto yy85;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= 'r') goto yy86;
+                                       if (yych == 'y') goto yy87;
+                                       goto yy21;
+                               }
+                       }
+yy57:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'd') {
+                               if (yych <= '@') {
+                                       if (yych <= '/') goto yy21;
+                                       if (yych <= '9') goto yy140;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= 'F') goto yy140;
+                                       if (yych <= '`') goto yy21;
+                                       if (yych <= 'a') goto yy143;
+                                       goto yy140;
+                               }
+                       } else {
+                               if (yych <= 'h') {
+                                       if (yych <= 'e') goto yy144;
+                                       if (yych <= 'f') goto yy140;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= 'i') goto yy90;
+                                       if (yych == 'o') goto yy91;
+                                       goto yy21;
+                               }
+                       }
+yy58:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'h') {
+                               if (yych <= '@') {
+                                       if (yych <= '/') goto yy21;
+                                       if (yych <= '9') goto yy140;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= 'F') goto yy140;
+                                       if (yych <= '`') goto yy21;
+                                       if (yych <= 'f') goto yy140;
+                                       goto yy21;
+                               }
+                       } else {
+                               if (yych <= 'n') {
+                                       if (yych <= 'i') goto yy92;
+                                       if (yych == 'l') goto yy93;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= 'o') goto yy94;
+                                       if (yych == 'u') goto yy95;
+                                       goto yy21;
+                               }
+                       }
+yy59:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'a':       goto yy96;
+                       case 'h':       goto yy97;
+                       case 'o':       goto yy98;
+                       case 'r':       goto yy99;
+                       default:        goto yy21;
+                       }
+yy60:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy100;
+                       if (yych == 's') goto yy101;
+                       goto yy21;
+yy61:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy102;
+                       if (yych == 'v') goto yy103;
+                       goto yy21;
+yy62:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy104;
+                       goto yy21;
+yy63:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'd') {
+                               if (yych == 'a') goto yy105;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'e') goto yy106;
+                               if (yych == 'i') goto yy107;
+                               goto yy21;
+                       }
+yy64:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'a':       goto yy108;
+                       case 'e':       goto yy109;
+                       case 'i':       goto yy110;
+                       case 'o':       goto yy111;
+                       default:        goto yy21;
+                       }
+yy65:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy112;
+                       goto yy21;
+yy66:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy113;
+                       if (yych == 'r') goto yy114;
+                       goto yy21;
+yy67:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'a':       goto yy115;
+                       case 'e':       goto yy116;
+                       case 'i':       goto yy117;
+                       case 'l':       goto yy118;
+                       case 'o':       goto yy119;
+                       case 'u':       goto yy120;
+                       default:        goto yy21;
+                       }
+yy68:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'f') {
+                               if (yych == 'e') goto yy121;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'g') goto yy122;
+                               if (yych == 'o') goto yy123;
+                               goto yy21;
+                       }
+yy69:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'a':       goto yy124;
+                       case 'e':       goto yy125;
+                       case 'i':       goto yy126;
+                       case 'k':       goto yy127;
+                       case 'l':       goto yy128;
+                       case 'n':       goto yy129;
+                       case 'p':       goto yy130;
+                       case 't':       goto yy131;
+                       default:        goto yy21;
+                       }
+yy70:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'a':       goto yy132;
+                       case 'e':       goto yy133;
+                       case 'h':       goto yy134;
+                       case 'o':       goto yy135;
+                       case 'u':       goto yy136;
+                       default:        goto yy21;
+                       }
+yy71:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy137;
+                       goto yy21;
+yy72:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy138;
+                       goto yy21;
+yy73:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy139;
+                       goto yy21;
+yy74:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy145;
+                       goto yy21;
+yy75:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy146;
+                       goto yy21;
+yy76:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy147;
+                       goto yy21;
+yy77:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy148;
+                       goto yy21;
+yy78:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy149;
+                       goto yy21;
+yy79:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy150;
+                       goto yy21;
+yy80:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy151;
+                       if (yych == 'u') goto yy152;
+                       goto yy21;
+yy81:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy153;
+                       goto yy21;
+yy82:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy154;
+                       goto yy21;
+yy83:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy155;
+                       goto yy21;
+yy84:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy156;
+                       if (yych == 'o') goto yy157;
+                       goto yy21;
+yy85:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy158;
+                       goto yy21;
+yy86:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy159;
+                       goto yy21;
+yy87:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy132;
+                       goto yy21;
+yy88:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy160;
+                       goto yy21;
+yy89:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy161;
+                       goto yy21;
+yy90:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy162;
+                       goto yy21;
+yy91:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy163;
+                       goto yy21;
+yy92:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy164;
+                       goto yy21;
+yy93:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy165;
+                       goto yy21;
+yy94:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy166;
+                       goto yy21;
+yy95:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy167;
+                       goto yy21;
+yy96:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy168;
+                       goto yy21;
+yy97:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy169;
+                       goto yy21;
+yy98:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy170;
+                       goto yy21;
+yy99:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy171;
+                       if (yych == 'e') goto yy172;
+                       goto yy21;
+yy100:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy173;
+                       if (yych == 't') goto yy174;
+                       goto yy21;
+yy101:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy175;
+                       goto yy21;
+yy102:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy176;
+                       goto yy21;
+yy103:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy177;
+                       goto yy21;
+yy104:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy178;
+                       goto yy21;
+yy105:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'u') goto yy21;
+                       if (yych <= 'v') goto yy179;
+                       if (yych <= 'w') goto yy180;
+                       goto yy21;
+yy106:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy181;
+                       goto yy21;
+yy107:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'l') {
+                               if (yych == 'g') goto yy182;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'm') goto yy183;
+                               if (yych <= 'n') goto yy184;
+                               goto yy21;
+                       }
+yy108:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy185;
+                       if (yych == 'r') goto yy186;
+                       goto yy21;
+yy109:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy187;
+                       goto yy21;
+yy110:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'm') {
+                               if (yych == 'd') goto yy188;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'n') goto yy189;
+                               if (yych == 's') goto yy190;
+                               goto yy21;
+                       }
+yy111:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy191;
+                       goto yy21;
+yy112:
+                       yych = *++YYCURSOR;
+                       if (yych == 'v') goto yy192;
+                       goto yy21;
+yy113:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy193;
+                       if (yych == 'i') goto yy194;
+                       goto yy21;
+yy114:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy195;
+                       if (yych == 'c') goto yy196;
+                       goto yy21;
+yy115:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy197;
+                       if (yych == 'p') goto yy198;
+                       goto yy21;
+yy116:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy199;
+                       if (yych == 'r') goto yy200;
+                       goto yy21;
+yy117:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy201;
+                       goto yy21;
+yy118:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy202;
+                       goto yy21;
+yy119:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy203;
+                       goto yy21;
+yy120:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy204;
+                       goto yy21;
+yy121:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy205;
+                       goto yy21;
+yy122:
+                       yych = *++YYCURSOR;
+                       if (yych == 'b') goto yy206;
+                       goto yy21;
+yy123:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy207;
+                       if (yych == 'y') goto yy208;
+                       goto yy21;
+yy124:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'k') {
+                               if (yych == 'd') goto yy209;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'l') goto yy210;
+                               if (yych == 'n') goto yy211;
+                               goto yy21;
+                       }
+yy125:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy212;
+                       goto yy21;
+yy126:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy213;
+                       if (yych == 'l') goto yy214;
+                       goto yy21;
+yy127:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy215;
+                       goto yy21;
+yy128:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy216;
+                       goto yy21;
+yy129:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy217;
+                       goto yy21;
+yy130:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy218;
+                       goto yy21;
+yy131:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy219;
+                       goto yy21;
+yy132:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy205;
+                       goto yy21;
+yy133:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy220;
+                       goto yy21;
+yy134:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy221;
+                       goto yy21;
+yy135:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy222;
+                       goto yy21;
+yy136:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy223;
+                       goto yy21;
+yy137:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy224;
+                       goto yy21;
+yy138:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy225;
+                       if (yych == 'i') goto yy226;
+                       goto yy21;
+yy139:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy227;
+                       goto yy21;
+yy140:
+                       yych = *++YYCURSOR;
+                       if (yych <= '@') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy228;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'F') goto yy228;
+                               if (yych <= '`') goto yy21;
+                               if (yych <= 'f') goto yy228;
+                               goto yy21;
+                       }
+yy141:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'F') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy228;
+                               if (yych <= '@') goto yy21;
+                               goto yy228;
+                       } else {
+                               if (yych <= 'f') {
+                                       if (yych <= '`') goto yy21;
+                                       goto yy228;
+                               } else {
+                                       if (yych == 'i') goto yy149;
+                                       goto yy21;
+                               }
+                       }
+yy142:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'F') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy228;
+                               if (yych <= '@') goto yy21;
+                               goto yy228;
+                       } else {
+                               if (yych <= 'c') {
+                                       if (yych <= '`') goto yy21;
+                                       goto yy228;
+                               } else {
+                                       if (yych <= 'd') goto yy230;
+                                       if (yych <= 'f') goto yy228;
+                                       goto yy21;
+                               }
+                       }
+yy143:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'F') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy228;
+                               if (yych <= '@') goto yy21;
+                               goto yy228;
+                       } else {
+                               if (yych <= 'f') {
+                                       if (yych <= '`') goto yy21;
+                                       goto yy228;
+                               } else {
+                                       if (yych == 'r') goto yy160;
+                                       goto yy21;
+                               }
+                       }
+yy144:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'F') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy228;
+                               if (yych <= '@') goto yy21;
+                               goto yy228;
+                       } else {
+                               if (yych <= 'd') {
+                                       if (yych <= '`') goto yy21;
+                                       goto yy228;
+                               } else {
+                                       if (yych <= 'e') goto yy231;
+                                       if (yych <= 'f') goto yy228;
+                                       goto yy21;
+                               }
+                       }
+yy145:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy232;
+                       goto yy21;
+yy146:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy233;
+                       goto yy21;
+yy147:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy234;
+                       goto yy21;
+yy148:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy235;
+                       goto yy21;
+yy149:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy235;
+                       goto yy21;
+yy150:
+                       yych = *++YYCURSOR;
+                       if (yych == 'q') goto yy236;
+                       goto yy21;
+yy151:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy201;
+                       if (yych == 'n') goto yy237;
+                       goto yy21;
+yy152:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy238;
+                       goto yy21;
+yy153:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy132;
+                       goto yy21;
+yy154:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy239;
+                       goto yy21;
+yy155:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy240;
+                       goto yy21;
+yy156:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy241;
+                       goto yy21;
+yy157:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy242;
+                       goto yy21;
+yy158:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy220;
+                       if (yych == 'n') goto yy243;
+                       goto yy21;
+yy159:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy244;
+                       goto yy21;
+yy160:
+                       yych = *++YYCURSOR;
+                       if (yych == 'k') goto yy245;
+                       goto yy21;
+yy161:
+                       yych = *++YYCURSOR;
+                       if (yych == 'p') goto yy246;
+                       goto yy21;
+yy162:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy247;
+                       goto yy21;
+yy163:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy248;
+                       goto yy21;
+yy164:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy249;
+                       goto yy21;
+yy165:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy250;
+                       goto yy21;
+yy166:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy251;
+                       goto yy21;
+yy167:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy252;
+                       goto yy21;
+yy168:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy253;
+                       goto yy21;
+yy169:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy254;
+                       goto yy21;
+yy170:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy255;
+                       goto yy21;
+yy171:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy205;
+                       goto yy21;
+yy172:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy256;
+                       if (yych == 'y') goto yy205;
+                       goto yy21;
+yy173:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy257;
+                       goto yy21;
+yy174:
+                       yych = *++YYCURSOR;
+                       if (yych == 'p') goto yy258;
+                       goto yy21;
+yy175:
+                       yych = *++YYCURSOR;
+                       if (yych == '(') goto yy259;
+                       if (yych == 'a') goto yy260;
+                       goto yy21;
+yy176:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy261;
+                       goto yy21;
+yy177:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy171;
+                       goto yy21;
+yy178:
+                       yych = *++YYCURSOR;
+                       if (yych == 'k') goto yy262;
+                       goto yy21;
+yy179:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy263;
+                       goto yy21;
+yy180:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy264;
+                       goto yy21;
+yy181:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy265;
+                       goto yy21;
+yy182:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy266;
+                       goto yy21;
+yy183:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy267;
+                       goto yy21;
+yy184:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy132;
+                       goto yy21;
+yy185:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy268;
+                       goto yy21;
+yy186:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy269;
+                       goto yy21;
+yy187:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy270;
+                       goto yy21;
+yy188:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy271;
+                       goto yy21;
+yy189:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy272;
+                       goto yy21;
+yy190:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy273;
+                       goto yy21;
+yy191:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy274;
+                       goto yy21;
+yy192:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy275;
+                       if (yych == 'y') goto yy205;
+                       goto yy21;
+yy193:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy276;
+                       goto yy21;
+yy194:
+                       yych = *++YYCURSOR;
+                       if (yych == 'v') goto yy277;
+                       goto yy21;
+yy195:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy278;
+                       goto yy21;
+yy196:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy279;
+                       goto yy21;
+yy197:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy280;
+                       goto yy21;
+yy198:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy281;
+                       goto yy21;
+yy199:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy282;
+                       goto yy21;
+yy200:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy205;
+                       goto yy21;
+yy201:
+                       yych = *++YYCURSOR;
+                       if (yych == 'k') goto yy205;
+                       goto yy21;
+yy202:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy205;
+                       goto yy21;
+yy203:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy248;
+                       goto yy21;
+yy204:
+                       yych = *++YYCURSOR;
+                       if (yych == 'p') goto yy283;
+                       goto yy21;
+yy205:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '&') {
+                               if (yych <= 0x1F) {
+                                       if (yych == '\t') goto yy284;
+                                       goto yy21;
+                               } else {
+                                       if (yych == '!') goto yy21;
+                                       if (yych <= '"') goto yy284;
+                                       goto yy21;
+                               }
+                       } else {
+                               if (yych <= '+') {
+                                       if (yych == '(') goto yy21;
+                                       if (yych <= ')') goto yy284;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= ',') goto yy284;
+                                       if (yych == ';') goto yy284;
+                                       goto yy21;
+                               }
+                       }
+yy206:
+                       yych = *++YYCURSOR;
+                       if (yych == '(') goto yy286;
+                       if (yych == 'a') goto yy287;
+                       goto yy21;
+yy207:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy288;
+                       goto yy21;
+yy208:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy289;
+                       goto yy21;
+yy209:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy290;
+                       goto yy21;
+yy210:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy269;
+                       goto yy21;
+yy211:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy207;
+                       goto yy21;
+yy212:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy291;
+                       if (yych == 's') goto yy292;
+                       goto yy21;
+yy213:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy293;
+                       goto yy21;
+yy214:
+                       yych = *++YYCURSOR;
+                       if (yych == 'v') goto yy294;
+                       goto yy21;
+yy215:
+                       yych = *++YYCURSOR;
+                       if (yych == 'b') goto yy295;
+                       goto yy21;
+yy216:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy296;
+                       goto yy21;
+yy217:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy205;
+                       goto yy21;
+yy218:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy297;
+                       goto yy21;
+yy219:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy289;
+                       goto yy21;
+yy220:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy205;
+                       goto yy21;
+yy221:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy298;
+                       goto yy21;
+yy222:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy299;
+                       goto yy21;
+yy223:
+                       yych = *++YYCURSOR;
+                       if (yych == 'q') goto yy300;
+                       goto yy21;
+yy224:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy301;
+                       goto yy21;
+yy225:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy302;
+                       goto yy21;
+yy226:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy303;
+                       goto yy21;
+yy227:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy304;
+                       goto yy21;
+yy228:
+                       yyaccept = 1;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych <= '@') {
+                               if (yych <= '/') goto yy229;
+                               if (yych <= '9') goto yy305;
+                       } else {
+                               if (yych <= 'F') goto yy305;
+                               if (yych <= '`') goto yy229;
+                               if (yych <= 'f') goto yy305;
+                       }
+yy229:
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_HEX;}
+yy230:
+                       yyaccept = 1;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych <= 'F') {
+                               if (yych <= '/') goto yy229;
+                               if (yych <= '9') goto yy305;
+                               if (yych <= '@') goto yy229;
+                               goto yy305;
+                       } else {
+                               if (yych <= 'd') {
+                                       if (yych <= '`') goto yy229;
+                                       goto yy305;
+                               } else {
+                                       if (yych <= 'e') goto yy306;
+                                       if (yych <= 'f') goto yy305;
+                                       goto yy229;
+                               }
+                       }
+yy231:
+                       yyaccept = 1;
+                       yych = *(YYMARKER = ++YYCURSOR);
+                       if (yych <= 'F') {
+                               if (yych <= '/') goto yy229;
+                               if (yych <= '9') goto yy305;
+                               if (yych <= '@') goto yy229;
+                               goto yy305;
+                       } else {
+                               if (yych <= 'f') {
+                                       if (yych <= '`') goto yy229;
+                                       goto yy305;
+                               } else {
+                                       if (yych == 'p') goto yy246;
+                                       goto yy229;
+                               }
+                       }
+yy232:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy215;
+                       goto yy21;
+yy233:
+                       yych = *++YYCURSOR;
+                       if (yych == 'q') goto yy307;
+                       goto yy21;
+yy234:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'm') goto yy308;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy235:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy205;
+                       goto yy21;
+yy236:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy235;
+                       goto yy21;
+yy237:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy309;
+                       goto yy21;
+yy238:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'v') goto yy71;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy239:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy310;
+                       goto yy21;
+yy240:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy215;
+                       goto yy21;
+yy241:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy311;
+                       goto yy21;
+yy242:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy312;
+                       goto yy21;
+yy243:
+                       yych = *++YYCURSOR;
+                       if (yych == 'f') goto yy313;
+                       if (yych == 's') goto yy314;
+                       goto yy21;
+yy244:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy269;
+                       goto yy21;
+yy245:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'b':       goto yy295;
+                       case 'c':       goto yy315;
+                       case 'g':       goto yy316;
+                       case 'k':       goto yy62;
+                       case 'm':       goto yy317;
+                       case 'o':       goto yy318;
+                       case 'r':       goto yy319;
+                       case 's':       goto yy320;
+                       case 't':       goto yy321;
+                       case 'v':       goto yy71;
+                       default:        goto yy21;
+                       }
+yy246:
+                       yych = *++YYCURSOR;
+                       if (yych == 'p') goto yy258;
+                       if (yych == 's') goto yy322;
+                       goto yy21;
+yy247:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy323;
+                       goto yy21;
+yy248:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy324;
+                       goto yy21;
+yy249:
+                       yych = *++YYCURSOR;
+                       if (yych == 'b') goto yy325;
+                       goto yy21;
+yy250:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy326;
+                       goto yy21;
+yy251:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy327;
+                       goto yy21;
+yy252:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy328;
+                       goto yy21;
+yy253:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy329;
+                       goto yy21;
+yy254:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy330;
+                       goto yy21;
+yy255:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'e') goto yy331;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy256:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy332;
+                       goto yy21;
+yy257:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy333;
+                       goto yy21;
+yy258:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy117;
+                       goto yy21;
+yy259:
+                       yych = *++YYCURSOR;
+                       if (yych == ')') goto yy21;
+                       goto yy335;
+yy260:
+                       yych = *++YYCURSOR;
+                       if (yych == '(') goto yy259;
+                       goto yy21;
+yy261:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy336;
+                       if (yych == 'g') goto yy337;
+                       goto yy21;
+yy262:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy205;
+                       goto yy21;
+yy263:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy338;
+                       goto yy21;
+yy264:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy291;
+                       goto yy21;
+yy265:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy339;
+                       goto yy21;
+yy266:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy340;
+                       goto yy21;
+yy267:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'g') goto yy291;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy268:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy341;
+                       goto yy21;
+yy269:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy132;
+                       goto yy21;
+yy270:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy342;
+                       goto yy21;
+yy271:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy343;
+                       goto yy21;
+yy272:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy344;
+                       goto yy21;
+yy273:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy345;
+                       goto yy21;
+yy274:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy346;
+                       goto yy21;
+yy275:
+                       yych = *++YYCURSOR;
+                       if (yych == 'j') goto yy347;
+                       goto yy21;
+yy276:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy348;
+                       goto yy21;
+yy277:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy349;
+                       goto yy21;
+yy278:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy350;
+                       goto yy21;
+yy279:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy121;
+                       goto yy21;
+yy280:
+                       yych = *++YYCURSOR;
+                       if (yych <= 's') {
+                               if (yych == 'g') goto yy351;
+                               goto yy21;
+                       } else {
+                               if (yych <= 't') goto yy321;
+                               if (yych == 'v') goto yy352;
+                               goto yy21;
+                       }
+yy281:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy353;
+                       goto yy21;
+yy282:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy354;
+                       goto yy21;
+yy283:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy235;
+                       goto yy21;
+yy284:
+                       ++YYCURSOR;
+                       YYCURSOR = YYCTXMARKER;
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_NAMED;}
+yy286:
+                       yych = *++YYCURSOR;
+                       if (yych == ')') goto yy21;
+                       goto yy356;
+yy287:
+                       yych = *++YYCURSOR;
+                       if (yych == '(') goto yy286;
+                       goto yy21;
+yy288:
+                       yych = *++YYCURSOR;
+                       if (yych == 'b') goto yy357;
+                       goto yy21;
+yy289:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy215;
+                       goto yy21;
+yy290:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy358;
+                       goto yy21;
+yy291:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy359;
+                       goto yy21;
+yy292:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy360;
+                       goto yy21;
+yy293:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy361;
+                       goto yy21;
+yy294:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy362;
+                       goto yy21;
+yy295:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy236;
+                       goto yy21;
+yy296:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy363;
+                       goto yy21;
+yy297:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy364;
+                       goto yy21;
+yy298:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy283;
+                       goto yy21;
+yy299:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy337;
+                       goto yy21;
+yy300:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy365;
+                       goto yy21;
+yy301:
+                       yych = *++YYCURSOR;
+                       if (yych != 'e') goto yy21;
+yy302:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy205;
+                       goto yy21;
+yy303:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy366;
+                       goto yy21;
+yy304:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy367;
+                       goto yy21;
+yy305:
+                       yych = *++YYCURSOR;
+                       if (yych <= '@') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy368;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'F') goto yy368;
+                               if (yych <= '`') goto yy21;
+                               if (yych <= 'f') goto yy368;
+                               goto yy21;
+                       }
+yy306:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'F') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy368;
+                               if (yych <= '@') goto yy21;
+                               goto yy368;
+                       } else {
+                               if (yych <= 'f') {
+                                       if (yych <= '`') goto yy21;
+                                       goto yy368;
+                               } else {
+                                       if (yych == 't') goto yy215;
+                                       goto yy21;
+                               }
+                       }
+yy307:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy369;
+                       goto yy21;
+yy308:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy370;
+                       goto yy21;
+yy309:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy371;
+                       goto yy21;
+yy310:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy372;
+                       goto yy21;
+yy311:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy373;
+                       goto yy21;
+yy312:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy374;
+                       goto yy21;
+yy313:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy375;
+                       goto yy21;
+yy314:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy376;
+                       goto yy21;
+yy315:
+                       yych = *++YYCURSOR;
+                       if (yych == 'y') goto yy87;
+                       goto yy21;
+yy316:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy377;
+                       if (yych == 'r') goto yy378;
+                       goto yy21;
+yy317:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy379;
+                       goto yy21;
+yy318:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy380;
+                       if (yych == 'r') goto yy381;
+                       goto yy21;
+yy319:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy121;
+                       goto yy21;
+yy320:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'd') {
+                               if (yych == 'a') goto yy382;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'e') goto yy383;
+                               if (yych == 'l') goto yy128;
+                               goto yy21;
+                       }
+yy321:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy136;
+                       goto yy21;
+yy322:
+                       yych = *++YYCURSOR;
+                       if (yych == 'k') goto yy127;
+                       goto yy21;
+yy323:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy171;
+                       if (yych == 'e') goto yy171;
+                       goto yy21;
+yy324:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy215;
+                       goto yy21;
+yy325:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy384;
+                       goto yy21;
+yy326:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy330;
+                       goto yy21;
+yy327:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy264;
+                       goto yy21;
+yy328:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy361;
+                       goto yy21;
+yy329:
+                       yych = *++YYCURSOR;
+                       if (yych == 'b') goto yy385;
+                       goto yy21;
+yy330:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy386;
+                       goto yy21;
+yy331:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy387;
+                       goto yy21;
+yy332:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'y') goto yy388;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy333:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy389;
+                       goto yy21;
+yy334:
+                       ++YYCURSOR;
+                       yych = *YYCURSOR;
+yy335:
+                       if (yybm[0+yych] & 128) {
+                               goto yy334;
+                       }
+                       if (yych == ')') goto yy390;
+                       goto yy21;
+yy336:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy392;
+                       goto yy21;
+yy337:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy205;
+                       goto yy21;
+yy338:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy393;
+                       goto yy21;
+yy339:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy394;
+                       goto yy21;
+yy340:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'b':       goto yy295;
+                       case 'c':       goto yy395;
+                       case 'g':       goto yy396;
+                       case 'p':       goto yy258;
+                       case 's':       goto yy397;
+                       case 'y':       goto yy388;
+                       default:        goto yy21;
+                       }
+yy341:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy361;
+                       goto yy21;
+yy342:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy398;
+                       goto yy21;
+yy343:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy399;
+                       goto yy21;
+yy344:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy400;
+                       goto yy21;
+yy345:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy401;
+                       goto yy21;
+yy346:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy402;
+                       goto yy21;
+yy347:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy330;
+                       goto yy21;
+yy348:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy235;
+                       goto yy21;
+yy349:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'd') goto yy403;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy350:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy404;
+                       goto yy21;
+yy351:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy377;
+                       if (yych == 'r') goto yy359;
+                       goto yy21;
+yy352:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy405;
+                       goto yy21;
+yy353:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy406;
+                       goto yy21;
+yy354:
+                       yych = *++YYCURSOR;
+                       if (yych == 'p') goto yy407;
+                       goto yy21;
+yy355:
+                       ++YYCURSOR;
+                       yych = *YYCURSOR;
+yy356:
+                       if (yych <= '(') {
+                               if (yych <= 0x1F) {
+                                       if (yych == '\t') goto yy355;
+                                       goto yy21;
+                               } else {
+                                       if (yych <= ' ') goto yy355;
+                                       if (yych == '%') goto yy355;
+                                       goto yy21;
+                               }
+                       } else {
+                               if (yych <= '-') {
+                                       if (yych <= ')') goto yy408;
+                                       if (yych == ',') goto yy355;
+                                       goto yy21;
+                               } else {
+                                       if (yych == '/') goto yy21;
+                                       if (yych <= '9') goto yy355;
+                                       goto yy21;
+                               }
+                       }
+yy357:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy81;
+                       goto yy21;
+yy358:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy288;
+                       goto yy21;
+yy359:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy184;
+                       goto yy21;
+yy360:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy410;
+                       goto yy21;
+yy361:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy205;
+                       goto yy21;
+yy362:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy205;
+                       goto yy21;
+yy363:
+                       yych = *++YYCURSOR;
+                       if (yych == 'b') goto yy295;
+                       if (yych == 'g') goto yy247;
+                       goto yy21;
+yy364:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy264;
+                       goto yy21;
+yy365:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy411;
+                       goto yy21;
+yy366:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 's') goto yy412;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy367:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy267;
+                       goto yy21;
+yy368:
+                       yych = *++YYCURSOR;
+                       if (yych <= '@') {
+                               if (yych <= '/') goto yy21;
+                               if (yych <= '9') goto yy413;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'F') goto yy413;
+                               if (yych <= '`') goto yy21;
+                               if (yych <= 'f') goto yy413;
+                               goto yy21;
+                       }
+yy369:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy330;
+                       goto yy21;
+yy370:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy415;
+                       goto yy21;
+yy371:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy416;
+                       goto yy21;
+yy372:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy417;
+                       goto yy21;
+yy373:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy418;
+                       goto yy21;
+yy374:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy419;
+                       goto yy21;
+yy375:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy420;
+                       goto yy21;
+yy376:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy201;
+                       goto yy21;
+yy377:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy421;
+                       goto yy21;
+yy378:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy171;
+                       if (yych == 'e') goto yy422;
+                       goto yy21;
+yy379:
+                       yych = *++YYCURSOR;
+                       if (yych == 'g') goto yy185;
+                       goto yy21;
+yy380:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy423;
+                       goto yy21;
+yy381:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy424;
+                       if (yych == 'c') goto yy196;
+                       goto yy21;
+yy382:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy210;
+                       goto yy21;
+yy383:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy264;
+                       goto yy21;
+yy384:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy425;
+                       goto yy21;
+yy385:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy426;
+                       goto yy21;
+yy386:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy427;
+                       goto yy21;
+yy387:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy417;
+                       goto yy21;
+yy388:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy428;
+                       goto yy21;
+yy389:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy217;
+                       goto yy21;
+yy390:
+                       ++YYCURSOR;
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_HSL;}
+yy392:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy319;
+                       goto yy21;
+yy393:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy429;
+                       goto yy21;
+yy394:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy430;
+                       goto yy21;
+yy395:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy431;
+                       if (yych == 'y') goto yy87;
+                       goto yy21;
+yy396:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy432;
+                       if (yych == 'r') goto yy378;
+                       goto yy21;
+yy397:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'a':       goto yy382;
+                       case 'e':       goto yy383;
+                       case 'k':       goto yy127;
+                       case 'l':       goto yy433;
+                       case 't':       goto yy131;
+                       default:        goto yy21;
+                       }
+yy398:
+                       yych = *++YYCURSOR;
+                       switch (yych) {
+                       case 'a':       goto yy434;
+                       case 'b':       goto yy295;
+                       case 'o':       goto yy435;
+                       case 'p':       goto yy436;
+                       case 's':       goto yy437;
+                       case 't':       goto yy321;
+                       case 'v':       goto yy352;
+                       default:        goto yy21;
+                       }
+yy399:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy240;
+                       goto yy21;
+yy400:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy438;
+                       goto yy21;
+yy401:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy439;
+                       goto yy21;
+yy402:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy132;
+                       goto yy21;
+yy403:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy440;
+                       goto yy21;
+yy404:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'r') goto yy319;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy405:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy441;
+                       goto yy21;
+yy406:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy442;
+                       goto yy21;
+yy407:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy443;
+                       goto yy21;
+yy408:
+                       ++YYCURSOR;
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_RGB;}
+yy410:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy220;
+                       goto yy21;
+yy411:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy439;
+                       goto yy21;
+yy412:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy444;
+                       goto yy21;
+yy413:
+                       ++YYCURSOR;
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_HEX;}
+yy415:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy445;
+                       goto yy21;
+yy416:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy446;
+                       goto yy21;
+yy417:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy121;
+                       goto yy21;
+yy418:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy439;
+                       goto yy21;
+yy419:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy235;
+                       goto yy21;
+yy420:
+                       yych = *++YYCURSOR;
+                       if (yych == 'w') goto yy248;
+                       goto yy21;
+yy421:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy447;
+                       goto yy21;
+yy422:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy132;
+                       if (yych == 'y') goto yy205;
+                       goto yy21;
+yy423:
+                       yych = *++YYCURSOR;
+                       if (yych == 'v') goto yy448;
+                       goto yy21;
+yy424:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy149;
+                       goto yy21;
+yy425:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy201;
+                       goto yy21;
+yy426:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy337;
+                       goto yy21;
+yy427:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy419;
+                       goto yy21;
+yy428:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy449;
+                       goto yy21;
+yy429:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy450;
+                       goto yy21;
+yy430:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy451;
+                       goto yy21;
+yy431:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy133;
+                       goto yy21;
+yy432:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy452;
+                       goto yy21;
+yy433:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy453;
+                       goto yy21;
+yy434:
+                       yych = *++YYCURSOR;
+                       if (yych == 'q') goto yy454;
+                       goto yy21;
+yy435:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy455;
+                       goto yy21;
+yy436:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy120;
+                       goto yy21;
+yy437:
+                       yych = *++YYCURSOR;
+                       if (yych <= 'k') {
+                               if (yych == 'e') goto yy383;
+                               goto yy21;
+                       } else {
+                               if (yych <= 'l') goto yy456;
+                               if (yych == 'p') goto yy130;
+                               goto yy21;
+                       }
+yy438:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy202;
+                       goto yy21;
+yy439:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy235;
+                       goto yy21;
+yy440:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy457;
+                       goto yy21;
+yy441:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy458;
+                       goto yy21;
+yy442:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy459;
+                       goto yy21;
+yy443:
+                       yych = *++YYCURSOR;
+                       if (yych == 'f') goto yy460;
+                       goto yy21;
+yy444:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy461;
+                       goto yy21;
+yy445:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy235;
+                       goto yy21;
+yy446:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy462;
+                       goto yy21;
+yy447:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy331;
+                       goto yy21;
+yy448:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy264;
+                       goto yy21;
+yy449:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy129;
+                       goto yy21;
+yy450:
+                       yych = *++YYCURSOR;
+                       YYCTXMARKER = YYCURSOR;
+                       if (yych <= '\'') {
+                               if (yych <= ' ') {
+                                       if (yych == '\t') goto yy284;
+                                       if (yych <= 0x1F) goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych == '"') goto yy284;
+                                       if (yych <= '&') goto yy21;
+                                       goto yy284;
+                               }
+                       } else {
+                               if (yych <= ',') {
+                                       if (yych == ')') goto yy284;
+                                       if (yych <= '+') goto yy21;
+                                       goto yy284;
+                               } else {
+                                       if (yych <= ';') {
+                                               if (yych <= ':') goto yy21;
+                                               goto yy284;
+                                       } else {
+                                               if (yych == 'b') goto yy463;
+                                               goto yy21;
+                                       }
+                               }
+                       }
+yy451:
+                       yych = *++YYCURSOR;
+                       if (yych == 'f') goto yy464;
+                       goto yy21;
+yy452:
+                       yych = *++YYCURSOR;
+                       if (yych == 'd') goto yy465;
+                       goto yy21;
+yy453:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy466;
+                       goto yy21;
+yy454:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy467;
+                       goto yy21;
+yy455:
+                       yych = *++YYCURSOR;
+                       if (yych == 'c') goto yy196;
+                       goto yy21;
+yy456:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy468;
+                       goto yy21;
+yy457:
+                       yych = *++YYCURSOR;
+                       if (yych == 'b') goto yy205;
+                       goto yy21;
+yy458:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy469;
+                       goto yy21;
+yy459:
+                       yych = *++YYCURSOR;
+                       if (yych == 'i') goto yy470;
+                       goto yy21;
+yy460:
+                       yych = *++YYCURSOR;
+                       if (yych == 'f') goto yy205;
+                       goto yy21;
+yy461:
+                       yych = *++YYCURSOR;
+                       if (yych == 'k') goto yy235;
+                       goto yy21;
+yy462:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy471;
+                       goto yy21;
+yy463:
+                       yych = *++YYCURSOR;
+                       if (yych == 'l') goto yy472;
+                       goto yy21;
+yy464:
+                       yych = *++YYCURSOR;
+                       if (yych == 'f') goto yy269;
+                       goto yy21;
+yy465:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy473;
+                       goto yy21;
+yy466:
+                       yych = *++YYCURSOR;
+                       if (yych == 'e') goto yy162;
+                       goto yy21;
+yy467:
+                       yych = *++YYCURSOR;
+                       if (yych == 'a') goto yy474;
+                       goto yy21;
+yy468:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy232;
+                       goto yy21;
+yy469:
+                       yych = *++YYCURSOR;
+                       if (yych == 't') goto yy392;
+                       goto yy21;
+yy470:
+                       yych = *++YYCURSOR;
+                       if (yych == 'p') goto yy205;
+                       goto yy21;
+yy471:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy475;
+                       goto yy21;
+yy472:
+                       yych = *++YYCURSOR;
+                       if (yych == 'u') goto yy476;
+                       goto yy21;
+yy473:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy477;
+                       goto yy21;
+yy474:
+                       yych = *++YYCURSOR;
+                       if (yych == 'm') goto yy308;
+                       goto yy21;
+yy475:
+                       yych = *++YYCURSOR;
+                       if (yych == 'o') goto yy478;
+                       goto yy21;
+yy476:
+                       yych = *++YYCURSOR;
+                       if (yych == 's') goto yy479;
+                       goto yy21;
+yy477:
+                       yych = *++YYCURSOR;
+                       if (yych == 'r') goto yy480;
+                       goto yy21;
+yy478:
+                       yych = *++YYCURSOR;
+                       if (yych == 'n') goto yy121;
+                       goto yy21;
+yy479:
+                       yych = *++YYCURSOR;
+                       if (yych == 'h') goto yy205;
+                       goto yy21;
+yy480:
+                       yych = *++YYCURSOR;
+                       if (yych != 'o') goto yy21;
+                       yych = *++YYCURSOR;
+                       if (yych != 'd') goto yy21;
+                       ++YYCURSOR;
+                       if ((yych = *YYCURSOR) == 'y') goto yy388;
+                       goto yy21;
+               }
+
+
+comment:
+
+               {
+                       guchar yych;
+                       yych = *YYCURSOR;
+                       if (yych <= 0xDF) {
+                               if (yych <= '*') {
+                                       if (yych <= 0x00) goto yy486;
+                                       if (yych <= ')') goto yy488;
+                                       goto yy490;
+                               } else {
+                                       if (yych <= 0x7F) goto yy488;
+                                       if (yych >= 0xC2) goto yy491;
+                               }
+                       } else {
+                               if (yych <= 0xF0) {
+                                       if (yych <= 0xE0) goto yy492;
+                                       if (yych <= 0xEF) goto yy493;
+                                       goto yy494;
+                               } else {
+                                       if (yych <= 0xF3) goto yy495;
+                                       if (yych <= 0xF4) goto yy496;
+                               }
+                       }
+yy485:
+yy486:
+                       ++YYCURSOR;
+                       {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_EOF;}
+yy488:
+                       ++YYCURSOR;
+yy489:
+                       { goto comment; }
+yy490:
+                       yych = *++YYCURSOR;
+                       if (yych == '/') goto yy497;
+                       goto yy489;
+yy491:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy485;
+                       if (yych <= 0xBF) goto yy488;
+                       goto yy485;
+yy492:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x9F) goto yy485;
+                       if (yych <= 0xBF) goto yy491;
+                       goto yy485;
+yy493:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy485;
+                       if (yych <= 0xBF) goto yy491;
+                       goto yy485;
+yy494:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x8F) goto yy485;
+                       if (yych <= 0xBF) goto yy493;
+                       goto yy485;
+yy495:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy485;
+                       if (yych <= 0xBF) goto yy493;
+                       goto yy485;
+yy496:
+                       yych = *++YYCURSOR;
+                       if (yych <= 0x7F) goto yy485;
+                       if (yych <= 0x8F) goto yy493;
+                       goto yy485;
+yy497:
+                       ++YYCURSOR;
+                       { goto standard; }
+               }
+
+}
+
+/* TODO: check for " ' \t space around named */
+/**
+ * gstyle_colorlexer_parse:
+ * @data: a constant string.
+ *
+ *  Parse a string and return an array of #GstyleColorItem.
+ *
+ * Returns: (element-type GstyleColorItem) (transfer full): a #GPtrArray of #GstyleColorItem.
+ *
+ */
+GPtrArray *
+gstyle_colorlexer_parse (const gchar *data)
+{
+  GPtrArray *ar;
+  GstyleColorItem *item;
+  GstyleColorScanner s;
+  gint token;
+
+  if (gstyle_str_empty0 (data))
+    return NULL;
+
+  ar = g_ptr_array_new_full (PARSE_ARRAY_INITIAL_SIZE, (GDestroyNotify)gstyle_color_item_unref);
+  gstyle_colorlexer_init (&s, data);
+
+  while((token = gstyle_colorlexer_scan (&s)) != GSTYLE_COLOR_TOKEN_EOF)
+    {
+      if (token != GSTYLE_COLOR_TOKEN_HEX && *s.start == '#')
+        ++s.start;
+
+      item = gstyle_color_item_new (NULL, s.start - data, s.cursor - s.start);
+      g_ptr_array_add (ar, item);
+    }
+
+  return ar;
+}
diff --git a/contrib/gstyle/gstyle-colorlexer.h b/contrib/gstyle/gstyle-colorlexer.h
new file mode 100644
index 0000000..26d4f64
--- /dev/null
+++ b/contrib/gstyle/gstyle-colorlexer.h
@@ -0,0 +1,48 @@
+/* gstyle-colorlexer.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_COLORLEXER_H
+#define GSTYLE_COLORLEXER_H
+
+#include "gstyle-types.h"
+#include "gstyle-color.h"
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+  const gchar *start;
+  const gchar *cursor;
+  const gchar *ptr;
+  const gchar *ptr_ctx;
+} GstyleColorScanner;
+
+typedef enum
+{
+  GSTYLE_COLOR_TOKEN_EOF,
+  GSTYLE_COLOR_TOKEN_HEX,
+  GSTYLE_COLOR_TOKEN_RGB,
+  GSTYLE_COLOR_TOKEN_HSL,
+  GSTYLE_COLOR_TOKEN_NAMED
+} GstyleColorToken;
+
+GPtrArray       *gstyle_colorlexer_parse       (const gchar     *data);
+
+G_END_DECLS
+
+#endif /* GSTYLE_COLORLEXER_H */
diff --git a/contrib/gstyle/gstyle-colorlexer.re b/contrib/gstyle/gstyle-colorlexer.re
new file mode 100644
index 0000000..d8371c8
--- /dev/null
+++ b/contrib/gstyle/gstyle-colorlexer.re
@@ -0,0 +1,142 @@
+/* gstyle-colorlexer.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-colorlexer"
+
+#include <glib.h>
+
+#include "gstyle-color.h"
+#include "gstyle-color-item.h"
+#include "gstyle-types.h"
+#include "gstyle-utils.h"
+
+#include "gstyle-colorlexer.h"
+
+#define PARSE_ARRAY_INITIAL_SIZE  32
+
+#define YYCTYPE     guchar
+#define YYCURSOR    cursor
+#define YYMARKER    s->ptr
+#define YYCTXMARKER s->ptr_ctx
+
+static void
+gstyle_colorlexer_init (GstyleColorScanner *s,
+                        const gchar        *data)
+{
+  s->start = data;
+  s->cursor = data;
+}
+
+static gint
+gstyle_colorlexer_scan (GstyleColorScanner *s)
+{
+  const gchar *cursor = s->cursor;
+
+standard:
+  s->start = cursor;
+
+/*!re2c
+  re2c:define:YYCTYPE = guchar;
+  re2c:yyfill:enable = 0;
+  re2c:indent:top = 2;
+
+  params = [0-9., \t%];
+  hex = [0-9a-fA-F];
+  named = "aliceblue" | "antiquewhite" | "aqua" | "aquamarine" | "azure" | "beige" | "bisque" | "black"| 
"blanchedalmond" |
+          "blue" | "blueviolet" | "brown" | "burlywood" | "cadetblue" | "chartreuse" | "chocolate" | "coral" 
|
+          "cornflowerblue" | "cornsilk" | "crimson" | "cyan" | "darkblue" | "darkcyan" | "darkgoldenrod" | 
"darkgray" |
+          "darkgreen" | "darkgrey" | "darkkhaki" | "darkmagenta" | "darkolivegreen" | "darkorange" | 
"darkorchid" |
+          "darkred" | "darksalmon" | "darkseagreen" | "darkslateblue" | "darkslategray" | "darkslategrey" | 
"darkturquoise" |
+          "darkviolet" | "deeppink" | "deepskyblue" | "dimgray" | "dimgrey" | "dodgerblue" | "firebrick" | 
"floralwhite" |
+          "forestgreen" | "fuchsia" | "gainsboro" | "ghostwhite" | "gold" | "goldenrod" | "gray" | "green" | 
"greenyellow" | "grey" |
+          "honeydew" | "hotpink" | "indianred" | "indigo" | "ivory" | "khaki" | "lavender" | "lavenderblush" 
| "lawngreen" |
+          "lemonchiffon" | "lightblue" | "lightcoral" | "lightcyan" | "lightgoldenrodyellow" | "lightgray" | 
"lightgreen" | "lightgrey" |
+          "lightpink" | "lightsalmon" | "lightseagreen" | "lightskyblue" | "lightslategray" | 
"lightslategrey" | "lightsteelblue" |
+          "lightyellow" | "lime" | "limegreen" | "linen" | "magenta" | "maroon" | "mediumaquamarine" | 
"mediumblue" | "mediumorchid" |
+          "mediumpurple" | "mediumseagreen" | "mediumslateblue" | "mediumspringgreen" | "mediumturquoise" | 
"mediumvioletred" |
+          "midnightblue" | "mintcream" | "mistyrose" | "moccasin" | "navajowhite" | "navy" | "oldlace" | 
"olive" | "olivedrab" |
+          "orange" | "orangered" | "orchid" | "palegoldenrod" | "palegreen" | "paleturquoise" | 
"palevioletred" | "papayawhip" |
+          "peachpuff" | "peru" | "pink" | "plum" | "powderblue" | "purple" | "red" | "rosybrown" | 
"royalblue" | "saddlebrown" |
+          "salmon" | "sandybrown" | "seagreen" | "seashell" | "sienna" | "silver" | "skyblue" | "slateblue" 
| "slategray" |
+          "slategrey" | "snow" | "springgreen" | "steelblue" | "tan" | "teal" | "thistle" | "tomato" | 
"turquoise" | "violet" |
+          "wheat" | "white" | "whitesmoke" | "yellow" | "yellowgreen";
+
+  "/*"                              { goto comment; }
+  [ \t"',:(] [ \t]*                 { s->start = cursor;goto color; }
+
+  "\000"                            {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_EOF;}
+  [^]                               { goto standard; }
+*/
+
+color:
+/*!re2c
+
+  "#" hex{3}                        {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_HEX;}
+  "#" hex{6}                        {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_HEX;}
+  "#"? "rgb" "a"? "(" params+ ")"   {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_RGB;}
+  "#"? "hsl" "a"? "(" params+ ")"   {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_HSL;}
+  "#"? named / ["' \t,;)]           {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_NAMED;}
+
+  "\000"                            {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_EOF;}
+  [^]                               { goto standard; }
+*/
+
+comment:
+/*!re2c
+
+  "*/"                              { goto standard; }
+  "\000"                            {s->cursor = cursor; return GSTYLE_COLOR_TOKEN_EOF;}
+  [^]                               { goto comment; }
+*/
+}
+
+/* TODO: check for " ' \t space around named */
+/**
+ * gstyle_colorlexer_parse:
+ * @data: a constant string.
+ *
+ *  Parse a string and return an array of #GstyleColorItem.
+ *
+ * Returns: (element-type GstyleColorItem) (transfer full): a #GPtrArray of #GstyleColorItem.
+ *
+ */
+GPtrArray *
+gstyle_colorlexer_parse (const gchar *data)
+{
+  GPtrArray *ar;
+  GstyleColorItem *item;
+  GstyleColorScanner s;
+  gint token;
+
+  if (gstyle_str_empty0 (data))
+    return NULL;
+
+  ar = g_ptr_array_new_full (PARSE_ARRAY_INITIAL_SIZE, (GDestroyNotify)gstyle_color_item_unref);
+  gstyle_colorlexer_init (&s, data);
+
+  while((token = gstyle_colorlexer_scan (&s)) != GSTYLE_COLOR_TOKEN_EOF)
+    {
+      if (token != GSTYLE_COLOR_TOKEN_HEX && *s.start == '#')
+        ++s.start;
+
+      item = gstyle_color_item_new (NULL, s.start - data, s.cursor - s.start);
+      g_ptr_array_add (ar, item);
+    }
+
+  return ar;
+}
diff --git a/contrib/gstyle/gstyle-css-provider.c b/contrib/gstyle/gstyle-css-provider.c
new file mode 100644
index 0000000..8a108f2
--- /dev/null
+++ b/contrib/gstyle/gstyle-css-provider.c
@@ -0,0 +1,158 @@
+/* gstyle-css-provider.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-css-provider"
+
+#include "gstyle-css-provider.h"
+
+struct _GstyleCssProvider
+{
+  GtkCssProvider parent_instance;
+};
+
+G_DEFINE_TYPE (GstyleCssProvider, gstyle_css_provider, GTK_TYPE_CSS_PROVIDER)
+
+enum {
+  PROP_0,
+  N_PROPS
+};
+
+/* static GParamSpec *properties [N_PROPS]; */
+
+static GstyleCssProvider *default_provider = NULL;
+
+static void
+parsing_error (GstyleCssProvider *self,
+               GtkCssSection     *section,
+               const GError      *error,
+               GtkCssProvider    *provider)
+{
+  g_autofree gchar *uri = NULL;
+  GFile *file;
+  guint line = 0;
+  guint line_offset = 0;
+
+  g_assert (GSTYLE_IS_CSS_PROVIDER (self));
+  g_assert (GTK_IS_CSS_PROVIDER (provider));
+  g_assert (error != NULL);
+
+  if (section != NULL)
+    {
+      file = gtk_css_section_get_file (section);
+      uri = g_file_get_uri (file);
+      line = gtk_css_section_get_start_line (section);
+      line_offset = gtk_css_section_get_start_position (section);
+      g_warning ("Parsing Error: %s @ %u:%u: %s", uri, line, line_offset, error->message);
+    }
+  else
+    {
+      g_warning ("%s", error->message);
+    }
+}
+
+static void
+default_provider_weak_notify (gpointer           unused,
+                              GstyleCssProvider *provider)
+{
+  g_assert (GTK_IS_CSS_PROVIDER (provider));
+
+  g_warn_if_fail (g_atomic_pointer_compare_and_exchange (&default_provider, provider, NULL));
+}
+
+GstyleCssProvider *
+gstyle_css_provider_init_default (GdkScreen *screen)
+{
+  g_return_val_if_fail (screen != NULL, NULL);
+
+  if (default_provider == NULL)
+    {
+      default_provider = g_object_new (GSTYLE_TYPE_CSS_PROVIDER, NULL);
+      g_object_weak_ref (G_OBJECT (default_provider), (GWeakNotify)default_provider_weak_notify, NULL);
+
+      g_assert ( GSTYLE_IS_CSS_PROVIDER (default_provider));
+
+      gtk_style_context_add_provider_for_screen (screen,
+                                                 GTK_STYLE_PROVIDER (default_provider),
+                                                 GTK_STYLE_PROVIDER_PRIORITY_FALLBACK);
+      return default_provider;
+    }
+
+  g_assert ( GSTYLE_IS_CSS_PROVIDER (default_provider));
+  return g_object_ref (default_provider);
+}
+
+GstyleCssProvider *
+gstyle_css_provider_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_CSS_PROVIDER, NULL);
+}
+
+static void
+gstyle_css_provider_finalize (GObject *object)
+{
+  /* GstyleCssProvider *self = (GstyleCssProvider *)object; */
+
+  G_OBJECT_CLASS (gstyle_css_provider_parent_class)->finalize (object);
+}
+
+static void
+gstyle_css_provider_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  /* GstyleCssProvider *self = GSTYLE_CSS_PROVIDER (object); */
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_css_provider_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  /* GstyleCssProvider *self = GSTYLE_CSS_PROVIDER (object); */
+
+  switch (prop_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_css_provider_class_init (GstyleCssProviderClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gstyle_css_provider_finalize;
+  object_class->get_property = gstyle_css_provider_get_property;
+  object_class->set_property = gstyle_css_provider_set_property;
+}
+
+static void
+gstyle_css_provider_init (GstyleCssProvider *self)
+{
+  gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (self), "/org/gnome/libgstyle/theme/gstyle.css");
+  g_signal_connect_swapped (self, "parsing-error", G_CALLBACK (parsing_error), self);
+}
diff --git a/contrib/gstyle/gstyle-css-provider.h b/contrib/gstyle/gstyle-css-provider.h
new file mode 100644
index 0000000..f3a8275
--- /dev/null
+++ b/contrib/gstyle/gstyle-css-provider.h
@@ -0,0 +1,37 @@
+/* gstyle-css-provider.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_CSS_PROVIDER_H
+#define GSTYLE_CSS_PROVIDER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_CSS_PROVIDER (gstyle_css_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (GstyleCssProvider, gstyle_css_provider, GSTYLE, CSS_PROVIDER, GtkCssProvider)
+
+GstyleCssProvider      *gstyle_css_provider_init_default       (GdkScreen *screen);
+GstyleCssProvider      *gstyle_css_provider_new                (void);
+
+G_END_DECLS
+
+#endif /* GSTYLE_CSS_PROVIDER_H */
+
diff --git a/contrib/gstyle/gstyle-eyedropper.c b/contrib/gstyle/gstyle-eyedropper.c
new file mode 100644
index 0000000..d3ee4b3
--- /dev/null
+++ b/contrib/gstyle/gstyle-eyedropper.c
@@ -0,0 +1,400 @@
+/* gstyle-eyedropper.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This source code is first based on the now deprecated
+ * gtk eyedropper source code available at:
+ * https://git.gnome.org/browse/gtk+/tree/gtk/deprecated/gtkcolorsel.c#n1705
+ */
+
+#define G_LOG_DOMAIN "gstyle-eyedropper"
+
+#include <gdk/gdk.h>
+
+#include "gstyle-color.h"
+#include "gstyle-eyedropper.h"
+
+struct _GstyleEyedropper
+{
+  GtkWindow   parent_instance;
+
+  GtkWidget  *source;
+  GtkWidget  *window;
+  GdkCursor  *cursor;
+  GdkSeat    *seat;
+
+  gulong      key_handler_id;
+  gulong      grab_broken_handler_id;
+  gulong      motion_notify_handler_id;
+  gulong      pointer_pressed_handler_id;
+  gulong      pointer_released_handler_id;
+};
+
+G_DEFINE_TYPE (GstyleEyedropper, gstyle_eyedropper, GTK_TYPE_WINDOW)
+
+enum {
+  COLOR_PICKED,
+  GRAB_RELEASED,
+  LAST_SIGNAL
+};
+
+enum {
+  PROP_0,
+  PROP_SOURCE_EVENT,
+  N_PROPS
+};
+
+static guint signals [LAST_SIGNAL];
+static GParamSpec *properties [N_PROPS];
+
+static void
+get_rgba_at_cursor (GstyleEyedropper *self,
+                    GdkScreen        *screen,
+                    GdkDevice        *device,
+                    gint              x,
+                    gint              y,
+                    GdkRGBA          *rgba)
+{
+  GdkWindow *window;
+  GdkPixbuf *pixbuf;
+  guchar *pixels;
+
+  g_assert (GSTYLE_IS_EYEDROPPER (self));
+  g_assert (GDK_IS_SCREEN (screen));
+  g_assert (GDK_IS_DEVICE (device));
+
+  window = gdk_screen_get_root_window (screen);
+  pixbuf = gdk_pixbuf_get_from_window (window, x, y, 1, 1);
+  if (!pixbuf)
+    {
+      window = gdk_device_get_window_at_position (device, &x, &y);
+      if (!window)
+        return;
+
+      pixbuf = gdk_pixbuf_get_from_window (window, x, y, 1, 1);
+      if (!pixbuf)
+        return;
+    }
+
+  g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
+  g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
+
+  pixels = gdk_pixbuf_get_pixels (pixbuf);
+  rgba->red = pixels[0] / 255.0;
+  rgba->green = pixels[1] / 255.0;
+  rgba->blue = pixels[2] /255.0;
+
+  g_object_unref (pixbuf);
+}
+
+static void
+release_grab (GstyleEyedropper *self)
+{
+  g_assert (GSTYLE_IS_EYEDROPPER (self));
+
+  if (self->key_handler_id)
+    {
+      g_signal_handler_disconnect (self->window, self->key_handler_id);
+      self->key_handler_id = 0;
+    }
+
+  if (self->grab_broken_handler_id)
+    {
+      g_signal_handler_disconnect (self->window, self->grab_broken_handler_id);
+      self->grab_broken_handler_id = 0;
+    }
+
+  if (self->motion_notify_handler_id)
+    {
+      g_signal_handler_disconnect (self->window, self->motion_notify_handler_id);
+      self->motion_notify_handler_id = 0;
+    }
+
+  if (self->pointer_released_handler_id)
+    {
+      g_signal_handler_disconnect (self->window, self->pointer_released_handler_id);
+      self->pointer_released_handler_id = 0;
+    }
+
+  gtk_grab_remove (self->window);
+  gdk_seat_ungrab (self->seat);
+
+  g_signal_emit (self, signals [GRAB_RELEASED], 0);
+}
+
+static void
+gstyle_eyedropper_pointer_motion_notify_cb (GstyleEyedropper *self,
+                                            GdkEventMotion   *event,
+                                            GtkWindow        *window)
+{
+  GdkRGBA rgba;
+
+  g_assert (GSTYLE_IS_EYEDROPPER (self));
+  g_assert (event != NULL);
+  g_assert (GTK_IS_WINDOW (window));
+
+  get_rgba_at_cursor (self,
+                      gdk_event_get_screen ((GdkEvent *) event),
+                      gdk_event_get_device ((GdkEvent *) event),
+                      event->x_root, event->y_root, &rgba);
+
+  g_signal_emit (self, signals [COLOR_PICKED], 0, &rgba);
+}
+
+static gboolean
+gstyle_eyedropper_pointer_released_cb (GstyleEyedropper *self,
+                                       GdkEventButton   *event,
+                                       GtkWindow        *window)
+{
+  g_assert (GSTYLE_IS_EYEDROPPER (self));
+  g_assert (event != NULL);
+  g_assert (GTK_IS_WINDOW (window));
+
+  release_grab (self);
+
+  return GDK_EVENT_STOP;
+}
+
+static gboolean
+gstyle_eyedropper_pointer_pressed_cb (GstyleEyedropper *self,
+                                      GdkEventButton   *event,
+                                      GtkWindow        *window)
+{
+  GdkRGBA rgba;
+
+  g_assert (GSTYLE_IS_EYEDROPPER (self));
+  g_assert (event != NULL);
+  g_assert (GTK_IS_WINDOW (window));
+
+  if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY)
+    {
+      self->motion_notify_handler_id =
+        g_signal_connect_swapped (window, "motion-notify-event",
+                                  G_CALLBACK (gstyle_eyedropper_pointer_motion_notify_cb), self);
+
+      self->pointer_released_handler_id =
+        g_signal_connect_swapped (window, "button-release-event",
+                                  G_CALLBACK (gstyle_eyedropper_pointer_released_cb), self);
+
+      g_signal_handler_disconnect (self->window, self->pointer_pressed_handler_id);
+      self->pointer_pressed_handler_id = 0;
+
+      get_rgba_at_cursor (self,
+                          gdk_event_get_screen ((GdkEvent *) event),
+                          gdk_event_get_device ((GdkEvent *) event),
+                          event->x_root, event->y_root, &rgba);
+
+      g_signal_emit (self, signals [COLOR_PICKED], 0, &rgba);
+
+      return GDK_EVENT_STOP;
+    }
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static gboolean
+gstyle_eyedropper_key_pressed_cb (GstyleEyedropper *self,
+                                  GdkEventKey      *event,
+                                  GtkWindow        *window)
+{
+  g_assert (GSTYLE_IS_EYEDROPPER (self));
+  g_assert (event != NULL);
+  g_assert (GTK_IS_WINDOW (window));
+
+  /* TODO: handle cursor and picker trigger keys */
+  switch (event->keyval)
+    {
+    case GDK_KEY_Escape:
+      release_grab (self);
+      break;
+
+    default:
+      break;
+    }
+
+  return GDK_EVENT_STOP;
+}
+
+static gboolean
+gstyle_eyedropper_grab_broken_cb (GstyleEyedropper *self,
+                                  GdkEventKey      *event,
+                                  GtkWidget        *window)
+{
+  g_assert (GSTYLE_IS_EYEDROPPER (self));
+  g_assert (event != NULL);
+  g_assert (GTK_IS_WINDOW (window));
+
+  release_grab (self);
+
+  return GDK_EVENT_STOP;
+}
+
+void
+gstyle_eyedropper_set_source_event (GstyleEyedropper *self,
+                                    GdkEvent         *event)
+{
+  GdkScreen *screen;
+  GtkWidget *source;
+  GdkGrabStatus status;
+
+  g_return_if_fail (GSTYLE_IS_EYEDROPPER (self));
+  g_return_if_fail (event != NULL);
+
+  self->seat = g_object_ref (gdk_event_get_seat (event));
+  source = gtk_get_event_widget (event);
+  screen = gdk_event_get_screen (event);
+
+  g_clear_object (&self->window);
+  g_clear_object (&self->cursor);
+
+  self->window = gtk_window_new (GTK_WINDOW_POPUP);
+  gtk_window_set_screen (GTK_WINDOW (self->window), screen);
+  gtk_window_resize (GTK_WINDOW (self->window), 1, 1);
+  gtk_window_move (GTK_WINDOW (self->window), -1, -1);
+  gtk_widget_show (self->window);
+
+  gtk_widget_add_events (self->window,
+                         GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
+
+  self->cursor = gdk_cursor_new_from_name (gdk_screen_get_display (screen), "cell");
+  gtk_grab_add (self->window);
+  status = gdk_seat_grab (self->seat,
+                          gtk_widget_get_window (source),
+                          GDK_SEAT_CAPABILITY_ALL,
+                          FALSE,
+                          self->cursor,
+                          event,
+                          NULL, NULL);
+
+  if (status != GDK_GRAB_SUCCESS)
+    {
+      g_warning ("grab failed status:%i\n", status);
+      return;
+    }
+
+  self->pointer_pressed_handler_id =
+    g_signal_connect_swapped (self->window,
+                              "button-press-event",
+                              G_CALLBACK (gstyle_eyedropper_pointer_pressed_cb),
+                              self);
+
+  self->key_handler_id =
+    g_signal_connect_swapped (self->window,
+                              "key-press-event",
+                              G_CALLBACK (gstyle_eyedropper_key_pressed_cb),
+                              self);
+
+  self->grab_broken_handler_id =
+    g_signal_connect_swapped (self->window,
+                              "grab-broken-event",
+                              G_CALLBACK (gstyle_eyedropper_grab_broken_cb),
+                              self);
+}
+
+GstyleEyedropper *
+gstyle_eyedropper_new (GdkEvent *event)
+{
+  return g_object_new (GSTYLE_TYPE_EYEDROPPER,
+                       "source-event", event,
+                       NULL);
+}
+
+static void
+gstyle_eyedropper_finalize (GObject *object)
+{
+  GstyleEyedropper *self = GSTYLE_EYEDROPPER (object);
+
+  g_clear_object (&self->window);
+  g_clear_object (&self->cursor);
+  gdk_seat_ungrab (self->seat);
+
+  G_OBJECT_CLASS (gstyle_eyedropper_parent_class)->finalize (object);
+}
+
+static void
+gstyle_eyedropper_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  GstyleEyedropper *self = GSTYLE_EYEDROPPER (object);
+  GdkEvent *event;
+
+  switch (prop_id)
+    {
+    case PROP_SOURCE_EVENT:
+      event = g_value_get_boxed (value);
+      gstyle_eyedropper_set_source_event (self, event);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_eyedropper_class_init (GstyleEyedropperClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gstyle_eyedropper_finalize;
+  object_class->set_property = gstyle_eyedropper_set_property;
+
+  /**
+   * GstyleEyedropper::color-picked:
+   * @self: A #GstyleEyedropper.
+   * @rgba: a #GdkRGBA color.
+   *
+   * This signal is emitted when you click to pick a color.
+   */
+  signals [COLOR_PICKED] = g_signal_new ("color-picked",
+                                         G_TYPE_FROM_CLASS (klass),
+                                         G_SIGNAL_RUN_LAST,
+                                         0,
+                                         NULL, NULL, NULL,
+                                         G_TYPE_NONE,
+                                         1,
+                                         GDK_TYPE_RGBA);
+
+  /**
+   * GstyleEyedropper::grab-released:
+   * @self: A #GstyleEyedropper.
+   *
+   * This signal is emitted when you release the grab by hitting 'Esc'.
+   */
+  signals [GRAB_RELEASED] = g_signal_new ("grab-released",
+                                          G_TYPE_FROM_CLASS (klass),
+                                          G_SIGNAL_RUN_LAST,
+                                          0,
+                                          NULL, NULL, NULL,
+                                          G_TYPE_NONE,
+                                          0);
+
+  properties [PROP_SOURCE_EVENT] =
+    g_param_spec_boxed ("source-event",
+                        "source-event",
+                        "the event generated when triggering the picker widget",
+                        GDK_TYPE_EVENT,
+                        (G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gstyle_eyedropper_init (GstyleEyedropper *self)
+{
+}
diff --git a/contrib/gstyle/gstyle-eyedropper.h b/contrib/gstyle/gstyle-eyedropper.h
new file mode 100644
index 0000000..bab4905
--- /dev/null
+++ b/contrib/gstyle/gstyle-eyedropper.h
@@ -0,0 +1,35 @@
+/* gstyle-eyedropper.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_EYEDROPPER_H
+#define GSTYLE_EYEDROPPER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_EYEDROPPER (gstyle_eyedropper_get_type())
+
+G_DECLARE_FINAL_TYPE (GstyleEyedropper, gstyle_eyedropper, GSTYLE, EYEDROPPER, GtkWindow)
+
+GstyleEyedropper       *gstyle_eyedropper_new       (GdkEvent       *event);
+
+G_END_DECLS
+
+#endif /* GSTYLE_EYEDROPPER_H */
diff --git a/contrib/gstyle/gstyle-hsv.c b/contrib/gstyle/gstyle-hsv.c
new file mode 100644
index 0000000..53e2b03
--- /dev/null
+++ b/contrib/gstyle/gstyle-hsv.c
@@ -0,0 +1,64 @@
+/* gstyle-hsv.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-hsv"
+
+#include "gstyle-hsv.h"
+
+G_DEFINE_BOXED_TYPE (GstyleHSV, gstyle_hsv, gstyle_hsv_copy, gstyle_hsv_free)
+
+/**
+ * GstyleHSV:
+ * @h: color hue in the range [0, 360[ degrees.
+ * @s: color saturation in the range [0, 1].
+ * @v: color value in the range [0, 1].
+ * @alpha: The opacity of the color in [0, 1] range.
+ *
+ * A #GstyleHSV is used to represent a color in
+ * the HSV (also called HSB) colorspace.
+ */
+
+/**
+ * gstyle_hsv_copy:
+ * @self: a #GstyleHSV
+ *
+ * Makes a copy of a #GstyleHSV
+ *
+ * The result must be freed through gstyle_hsv_free().
+ *
+ * Returns: a newly allocated #GstyleHSV with the same content as @self.
+ *
+ */
+GstyleHSV *
+gstyle_hsv_copy (const GstyleHSV *self)
+{
+  return g_slice_dup (GstyleHSV, self);
+}
+
+/**
+ * gstyle_hsv_free:
+ * @self: a #GstyleHSV
+ *
+ * Frees a #GstyleHSV created with gstyle_hsv_copy().
+ *
+ */
+void
+gstyle_hsv_free (GstyleHSV *self)
+{
+  g_slice_free (GstyleHSV, self);
+}
diff --git a/contrib/gstyle/gstyle-hsv.h b/contrib/gstyle/gstyle-hsv.h
new file mode 100644
index 0000000..c93f542
--- /dev/null
+++ b/contrib/gstyle/gstyle-hsv.h
@@ -0,0 +1,45 @@
+/* gstyle-hsv.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_HSV_H
+#define GSTYLE_HSV_H
+
+#include <glib.h>
+
+#include "gstyle-types.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_HSV (gstyle_hsv_get_type ())
+
+struct _GstyleHSV
+{
+  gdouble h;
+  gdouble s;
+  gdouble v;
+  gdouble alpha;
+};
+
+GType          gstyle_hsv_get_type                (void) G_GNUC_CONST;
+
+GstyleHSV     *gstyle_hsv_copy                    (const GstyleHSV  *self);
+void           gstyle_hsv_free                    (GstyleHSV        *self);
+
+G_END_DECLS
+
+#endif /* GSTYLE_HSV_H */
diff --git a/contrib/gstyle/gstyle-palette-widget.c b/contrib/gstyle/gstyle-palette-widget.c
new file mode 100644
index 0000000..4f621f2
--- /dev/null
+++ b/contrib/gstyle/gstyle-palette-widget.c
@@ -0,0 +1,1454 @@
+/* gstyle-palette-widget.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-palette-widget"
+
+#include <cairo/cairo.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <math.h>
+
+#include "gstyle-css-provider.h"
+#include "gstyle-color.h"
+#include "gstyle-color-widget.h"
+#include "gstyle-utils.h"
+
+#include "gstyle-palette-widget.h"
+
+/*
+ * Each palette are refed twice, once when added to the #GListStore,
+ * once when they are binded to the display widget (#GtkListBox or #GtkFlowBox ).
+ * Both references are removed when the #GstylePalette is removed from the #GstylePaletteWidget.
+ */
+
+struct _GstylePaletteWidget
+{
+  GtkBin                       parent_instance;
+
+  GstyleCssProvider           *default_provider;
+  GListStore                  *palettes;
+  GstylePalette               *selected_palette;
+
+  GtkWidget                   *placeholder_box;
+  GtkWidget                   *placeholder;
+  GtkStack                    *view_stack;
+  GtkWidget                   *listbox;
+  GtkWidget                   *flowbox;
+
+  GstyleColor                 *dnd_color;
+  gint                         dnd_child_index;
+  GdkPoint                     dnd_last_pos;
+  guint                        dnd_last_time;
+  gdouble                      dnd_speed;
+  gboolean                     is_on_drag;
+
+  GstylePaletteWidgetViewMode  view_mode;
+  GstylePaletteWidgetSortMode  sort_mode;
+
+  guint                        current_has_load : 1;
+  guint                        current_has_save : 1;
+
+  guint                        dnd_draw_highlight : 1;
+  guint                        is_dnd_at_end : 1;
+};
+
+G_DEFINE_TYPE (GstylePaletteWidget, gstyle_palette_widget, GTK_TYPE_BIN)
+
+#define GSTYLE_DND_SPEED_THRESHOLD 50
+#define DND_INDEX_START (G_MININT)
+
+static guint unsaved_palette_count = 0;
+
+enum {
+  PROP_0,
+  PROP_PLACEHOLDER,
+  PROP_SELECTED_PALETTE_ID,
+  PROP_VIEW_MODE,
+  PROP_SORT_MODE,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+enum {
+  ACTIVATED,
+  PALETTE_ADDED,
+  PALETTE_REMOVED,
+  LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL];
+
+typedef struct _CursorInfo
+{
+  GstyleColorWidget *child;
+  gint               index;
+  gint               dest_x;
+  gint               dest_y;
+  gint               nb_col;
+} CursorInfo;
+
+static gint
+flowbox_get_nb_col (GstylePaletteWidget *self,
+                    GtkFlowBox          *flowbox)
+{
+  GtkFlowBoxChild *child;
+  GtkAllocation alloc;
+  guint min_per_line;
+  guint max_per_line;
+  gint previous_x = -1;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GTK_IS_FLOW_BOX (flowbox));
+  g_assert (gtk_flow_box_get_homogeneous (flowbox) == TRUE);
+
+  /* Child width is not perfectly constant, so we need some tricks */
+  min_per_line = gtk_flow_box_get_min_children_per_line (flowbox);
+  if (min_per_line < 1)
+    min_per_line = 1;
+
+  max_per_line = gtk_flow_box_get_max_children_per_line (flowbox);
+  if (max_per_line < 1)
+    max_per_line = 20;
+
+  for (guint i = 0; i <= max_per_line; ++i)
+    {
+      child = gtk_flow_box_get_child_at_index (flowbox, i);
+      if (child != NULL)
+        {
+          gtk_widget_get_allocation (GTK_WIDGET (child), &alloc);
+          if (alloc.x > previous_x)
+            {
+              previous_x = alloc.x;
+              continue;
+            }
+        }
+
+      return i;
+    }
+
+  return -1;
+}
+
+/* We make the assumption that the list is in order of apparition,
+ * in vertical orientation, with all children visible and
+ * homogenous set.
+ */
+static GtkFlowBoxChild *
+flowbox_get_child_at_xy (GstylePaletteWidget *self,
+                         gint                 x,
+                         gint                 y,
+                         gint                *index,
+                         gint                *nb_col)
+{
+  GtkFlowBox *flowbox;
+  GtkFlowBoxChild *child;
+  GtkAllocation alloc;
+  gint row_spacing;
+  guint right;
+  gint bottom;
+  guint index_y = 0;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (index != NULL);
+  g_assert (nb_col != NULL);
+
+  *index = -1;
+  if (x == -1 || y == -1)
+    return NULL;
+
+  flowbox = GTK_FLOW_BOX (self->flowbox);
+
+  g_assert (gtk_flow_box_get_homogeneous (flowbox) == TRUE);
+
+  child = gtk_flow_box_get_child_at_index (flowbox, 0);
+  if (child == NULL)
+    return NULL;
+
+  gtk_widget_get_allocation (GTK_WIDGET (child), &alloc);
+  row_spacing = gtk_flow_box_get_row_spacing (flowbox);
+
+  *nb_col = flowbox_get_nb_col (self, flowbox);
+  index_y = (y / (alloc.height + row_spacing) * (*nb_col));
+  for (guint i = index_y; i < (index_y + *nb_col); ++i)
+    {
+      child = gtk_flow_box_get_child_at_index (flowbox, i);
+      if (child != NULL)
+        {
+          gtk_widget_get_allocation (GTK_WIDGET (child), &alloc);
+          right = alloc.x + alloc.width;
+          bottom = alloc.y + alloc.height;
+          if (alloc.x <= x && x < right && alloc.y <= y && y < bottom)
+            {
+              *index = i;
+              return child;
+            }
+        }
+    }
+
+  return NULL;
+}
+
+/* x,y are in #GstylePaletteWidget coordinates.
+ * if the cursor is on the placeholder, %FALSE is returned.
+ */
+static gboolean
+dnd_get_index_from_cursor (GstylePaletteWidget *self,
+                           gint                 x,
+                           gint                 y,
+                           CursorInfo          *info)
+{
+  GtkBin *bin_child;
+  gint len;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (info != NULL);
+
+  if (self->view_mode == GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST)
+    {
+      gtk_widget_translate_coordinates (GTK_WIDGET (self), self->listbox, x, y, &info->dest_x, 
&info->dest_y);
+      bin_child = GTK_BIN (gtk_list_box_get_row_at_y (GTK_LIST_BOX (self->listbox), info->dest_y));
+      if (bin_child == NULL)
+        {
+          len = gstyle_palette_get_len (self->selected_palette);
+          if (len == 0)
+            return FALSE;
+
+          bin_child = GTK_BIN (gtk_list_box_get_row_at_index (GTK_LIST_BOX (self->listbox), len - 1));
+        }
+
+      info->index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (bin_child));
+      info->child = GSTYLE_COLOR_WIDGET (gtk_bin_get_child (GTK_BIN (bin_child)));
+    }
+  else
+    {
+      gtk_widget_translate_coordinates (GTK_WIDGET (self), self->flowbox, x, y, &info->dest_x, 
&info->dest_y);
+      bin_child = GTK_BIN (flowbox_get_child_at_xy (self, info->dest_x, info->dest_y, &info->index, 
&info->nb_col));
+      if (bin_child == NULL)
+        return FALSE;
+
+      info->child = GSTYLE_COLOR_WIDGET (gtk_bin_get_child (GTK_BIN (bin_child)));
+    }
+
+  return TRUE;
+}
+
+/* Returns: The insertion index
+ * x and y are in #GstylePaletteWidget coordinates.
+ * if either x or y are equal to -1, then the highlight
+ * is removed, and -1 is returned in this case.
+ */
+static gint
+dnd_highlight_set_from_cursor (GstylePaletteWidget *self,
+                               gint                 x,
+                               gint                 y)
+{
+  GtkAllocation alloc;
+  CursorInfo info;
+  gint dest_ref;
+  gint start;
+  gint size;
+  gboolean highlight;
+  gboolean redraw = FALSE;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+
+  if (x != -1 && y != -1 && dnd_get_index_from_cursor (self, x, y, &info))
+    {
+      gtk_widget_get_allocation (GTK_WIDGET (info.child), &alloc);
+      if (self->view_mode == GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST)
+        {
+          gint len;
+
+          dest_ref = info.dest_y;
+          start = alloc.y;
+          size = alloc.height;
+
+          len = gstyle_palette_get_len (self->selected_palette);
+          self->is_dnd_at_end = (info.index == (len - 1));
+        }
+      else
+        {
+          dest_ref = info.dest_x;
+          start = alloc.x;
+          size = alloc.width;
+
+          /* Check if we in the rightmost column */
+          self->is_dnd_at_end = ((info.index + 1)% info.nb_col == 0);
+        }
+
+      if (dest_ref > (start + size * 0.80))
+        info.index += 1;
+      else if (dest_ref > (start + size * 0.20))
+        info.index = -1;
+
+      highlight = TRUE;
+    }
+  else
+    {
+      highlight = FALSE;
+      info.index = -1;
+    }
+
+  if (self->dnd_draw_highlight != highlight || self->dnd_child_index != info.index)
+    redraw = TRUE;
+
+  self->dnd_child_index = info.index;
+  self->dnd_draw_highlight = highlight;
+
+  if (redraw)
+    {
+      if (self->view_mode == GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST)
+        gtk_widget_queue_draw (self->listbox);
+      else
+        gtk_widget_queue_draw (self->flowbox);
+    }
+
+  return info.index;
+}
+
+/* TODO: set the palette to need-attention if drop ( mean you need to save */
+/* TODO: take into account the case when the src and dst are from the same palette */
+/* TODO: do dnd from the flowbox */
+
+static gboolean
+gstyle_palette_widget_on_drag_motion (GtkWidget      *widget,
+                                      GdkDragContext *context,
+                                      gint            x,
+                                      gint            y,
+                                      guint           time)
+{
+  GstylePaletteWidget *self = GSTYLE_PALETTE_WIDGET (widget);
+  GdkAtom target;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  target = gtk_drag_dest_find_target (widget, context, NULL);
+  if (target != gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET"))
+    {
+      dnd_highlight_set_from_cursor (self, -1, -1);
+      gdk_drag_status (context, 0, time);
+      return FALSE;
+    }
+
+  dnd_highlight_set_from_cursor (self, x, y);
+  gdk_drag_status (context, GDK_ACTION_COPY, time);
+
+  return TRUE;
+}
+
+static void
+gstyle_palette_widget_on_drag_leave (GtkWidget      *widget,
+                                     GdkDragContext *context,
+                                     guint           time)
+{
+  GstylePaletteWidget *self = GSTYLE_PALETTE_WIDGET (widget);
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  self->dnd_draw_highlight = FALSE;
+
+  if (self->view_mode == GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST)
+    gtk_widget_queue_draw (self->listbox);
+  else
+    gtk_widget_queue_draw (self->flowbox);
+}
+
+static gboolean
+gstyle_palette_widget_on_drag_drop (GtkWidget        *widget,
+                                    GdkDragContext   *context,
+                                    gint              x,
+                                    gint              y,
+                                    guint             time)
+{
+  GstylePaletteWidget *self = GSTYLE_PALETTE_WIDGET (widget);
+  GdkAtom target;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  target = gtk_drag_dest_find_target (widget, context, NULL);
+  if (target == gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET"))
+    {
+      gtk_drag_get_data (widget, context, target, time);
+      return TRUE;
+    }
+
+  dnd_highlight_set_from_cursor (self, -1, -1);
+  return FALSE;
+}
+
+static void
+gstyle_palette_widget_on_drag_data_received (GtkWidget        *widget,
+                                             GdkDragContext   *context,
+                                             gint              x,
+                                             gint              y,
+                                             GtkSelectionData *data,
+                                             guint             info,
+                                             guint             time)
+{
+  GstylePaletteWidget *self = GSTYLE_PALETTE_WIDGET (widget);
+  GstyleColor **src_color;
+  GstyleColor *color;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GDK_IS_DRAG_CONTEXT (context));
+
+  if (gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GSTYLE_COLOR_WIDGET"))
+    {
+      /* TODO: check if the color widget is coming from a PaletteWidget container */
+      src_color = (void*)gtk_selection_data_get_data (data);
+      color = gstyle_color_copy (*src_color);
+      gstyle_palette_add_at_index (self->selected_palette,
+                                   color,
+                                   self->dnd_child_index,
+                                   NULL);
+
+      g_object_unref (color);
+      gtk_drag_finish (context, TRUE, FALSE, time);
+    }
+  else
+    gtk_drag_finish (context, FALSE, FALSE, time);
+
+  dnd_highlight_set_from_cursor (self, -1, -1);
+}
+
+/**
+ * gstyle_palette_widget_set_placeholder:
+ * @self: A #GstylePaletteWidget.
+ * @placeholder: A #GtkWidget or %NULL.
+ *
+ * Set a placeholder to show when no palettes are loaded.
+ *
+ */
+void
+gstyle_palette_widget_set_placeholder (GstylePaletteWidget *self,
+                                       GtkWidget           *placeholder)
+{
+  g_return_if_fail (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_return_if_fail (GTK_IS_WIDGET (self) || placeholder == NULL);
+
+  if (self->placeholder != placeholder)
+    {
+      if (self->placeholder != NULL)
+        gtk_container_remove (GTK_CONTAINER (self->placeholder_box), self->placeholder);
+
+      self->placeholder = placeholder;
+      if (placeholder != NULL)
+        {
+          gtk_container_add (GTK_CONTAINER (self->placeholder_box), placeholder);
+          g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PLACEHOLDER]);
+
+          if (self->selected_palette == NULL)
+            gtk_stack_set_visible_child_name (self->view_stack, "placeholder");
+        }
+      else
+        gstyle_palette_widget_set_view_mode (self, self->view_mode);
+    }
+}
+
+/**
+ * gstyle_palette_widget_get_placeholder:
+ * @self: A #GstylePaletteWidget.
+ *
+ * Get the current placeholder GtkWidget.
+ *
+ * Returns: (transfer none): A #GtkObject.
+ *
+ */
+GtkWidget *
+gstyle_palette_widget_get_placeholder (GstylePaletteWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), NULL);
+
+  return self->placeholder;
+}
+
+static void
+gstyle_palette_widget_add_actions (GstylePaletteWidget *self)
+{
+  GSimpleActionGroup *actions_group;
+  GPropertyAction *action;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+
+  actions_group = g_simple_action_group_new ();
+
+  action = g_property_action_new ("view-mode", self, "view-mode");
+  g_action_map_add_action (G_ACTION_MAP (actions_group), G_ACTION (action));
+  action = g_property_action_new ("sort-mode", self, "sort-mode");
+  g_action_map_add_action (G_ACTION_MAP (actions_group), G_ACTION (action));
+
+  gtk_widget_insert_action_group (GTK_WIDGET (self), "gstyle-palettes-prefs", G_ACTION_GROUP 
(actions_group));
+}
+
+static gint
+gstyle_palette_widget_get_palette_position (GstylePaletteWidget *self,
+                                            GstylePalette       *palette)
+{
+  gint len;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GSTYLE_IS_PALETTE (palette));
+
+  len = g_list_model_get_n_items (G_LIST_MODEL (self->palettes));
+  for (gint n = 0; n < len; ++n)
+    {
+      g_autoptr (GstylePalette) model_palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), n);
+
+      if (palette == model_palette)
+        return n;
+    }
+
+  return -1;
+}
+
+static GtkWidget *
+create_palette_list_item (gpointer item,
+                          gpointer user_data)
+{
+  GstylePaletteWidget *self = (GstylePaletteWidget *)user_data;
+  GstyleColor *color = (GstyleColor *)item;
+  GtkWidget *row;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GSTYLE_IS_COLOR (color));
+
+  row = g_object_new (GSTYLE_TYPE_COLOR_WIDGET,
+                      "color", color,
+                      "visible", TRUE,
+                      "halign", GTK_ALIGN_FILL,
+                      NULL);
+
+  return row;
+}
+
+static GtkWidget *
+create_palette_flow_item (gpointer item,
+                          gpointer user_data)
+{
+  GstylePaletteWidget *self = (GstylePaletteWidget *)user_data;
+  GstyleColor *color = (GstyleColor *)item;
+  g_autofree gchar *color_string = NULL;
+  g_autofree gchar *tooltip = NULL;
+  const gchar *name;
+  GtkWidget *swatch;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GSTYLE_IS_COLOR (color));
+
+  name = gstyle_color_get_name (color);
+  if (gstyle_str_empty0 (name))
+    tooltip = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_ORIGINAL);
+  else
+    {
+      color_string = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_ORIGINAL);
+      tooltip = g_strdup_printf ("%s (%s)", name, color_string);
+    }
+
+  swatch = g_object_new (GSTYLE_TYPE_COLOR_WIDGET,
+                         "color", color,
+                         "visible", TRUE,
+                         "name-visible", FALSE,
+                         "fallback-name-visible", FALSE,
+                         "tooltip-text", tooltip,
+                         "width-request", 64,
+                         "height-request", 64,
+                         NULL);
+
+  return swatch;
+}
+
+static void
+bind_palette (GstylePaletteWidget *self,
+              GstylePalette       *palette)
+{
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (palette == NULL || GSTYLE_IS_PALETTE (palette));
+  g_assert (palette == NULL || gstyle_palette_widget_get_palette_position (self, palette) != -1);
+
+  if (self->view_mode == GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST)
+    {
+      gtk_flow_box_bind_model (GTK_FLOW_BOX (self->flowbox), NULL, NULL, NULL, NULL);
+      if (palette != NULL)
+        {
+          gtk_list_box_bind_model (GTK_LIST_BOX (self->listbox), G_LIST_MODEL (palette),
+                                   create_palette_list_item, self, NULL);
+          gtk_stack_set_visible_child_name (self->view_stack, "list");
+        }
+      else
+        gtk_list_box_bind_model (GTK_LIST_BOX (self->listbox), NULL, NULL, NULL, NULL);
+    }
+  else
+    {
+      gtk_list_box_bind_model (GTK_LIST_BOX (self->listbox), NULL, NULL, NULL, NULL);
+      if (palette != NULL)
+        {
+          gtk_flow_box_bind_model (GTK_FLOW_BOX (self->flowbox),  G_LIST_MODEL (palette),
+                                   create_palette_flow_item, self, NULL);
+          gtk_stack_set_visible_child_name (self->view_stack, "flow");
+        }
+      else
+        gtk_flow_box_bind_model (GTK_FLOW_BOX (self->flowbox), NULL, NULL, NULL, NULL);
+    }
+
+  self->selected_palette = palette;
+}
+
+static const gchar *
+gstyle_palette_widget_get_selected_palette_id (GstylePaletteWidget *self)
+{
+  GstylePalette *palette;
+
+  palette = gstyle_palette_widget_get_selected_palette (self);
+  if (palette != NULL)
+    return gstyle_palette_get_id (palette);
+  else
+    return "\0";
+}
+
+static void
+gstyle_palette_widget_set_selected_palette_by_id (GstylePaletteWidget *self,
+                                                  const gchar         *palette_id)
+{
+  const gchar *current_palette_id;
+  gint len;
+
+  len = g_list_model_get_n_items (G_LIST_MODEL (self->palettes));
+  for (gint n = 0; n < len; ++n)
+    {
+      g_autoptr (GstylePalette) palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), n);
+
+      current_palette_id = gstyle_palette_get_id (palette);
+      if (g_strcmp0 (current_palette_id, palette_id) == 0)
+        gstyle_palette_widget_show_palette (self, palette);
+    }
+}
+
+/**
+ * gstyle_palette_widget_get_selected_palette:
+ * @self: A #GstylePaletteWidget
+ *
+ * Return the selected #GstylePalette.
+ *
+ * Returns: (transfer none) (allow-none): a #GstylePalette or %NULL if none are selected or loaded.
+ *
+ */
+GstylePalette *
+gstyle_palette_widget_get_selected_palette (GstylePaletteWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+
+  return self->selected_palette;
+}
+
+/**
+ * gstyle_palette_widget_show_palette:
+ * @self: A #GstylePaletteWidget
+ * @palette: A #GstylePalette
+ *
+ * Show @palette in the widget.
+ *
+ * Returns: %TRUE on succes, %FALSE if @palette is not in the list.
+ *
+ */
+gboolean
+gstyle_palette_widget_show_palette (GstylePaletteWidget *self,
+                                    GstylePalette       *palette)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (palette), FALSE);
+
+  if (self->selected_palette != palette)
+    {
+      if (gstyle_palette_widget_get_palette_position (self, palette) == -1)
+        return FALSE;
+
+      bind_palette (self, palette);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTED_PALETTE_ID]);
+    }
+
+  return TRUE;
+}
+
+static void
+gstyle_palette_widget_color_swatch_activated (GstylePaletteWidget *self,
+                                              GtkFlowBoxChild     *child,
+                                              GtkFlowBox          *flowbox)
+{
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GTK_IS_FLOW_BOX (flowbox));
+  g_assert (GTK_IS_FLOW_BOX_CHILD (child));
+
+  g_signal_emit (self, signals [ACTIVATED], 0, self->selected_palette, gtk_flow_box_child_get_index (child));
+}
+
+static void
+gstyle_palette_widget_color_row_activated (GstylePaletteWidget *self,
+                                           GtkListBoxRow       *row,
+                                           GtkListBox          *listbox)
+{
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GTK_IS_LIST_BOX (listbox));
+  g_assert (GTK_IS_LIST_BOX_ROW (row));
+
+  g_signal_emit (self, signals [ACTIVATED], 0, self->selected_palette, gtk_list_box_row_get_index (row));
+}
+
+/**
+ * gstyle_palette_widget_get_n_palettes:
+ * @self: A #GstylePaletteWidget
+ *
+ * Get the number of #GstylePalette in the palettes list.
+ *
+ * Returns: number of palettes in the list.
+ *
+ */
+gint
+gstyle_palette_widget_get_n_palettes (GstylePaletteWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), 0);
+
+  return g_list_model_get_n_items (G_LIST_MODEL (self->palettes));;
+}
+
+/**
+ * gstyle_palette_widget_get_palette_at_index:
+ * @self: A #GstylePaletteWidget
+ * @index: A position in the palette list, from 0 to (n - 1) palettes
+ *
+ * Get the #GstylePalette ref at position @index in the palettes list.
+ *
+ * Returns: (transfer none): A #GstylePalette or %NULL if index is out of bounds.
+ *
+ */
+GstylePalette *
+gstyle_palette_widget_get_palette_at_index (GstylePaletteWidget *self,
+                                            guint                index)
+{
+  g_autoptr (GstylePalette) palette = NULL;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+
+  palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), index);
+  return palette;
+}
+
+/**
+ * gstyle_palette_widget_get_store:
+ * @self: A #GstylePaletteWidget
+ *
+ * Return a #GListStore containing the palettes.
+ *
+ * Returns: (transfer none): #GListStore.
+ *
+ */
+GListStore *
+gstyle_palette_widget_get_store (GstylePaletteWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+
+  return self->palettes;
+}
+
+/**
+ * gstyle_palette_widget_get_list:
+ * @self: A #GstylePaletteWidget
+ *
+ * Return a #GList of the palettes.
+ *
+ * Returns: (transfer container) (element-type GstylePalette): #GList of #GstylePalette.
+ *
+ */
+GList *
+gstyle_palette_widget_get_list (GstylePaletteWidget *self)
+{
+  GList *l = NULL;
+  gint len;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+
+  len = g_list_model_get_n_items (G_LIST_MODEL (self->palettes));
+  if (len > 0)
+    for (gint n = (len - 1); n >= 0; --n)
+    {
+      g_autoptr (GstylePalette) palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), n);
+
+      l = g_list_prepend (l, palette);
+    }
+
+  return l;
+}
+
+/**
+ * gstyle_palette_widget_add:
+ * @self: A #GstylePaletteWidget
+ * @palette: A #GstylePalette
+ *
+ * Add @palette to the widget list.
+ *
+ * Returns: %TRUE on succes, %FALSE if @palette is already in the list.
+ *
+ */
+gboolean
+gstyle_palette_widget_add (GstylePaletteWidget *self,
+                           GstylePalette       *palette)
+{
+  const gchar *id;
+  const gchar *list_id;
+  const gchar *palette_name;
+  gchar *name;
+  gint len;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (palette), FALSE);
+
+  id = gstyle_palette_get_id (palette);
+  len = g_list_model_get_n_items (G_LIST_MODEL (self->palettes));
+  for (gint n = 0; n < len; ++n)
+    {
+      g_autoptr (GstylePalette) list_palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), n);
+
+      list_id = gstyle_palette_get_id (list_palette);
+      if (g_strcmp0 (id, list_id) == 0)
+        return FALSE;
+    }
+
+  palette_name = gstyle_palette_get_name (palette);
+  if (gstyle_str_empty0 (palette_name))
+    {
+      name = g_strdup_printf ("Unsaved palette %u", unsaved_palette_count++);
+      gstyle_palette_set_name (palette, name);
+      g_free (name);
+    }
+
+  g_list_store_append (self->palettes, palette);
+  g_signal_emit (self, signals [PALETTE_ADDED], 0, palette);
+
+  return TRUE;
+}
+
+/**
+ * gstyle_palette_widget_remove_all:
+ * @self: A #GstylePaletteWidget
+ *
+ * Remove all palettes in the widget list.
+ *
+ */
+void
+gstyle_palette_widget_remove_all (GstylePaletteWidget *self)
+{
+  gint len;
+
+  g_return_if_fail (GSTYLE_IS_PALETTE_WIDGET (self));
+
+  len = g_list_model_get_n_items (G_LIST_MODEL (self->palettes));
+  for (gint n = 0; n < len; ++n)
+    {
+      g_autoptr (GstylePalette) palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), n);
+
+      g_signal_emit (self, signals [PALETTE_REMOVED], 0, palette);
+    }
+
+  bind_palette (self, NULL);
+  g_list_store_remove_all (self->palettes);
+
+  gtk_stack_set_visible_child_name (self->view_stack, "placeholder");
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTED_PALETTE_ID]);
+}
+
+/**
+ * gstyle_palette_widget_remove:
+ * @self: A #GstylePaletteWidget
+ * @palette: A #GstylePalette
+ *
+ * Remove @palette in the widget list.
+ *
+ * Returns: %TRUE on succes, %FALSE if @palette is not in the list.
+ *
+ */
+gboolean
+gstyle_palette_widget_remove (GstylePaletteWidget *self,
+                              GstylePalette       *palette)
+{
+  gint len;
+  gint next;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (palette), FALSE);
+
+  len = g_list_model_get_n_items (G_LIST_MODEL (self->palettes));
+  for (gint n = 0; n < len; ++n)
+    {
+      g_autoptr (GstylePalette) next_palette = NULL;
+      g_autoptr (GstylePalette) model_palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), n);
+
+      if (palette == model_palette)
+        {
+          if (palette == self->selected_palette)
+            bind_palette (self, NULL);
+
+          g_list_store_remove (self->palettes, n);
+          g_signal_emit (self, signals [PALETTE_REMOVED], 0, palette);
+
+          len -= 1;
+          if (len > 0)
+            {
+              next = (n == len) ? (n - 1) : n;
+              next_palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), next);
+              if (next_palette != NULL)
+                gstyle_palette_widget_show_palette (self, next_palette);
+            }
+          else
+            {
+              gtk_stack_set_visible_child_name (self->view_stack, "placeholder");
+              g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTED_PALETTE_ID]);
+            }
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+
+}
+
+/**
+ * gstyle_palette_widget_get_palette_by_id:
+ * @self: A #GstylePaletteWidget
+ * @id: A palette id string
+ *
+ * Return the corresponding #GstylePalette if in the #GstylePaletteWidget list.
+ *
+ * Returns: (transfer none): A #GstylePalette if in the list, %NULL otherwise.
+ *
+ */
+GstylePalette *
+gstyle_palette_widget_get_palette_by_id (GstylePaletteWidget *self,
+                                         const gchar         *id)
+{
+  const gchar *palette_id;
+  gint len;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), NULL);
+  g_return_val_if_fail (!gstyle_str_empty0 (id), NULL);
+
+  len = g_list_model_get_n_items (G_LIST_MODEL (self->palettes));
+  for (gint n = 0; n < len; ++n)
+    {
+      g_autoptr (GstylePalette) palette = g_list_model_get_item (G_LIST_MODEL (self->palettes), n);
+
+      palette_id = gstyle_palette_get_id (palette);
+      if (g_strcmp0 (palette_id, id) == 0)
+        return palette;
+    }
+
+  return NULL;
+}
+
+/**
+ * gstyle_palette_widget_remove_by_id:
+ * @self: A #GstylePaletteWidget
+ * @id: A palette id string
+ *
+ * Remove palette with @id  from the widget list.
+ *
+ * Returns: %TRUE on succes, %FALSE if not in the palettes list.
+ *
+ */
+gboolean
+gstyle_palette_widget_remove_by_id (GstylePaletteWidget *self,
+                                    const gchar         *id)
+{
+  GstylePalette *palette;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), FALSE);
+  g_return_val_if_fail (!gstyle_str_empty0 (id), FALSE);
+
+  palette = gstyle_palette_widget_get_palette_by_id (self, id);
+  if (palette != NULL)
+    {
+      gstyle_palette_widget_remove (self, palette);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * gstyle_palette_widget_set_view_mode:
+ * @self: A #GstylePaletteWidget
+ * @mode: A #GstylePaletteWidgetViewMode
+ *
+ * Sets the view mode of the palette widget.
+ *
+ */
+void
+gstyle_palette_widget_set_view_mode (GstylePaletteWidget         *self,
+                                     GstylePaletteWidgetViewMode  mode)
+{
+  g_return_if_fail (GSTYLE_IS_PALETTE_WIDGET (self));
+
+  if (self->view_mode != mode)
+    {
+      self->view_mode = mode;
+      self->dnd_child_index = -1;
+      bind_palette (self, self->selected_palette);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_VIEW_MODE]);
+    }
+
+
+  if (self->selected_palette != NULL || self->placeholder == NULL)
+    {
+      if (mode == GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST)
+        gtk_stack_set_visible_child_name (self->view_stack, "list");
+      else
+        gtk_stack_set_visible_child_name (self->view_stack, "flow");
+    }
+}
+
+/**
+ * gstyle_palette_widget_get_view_mode:
+ * @self: A #GstylePaletteWidget
+ *
+ * Get the view mode of the palette widget.
+ *
+ * Returns: The #GstylePaletteWidgetViewMode.
+ *
+ */
+GstylePaletteWidgetViewMode
+gstyle_palette_widget_get_view_mode (GstylePaletteWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST);
+
+  return self->view_mode;
+}
+
+/**
+ * gstyle_palette_widget_set_sort_mode:
+ * @self: A #GstylePaletteWidget
+ * @mode: A #GstylePaletteWidgetViewMode
+ *
+ * Sets the sort mode of the palette widget.
+ *
+ */
+void
+gstyle_palette_widget_set_sort_mode (GstylePaletteWidget         *self,
+                                     GstylePaletteWidgetSortMode  mode)
+{
+  g_return_if_fail (GSTYLE_IS_PALETTE_WIDGET (self));
+
+  if (self->sort_mode != mode)
+  {
+    self->sort_mode = mode;
+    g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SORT_MODE]);
+  }
+}
+
+/**
+ * gstyle_palette_widget_get_sort_mode:
+ * @self: A #GstylePaletteWidget
+ *
+ * Get the sort mode of the palette widget.
+ *
+ * Returns: The #GstylePaletteWidgetSortMode.
+ *
+ */
+GstylePaletteWidgetSortMode
+gstyle_palette_widget_get_sort_mode (GstylePaletteWidget *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE_WIDGET (self), GSTYLE_PALETTE_WIDGET_SORT_MODE_ORIGINAL);
+
+  return self->sort_mode;
+}
+
+/**
+ * gstyle_palette_widget_new:
+ *
+ * Create a new #GstylePaletteWidget.
+ *
+ * Returns: A #GstylePaletteWidget.
+ *
+ */
+GstylePaletteWidget *
+gstyle_palette_widget_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_PALETTE_WIDGET, NULL);
+}
+
+static gboolean
+listbox_draw_cb (GtkWidget           *listbox,
+                 cairo_t             *cr,
+                 GstylePaletteWidget *self)
+{
+  GtkStyleContext *style_context;
+  GtkListBoxRow *bin_child;
+  GtkAllocation alloc;
+  gint y;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GTK_IS_LIST_BOX (listbox));
+
+  if (self->dnd_draw_highlight && self->dnd_child_index != -1)
+    {
+      style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+      gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_DND);
+
+      if (self->is_dnd_at_end)
+        {
+          bin_child = gtk_list_box_get_row_at_index (GTK_LIST_BOX (self->listbox), self->dnd_child_index - 
1);
+          gtk_widget_get_allocation (GTK_WIDGET (bin_child), &alloc);
+          y = alloc.y + alloc.height - 2;
+        }
+      else
+        {
+          bin_child = gtk_list_box_get_row_at_index (GTK_LIST_BOX (self->listbox), self->dnd_child_index);
+          gtk_widget_get_allocation (GTK_WIDGET (bin_child), &alloc);
+          y = alloc.y - 2;
+          if (y < 0)
+            y = 0;
+        }
+
+      gtk_render_background (style_context, cr, alloc.x, y, alloc.width, 4);
+      gtk_render_frame (style_context, cr, alloc.x, y, alloc.width, 4);
+    }
+
+  return FALSE;
+}
+
+static gboolean
+flowbox_draw_cb (GtkWidget           *flowbox,
+                 cairo_t             *cr,
+                 GstylePaletteWidget *self)
+{
+  GtkStyleContext *style_context;
+  GtkFlowBoxChild *bin_child;
+  GtkAllocation alloc;
+  gint len;
+  gint x;
+
+  g_assert (GSTYLE_IS_PALETTE_WIDGET (self));
+  g_assert (GTK_IS_FLOW_BOX (flowbox));
+
+  if (self->dnd_draw_highlight && self->dnd_child_index != -1)
+    {
+      style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+      gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_DND);
+
+      len = gstyle_palette_get_len (self->selected_palette);
+      if (self->dnd_child_index == len || self->is_dnd_at_end)
+        {
+          bin_child = gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (self->flowbox), self->dnd_child_index - 
1);
+          gtk_widget_get_allocation (GTK_WIDGET (bin_child), &alloc);
+          x = alloc.x + alloc.width - 2;
+        }
+      else
+        {
+          bin_child = gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (self->flowbox), self->dnd_child_index);
+          gtk_widget_get_allocation (GTK_WIDGET (bin_child), &alloc);
+          x = alloc.x - 2;
+          if (x < 0)
+            x = 0;
+        }
+
+      gtk_render_background (style_context, cr, x, alloc.y, 4, alloc.height);
+      gtk_render_frame (style_context, cr, x, alloc.y, 4, alloc.height);
+    }
+
+  return FALSE;
+}
+
+static void
+gstyle_palette_widget_finalize (GObject *object)
+{
+  GstylePaletteWidget *self = (GstylePaletteWidget *)object;
+
+  g_clear_object (&self->dnd_color);
+  g_clear_object (&self->placeholder);
+  g_clear_object (&self->default_provider);
+
+  bind_palette (self, NULL);
+  g_clear_object (&self->palettes);
+
+  G_OBJECT_CLASS (gstyle_palette_widget_parent_class)->finalize (object);
+}
+
+static void
+gstyle_palette_widget_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GstylePaletteWidget *self = GSTYLE_PALETTE_WIDGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_PLACEHOLDER:
+      g_value_set_object (value, gstyle_palette_widget_get_placeholder (self));
+      break;
+
+    case PROP_SELECTED_PALETTE_ID:
+      g_value_set_string (value, gstyle_palette_widget_get_selected_palette_id (self));
+      break;
+
+    case PROP_VIEW_MODE:
+      g_value_set_enum (value, gstyle_palette_widget_get_view_mode (self));
+      break;
+
+    case PROP_SORT_MODE:
+      g_value_set_enum (value, gstyle_palette_widget_get_sort_mode (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_palette_widget_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GstylePaletteWidget *self = GSTYLE_PALETTE_WIDGET (object);
+
+  switch (prop_id)
+    {
+    case PROP_PLACEHOLDER:
+      gstyle_palette_widget_set_placeholder (self, g_value_get_object (value));
+      break;
+
+    case PROP_SELECTED_PALETTE_ID:
+      gstyle_palette_widget_set_selected_palette_by_id (self, g_value_get_string (value));
+      break;
+
+    case PROP_VIEW_MODE:
+      gstyle_palette_widget_set_view_mode (self, g_value_get_enum (value));
+      break;
+
+    case PROP_SORT_MODE:
+      gstyle_palette_widget_set_sort_mode (self, g_value_get_enum (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_palette_widget_class_init (GstylePaletteWidgetClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gstyle_palette_widget_finalize;
+  object_class->get_property = gstyle_palette_widget_get_property;
+  object_class->set_property = gstyle_palette_widget_set_property;
+
+  widget_class->drag_motion = gstyle_palette_widget_on_drag_motion;
+  widget_class->drag_leave = gstyle_palette_widget_on_drag_leave;
+  widget_class->drag_drop = gstyle_palette_widget_on_drag_drop;
+  widget_class->drag_data_received = gstyle_palette_widget_on_drag_data_received;
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/libgstyle/ui/gstyle-palette-widget.ui");
+
+  gtk_widget_class_bind_template_child (widget_class, GstylePaletteWidget, view_stack);
+  gtk_widget_class_bind_template_child (widget_class, GstylePaletteWidget, placeholder_box);
+  gtk_widget_class_bind_template_child (widget_class, GstylePaletteWidget, listbox);
+  gtk_widget_class_bind_template_child (widget_class, GstylePaletteWidget, flowbox);
+
+  properties [PROP_PLACEHOLDER] =
+    g_param_spec_object ("placeholder",
+                         "placeholder",
+                         "placeholder GtkWidget",
+                         GTK_TYPE_WIDGET,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_SELECTED_PALETTE_ID] =
+    g_param_spec_string ("selected-palette-id",
+                         "selected-palette-id",
+                         "The selected palette id",
+                         "",
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY |G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_VIEW_MODE] =
+    g_param_spec_enum ("view-mode",
+                       "view-mode",
+                       "The view mode of the palettes",
+                       GSTYLE_TYPE_PALETTE_WIDGET_VIEW_MODE,
+                       GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST,
+                       (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_SORT_MODE] =
+    g_param_spec_enum ("sort-mode",
+                       "sort-mode",
+                       "The sort mode of the palettes",
+                       GSTYLE_TYPE_PALETTE_WIDGET_SORT_MODE,
+                       GSTYLE_PALETTE_WIDGET_SORT_MODE_ORIGINAL,
+                       (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  /**
+   * GstylePaletteWidget::activated:
+   * @self: A #GstylePaletteWidget
+   * @palette: a #GstylePalette
+   * @position: a position in the #palette
+   *
+   * This signal is emitted when you select a color in the palette widget.
+   */
+  signals [ACTIVATED] = g_signal_new ("activated",
+                                      G_TYPE_FROM_CLASS (klass),
+                                      G_SIGNAL_RUN_LAST,
+                                      0,
+                                      NULL, NULL, NULL,
+                                      G_TYPE_NONE,
+                                      2,
+                                      GSTYLE_TYPE_PALETTE,
+                                      G_TYPE_INT);
+
+  /**
+   * GstylePaletteWidget::palette-added:
+   * @self: A #GstylePaletteWidget
+   * @palette: a #GstylePalette
+   *
+   * This signal is emitted when a palette is added to the palette widget.
+   */
+  signals [PALETTE_ADDED] = g_signal_new ("palette-added",
+                                          G_TYPE_FROM_CLASS (klass),
+                                          G_SIGNAL_RUN_LAST,
+                                          0,
+                                          NULL, NULL, NULL,
+                                          G_TYPE_NONE,
+                                          1,
+                                          GSTYLE_TYPE_PALETTE);
+
+  /**
+   * GstylePaletteWidget::palette-removed:
+   * @self: A #GstylePaletteWidget
+   * @palette: a #GstylePalette
+   *
+   * This signal is emitted when a palette is removed to the palette widget.
+   */
+  signals [PALETTE_REMOVED] = g_signal_new ("palette-removed",
+                                            G_TYPE_FROM_CLASS (klass),
+                                            G_SIGNAL_RUN_LAST,
+                                            0,
+                                            NULL, NULL, NULL,
+                                            G_TYPE_NONE,
+                                            1,
+                                            GSTYLE_TYPE_PALETTE);
+
+  gtk_widget_class_set_css_name (widget_class, "gstylepalettewidget");
+}
+
+static void
+gstyle_palette_widget_init (GstylePaletteWidget *self)
+{
+  GtkStyleContext *context;
+
+  static const GtkTargetEntry dnd_targets [] = {
+    {"GSTYLE_COLOR_WIDGET", GTK_TARGET_SAME_APP, 0},
+  };
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  self->view_mode = GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST;
+  gtk_stack_set_visible_child_name (self->view_stack, "list");
+
+  self->palettes = g_list_store_new (GSTYLE_TYPE_PALETTE);
+
+  gstyle_palette_widget_add_actions (self);
+
+  g_signal_connect_swapped (self->listbox,
+                            "row-activated",
+                            G_CALLBACK (gstyle_palette_widget_color_row_activated),
+                            self);
+
+  g_signal_connect_after (self->listbox,
+                          "draw",
+                          G_CALLBACK (listbox_draw_cb),
+                          self);
+
+  g_signal_connect_swapped (self->flowbox,
+                            "child-activated",
+                            G_CALLBACK (gstyle_palette_widget_color_swatch_activated),
+                            self);
+
+  g_signal_connect_after (self->flowbox,
+                          "draw",
+                          G_CALLBACK (flowbox_draw_cb),
+                          self);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  self->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
+
+  gtk_drag_dest_set (GTK_WIDGET (self), 0,
+                     dnd_targets, G_N_ELEMENTS (dnd_targets),
+                     GDK_ACTION_COPY);
+
+  gtk_drag_dest_set_track_motion (GTK_WIDGET (self), TRUE);
+
+  self->dnd_color = gstyle_color_new ("placeholder", GSTYLE_COLOR_KIND_RGBA, 210, 210, 210, 100);
+  self->dnd_child_index = -1;
+}
+
+GType
+gstyle_palette_widget_view_mode_get_type (void)
+{
+  static GType view_mode_type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST,    "GSTYLE_PALETTE_WIDGET__VIEW_MODE_LIST",    "list" },
+    { GSTYLE_PALETTE_WIDGET_VIEW_MODE_SWATCHS, "GSTYLE_PALETTE_WIDGET__VIEW_MODE_SWATCHS", "swatchs" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&view_mode_type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstylePaletteWidgetViewMode", values);
+      g_once_init_leave (&view_mode_type_id, _type_id);
+    }
+
+  return view_mode_type_id;
+}
+
+GType
+gstyle_palette_widget_sort_mode_get_type (void)
+{
+  static GType sort_mode_type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_PALETTE_WIDGET_SORT_MODE_ORIGINAL,   "GSTYLE_PALETTE_WIDGET_SORT_MODE_ORIGINAL",   "original" },
+    { GSTYLE_PALETTE_WIDGET_SORT_MODE_LIGHT,      "GSTYLE_PALETTE_WIDGET_SORT_MODE_LIGHT",      "light" },
+    { GSTYLE_PALETTE_WIDGET_SORT_MODE_APPROCHING, "GSTYLE_PALETTE_WIDGET_SORT_MODE_APPROCHING", "approching" 
},
+    { 0 }
+  };
+
+  if (g_once_init_enter (&sort_mode_type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstylePaletteWidgetSortMode", values);
+      g_once_init_leave (&sort_mode_type_id, _type_id);
+    }
+
+  return sort_mode_type_id;
+}
diff --git a/contrib/gstyle/gstyle-palette-widget.h b/contrib/gstyle/gstyle-palette-widget.h
new file mode 100644
index 0000000..177880b
--- /dev/null
+++ b/contrib/gstyle/gstyle-palette-widget.h
@@ -0,0 +1,83 @@
+/* gstyle-palette-widget.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_PALETTE_WIDGET_H
+#define GSTYLE_PALETTE_WIDGET_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-palette.h"
+#include "gstyle-types.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_PALETTE_WIDGET (gstyle_palette_widget_get_type())
+#define GSTYLE_TYPE_PALETTE_WIDGET_VIEW_MODE (gstyle_palette_widget_view_mode_get_type())
+#define GSTYLE_TYPE_PALETTE_WIDGET_SORT_MODE (gstyle_palette_widget_sort_mode_get_type())
+
+G_DECLARE_FINAL_TYPE (GstylePaletteWidget, gstyle_palette_widget, GSTYLE, PALETTE_WIDGET, GtkBin)
+
+typedef enum
+{
+  GSTYLE_PALETTE_WIDGET_VIEW_MODE_LIST,
+  GSTYLE_PALETTE_WIDGET_VIEW_MODE_SWATCHS
+} GstylePaletteWidgetViewMode;
+
+typedef enum
+{
+  GSTYLE_PALETTE_WIDGET_SORT_MODE_ORIGINAL,
+  GSTYLE_PALETTE_WIDGET_SORT_MODE_LIGHT,
+  GSTYLE_PALETTE_WIDGET_SORT_MODE_APPROCHING
+} GstylePaletteWidgetSortMode;
+
+GType                            gstyle_palette_widget_view_mode_get_type    (void);
+GType                            gstyle_palette_widget_sort_mode_get_type    (void);
+
+gboolean                         gstyle_palette_widget_add                   (GstylePaletteWidget         
*self,
+                                                                              GstylePalette               
*palette);
+GList                           *gstyle_palette_widget_get_list              (GstylePaletteWidget         
*self);
+gint                             gstyle_palette_widget_get_n_palettes        (GstylePaletteWidget         
*self);
+GstylePalette                   *gstyle_palette_widget_get_palette_at_index  (GstylePaletteWidget         
*self,
+                                                                              guint                        
index);
+GstylePalette                   *gstyle_palette_widget_get_palette_by_id     (GstylePaletteWidget         
*self,
+                                                                              const gchar                 
*id);
+GtkWidget                       *gstyle_palette_widget_get_placeholder       (GstylePaletteWidget         
*self);
+GstylePalette                   *gstyle_palette_widget_get_selected_palette  (GstylePaletteWidget         
*self);
+GstylePaletteWidgetSortMode      gstyle_palette_widget_get_sort_mode         (GstylePaletteWidget         
*self);
+GListStore                      *gstyle_palette_widget_get_store             (GstylePaletteWidget         
*self);
+GstylePaletteWidgetViewMode      gstyle_palette_widget_get_view_mode         (GstylePaletteWidget         
*self);
+gboolean                         gstyle_palette_widget_remove                (GstylePaletteWidget         
*self,
+                                                                              GstylePalette               
*palette);
+void                             gstyle_palette_widget_remove_all            (GstylePaletteWidget         
*self);
+gboolean                         gstyle_palette_widget_remove_by_id          (GstylePaletteWidget         
*self,
+                                                                              const gchar                 
*id);
+void                             gstyle_palette_widget_set_placeholder       (GstylePaletteWidget         
*self,
+                                                                              GtkWidget                   
*placeholder);
+void                             gstyle_palette_widget_set_sort_mode         (GstylePaletteWidget         
*self,
+                                                                              GstylePaletteWidgetSortMode  
mode);
+void                             gstyle_palette_widget_set_view_mode         (GstylePaletteWidget         
*self,
+                                                                              GstylePaletteWidgetViewMode  
mode);
+gboolean                         gstyle_palette_widget_show_palette          (GstylePaletteWidget         
*self,
+                                                                              GstylePalette               
*palette);
+GstylePaletteWidget             *gstyle_palette_widget_new                   (void);
+
+G_END_DECLS
+
+#endif /* GSTYLE_PALETTE_WIDGET_H */
+
diff --git a/contrib/gstyle/gstyle-palette.c b/contrib/gstyle/gstyle-palette.c
new file mode 100644
index 0000000..b25e973
--- /dev/null
+++ b/contrib/gstyle/gstyle-palette.c
@@ -0,0 +1,1134 @@
+/* gstyle-palette.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-palette"
+
+#include <glib/gi18n.h>
+#include <string.h>
+
+#include "gstyle-private.h"
+#include "gstyle-palette.h"
+
+#define XML_TO_CHAR(s)  ((char *) (s))
+#define CHAR_TO_XML(s)  ((unsigned char *) (s))
+
+#define GSTYLE_PALETTE_ID_CHARSET "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
+
+struct _GstylePalette
+{
+  GObject     parent_instance;
+
+  GPtrArray  *colors;
+  GHashTable *color_names;
+  gchar      *id;
+  gchar      *name;
+  GFile      *file;
+};
+
+static void gstyle_palette_list_model_iface_init (GListModelInterface *iface);
+
+G_DEFINE_QUARK (gstyle_palette_error, gstyle_palette_error)
+
+G_DEFINE_TYPE_WITH_CODE (GstylePalette, gstyle_palette, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gstyle_palette_list_model_iface_init));
+
+enum {
+  PROP_0,
+  PROP_ID,
+  PROP_NAME,
+  PROP_FILE,
+  PROP_COLORS,
+  PROP_LEN,
+  N_PROPS
+};
+
+static inline gchar *
+strdup_and_xmlfree (xmlChar *xml_str)
+{
+  gchar *res = NULL;
+
+  if (xml_str != NULL)
+    {
+      res = g_strdup ((char *)xml_str);
+      xmlFree(xml_str);
+    }
+
+  return res;
+}
+
+static void
+gstyle_palette_error_cb (void                    *arg,
+                         const char              *msg,
+                         xmlParserSeverities      severity,
+                         xmlTextReaderLocatorPtr  locator)
+{
+  g_warning ("Parse error at line %i:\n%s\n",
+             xmlTextReaderLocatorLineNumber (locator),
+             msg);
+}
+
+static GParamSpec *properties [N_PROPS];
+
+static gboolean
+gstyle_palette_xml_get_header (xmlTextReaderPtr   reader,
+                               gchar            **id,
+                               gchar            **name)
+{
+  g_assert (reader != NULL);
+  g_assert (id != NULL);
+  g_assert (name != NULL);
+
+  *id = *name = NULL;
+  if (xmlTextReaderRead(reader) == 1 &&
+      xmlTextReaderNodeType (reader) == XML_READER_TYPE_ELEMENT &&
+      !g_strcmp0 (XML_TO_CHAR (xmlTextReaderConstName (reader)), "palette") &&
+      xmlTextReaderDepth (reader) == 0)
+    {
+      *id = strdup_and_xmlfree (xmlTextReaderGetAttribute (reader, CHAR_TO_XML ("id")));
+      *name = strdup_and_xmlfree (xmlTextReaderGetAttribute (reader, CHAR_TO_XML ("_name")));
+      if (gstyle_str_empty0 (*id) || gstyle_utf8_is_spaces (*id))
+        {
+          g_warning ("Palette '%s'has an empty or NULL id\n", *name);
+          return FALSE;
+        }
+
+      if (gstyle_utf8_is_spaces (*name))
+        g_clear_pointer (name, g_free);
+    }
+
+  return (*id != NULL);
+}
+
+static GstyleColor *
+gstyle_palette_xml_get_color (xmlTextReaderPtr reader)
+{
+  GstyleColor *color = NULL;
+  g_autofree gchar *name;
+  g_autofree gchar *value;
+
+  g_assert (reader != NULL);
+
+  if (xmlTextReaderNodeType (reader) == XML_READER_TYPE_ELEMENT &&
+      !g_strcmp0 (XML_TO_CHAR (xmlTextReaderConstName (reader)), "color") &&
+      xmlTextReaderDepth (reader) == 1)
+    {
+      name = strdup_and_xmlfree (xmlTextReaderGetAttribute (reader, CHAR_TO_XML ("name")));
+      if (gstyle_utf8_is_spaces (name))
+        g_clear_pointer (&name, g_free);
+
+      value = strdup_and_xmlfree (xmlTextReaderGetAttribute (reader, CHAR_TO_XML ("value")));
+      if (!gstyle_str_empty0 (value))
+        color = gstyle_color_new_from_string (name, value);
+    }
+
+  return color;
+}
+
+/**
+ * gstyle_palette_get_colors:
+ * @self: a #GstylePalette
+ *
+ *  Return an array of colors contained in the palette.
+ *
+ * Returns: (transfer none) (element-type GstyleColor): a #GPtrArray of #GstyleColor.
+ */
+GPtrArray *
+gstyle_palette_get_colors (GstylePalette  *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), NULL);
+
+  return self->colors;
+}
+
+/**
+ * gstyle_palette_get_color_at_index:
+ * @self: a #GstylePalette
+ * @index: position of the #GstyleColor to get
+ *
+ *  Return the #gstyleColor at @index position
+ * or %NULL if the index is out of bounds.
+ *
+ * Returns: (transfer none) (nullable): a #GstyleColor.
+ */
+const GstyleColor *
+gstyle_palette_get_color_at_index (GstylePalette  *self,
+                                   guint           index)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), NULL);
+  g_return_val_if_fail (index < self->colors->len, NULL);
+
+  return g_ptr_array_index (self->colors, index);
+}
+
+/* TODO: add an unnamed category ? */
+static gboolean
+add_color_to_names_sets (GstylePalette *self,
+                         GstyleColor   *color)
+{
+  const gchar *name;
+  GPtrArray *set;
+
+  g_assert (GSTYLE_IS_PALETTE (self));
+  g_assert (GSTYLE_IS_COLOR (color));
+
+  name = gstyle_color_get_name (color);
+  if (gstyle_str_empty0 (name))
+    return FALSE;
+
+  set = g_hash_table_lookup (self->color_names, name);
+  if (set == NULL)
+    {
+      set = g_ptr_array_new ();
+      g_hash_table_insert (self->color_names, (gpointer)name, set);
+    }
+
+  g_ptr_array_add (set, color);
+  return TRUE;
+}
+
+static gboolean
+remove_color_to_names_sets (GstylePalette *self,
+                            GstyleColor   *color)
+{
+  const gchar *name;
+  GPtrArray *set;
+  gboolean ret = FALSE;
+
+  g_assert (GSTYLE_IS_PALETTE (self));
+  g_assert (GSTYLE_IS_COLOR (color));
+
+  name = gstyle_color_get_name (color);
+  if (gstyle_str_empty0 (name))
+    return FALSE;
+
+  set = g_hash_table_lookup (self->color_names, name);
+  if (set == NULL)
+    return FALSE;
+
+  ret = g_ptr_array_remove (set, color);
+  if (set->len == 0)
+    {
+      g_ptr_array_unref (set);
+      g_hash_table_remove (self->color_names, name);
+    }
+
+  return ret;
+}
+
+/**
+ * gstyle_palette_add_at_index:
+ * @self: a #GstylePalette
+ * @color: A #GstyleColor
+ * @position: Position to insert the new color, from 0 to gstyle_palette_get_len() -1,
+ *   or -1 to append it
+ * @error: (nullable): a #GError location or %NULL
+ *
+ * Add a #GstyleColor to the palette.
+ *
+ * Returns: %TRUE on succes, %FALSE otherwise.
+ */
+gboolean
+gstyle_palette_add_at_index (GstylePalette  *self,
+                             GstyleColor    *color,
+                             gint            position,
+                             GError        **error)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), FALSE);
+  g_return_val_if_fail (GSTYLE_IS_COLOR (color), FALSE);
+
+  /* If we are just after the last position, we in fact do an append */
+  if (position == self->colors->len)
+    position = -1;
+
+  if (position == -1 ||
+      (position == 0 && self->colors->len == 0) ||
+      (0 <= position && position < self->colors->len))
+    {
+      g_object_ref (color);
+      g_ptr_array_insert (self->colors, position, color);
+      add_color_to_names_sets (self, color);
+
+      position = (position == -1) ? self->colors->len - 1 : position;
+      g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
+
+      return TRUE;
+    }
+  else
+    {
+      g_warning ("Color inserted in palette '%s' at out-of-bounds position %i in (0, %i)\n",
+                 gstyle_palette_get_name (self),
+                 position, self->colors->len - 1);
+
+      return FALSE;
+     }
+}
+
+/**
+ * gstyle_palette_add:
+ * @self: a #GstylePalette
+ * @color: A #GstyleColor
+ * @error: (nullable): a #GError location or %NULL
+ *
+ * Add a #GstyleColor to the palette.
+ *
+ * Returns: %TRUE on succes, %FALSE otherwise.
+ */
+gboolean
+gstyle_palette_add (GstylePalette  *self,
+                    GstyleColor    *color,
+                    GError        **error)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), FALSE);
+  g_return_val_if_fail (GSTYLE_IS_COLOR (color), FALSE);
+
+  return gstyle_palette_add_at_index (self, color, -1, error);
+}
+
+/**
+ * gstyle_palette_remove_at_index:
+ * @self: a #GstylePalette
+ * @position: A position to remove the #GstyleColor from
+ *
+ * Try to remove the #GstyleColor at @position from the palette
+ *
+ * Returns: %TRUE on succes, %FALSE otherwise.
+ */
+gboolean
+gstyle_palette_remove_at_index (GstylePalette  *self,
+                                gint            position)
+{
+  GstyleColor *color;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), FALSE);
+
+  if (0 <= position && position < self->colors->len)
+    {
+      color = GSTYLE_COLOR (g_ptr_array_index (self->colors, position));
+      remove_color_to_names_sets (self, color);
+      g_ptr_array_remove_index (self->colors, position);
+      g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
+
+      return TRUE;
+    }
+  else
+    {
+      g_warning ("Trying to remove a Color in palette '%s' at out-of-bounds position %i in (0, %i)\n",
+                 gstyle_palette_get_name (self),
+                 position, self->colors->len - 1);
+
+      return FALSE;
+     }
+}
+
+/**
+ * gstyle_palette_remove:
+ * @self: a #GstylePalette
+ * @color: A #GstyleColor
+ *
+ * Try to remove a #GstyleColor from the palette.
+ *
+ * Returns: %TRUE on succes, %FALSE otherwise.
+ */
+gboolean
+gstyle_palette_remove (GstylePalette  *self,
+                       GstyleColor    *color)
+{
+  GPtrArray *array;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), FALSE);
+  g_return_val_if_fail (GSTYLE_IS_COLOR (self), FALSE);
+
+  array = self->colors;
+  for (gint i = 0; i < array->len; ++i)
+    {
+      if (array->pdata[i] == color)
+        {
+          remove_color_to_names_sets (self, color);
+          g_ptr_array_remove_index (array, i);
+          g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
+
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+/**
+ * gstyle_palette_lookup:
+ * @self: a #GstylePalette
+ * @name: A #GstyleColor name
+ *
+ * Search for one or several #GstyleColor named @name in the palette.
+ *
+ * Returns: (transfer none) (nullable) (element-type GstyleColor): a #GstyleColor pointer array.
+ */
+GPtrArray *
+gstyle_palette_lookup (GstylePalette  *self,
+                       const gchar    *name)
+{
+  GPtrArray *set;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), NULL);
+  g_return_val_if_fail (!gstyle_str_empty0 (name), NULL);
+
+  set = g_hash_table_lookup (self->color_names, name);
+
+  return set;
+}
+
+/**
+ * gstyle_palette_get_index:
+ * @self: a #GstylePalette
+ * @color: A #GstyleColor
+ *
+ * Search for a #GstyleColor in the palette and
+ * return its index or -1 if not found.
+ *
+ * Returns: An index in the palette or -1.
+ */
+gint
+gstyle_palette_get_index (GstylePalette  *self,
+                          GstyleColor    *color)
+{
+  guint len;
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), -1);
+  g_return_val_if_fail (GSTYLE_COLOR (color), -1);
+
+  len = self->colors->len;
+  for (gint i = 0; i < len; i++)
+    if (color == g_ptr_array_index (self->colors, i))
+      return i;
+
+  return -1;
+}
+
+/* We skip commented lines and not prefixed by prefix if not NULL */
+static gchar *
+read_gpl_line (GDataInputStream  *stream,
+               GError           **error,
+               const gchar       *prefix)
+{
+  gchar *line;
+
+  g_assert (G_IS_INPUT_STREAM (stream));
+
+  while ((line = g_data_input_stream_read_line_utf8 (stream, NULL, NULL, error)))
+    {
+      g_strchug (line);
+      if (*line == '#' || (prefix != NULL && !g_str_has_prefix (line, prefix)))
+        g_free (line);
+      else
+        break;
+    }
+
+  return line;
+}
+
+static gboolean
+read_gpl_header (GDataInputStream   *stream,
+                 gchar             **palette_name,
+                 gint               *line_count,
+                 GError            **error)
+{
+  gchar *line;
+
+  g_assert (G_IS_INPUT_STREAM (stream));
+  g_assert (palette_name != NULL);
+  g_assert (line_count != NULL);
+
+  if ((line = read_gpl_line (stream, error, "GIMP Palette")))
+    {
+      g_free (line);
+      ++(*line_count);
+      line = read_gpl_line (stream, error, "Name:");
+      if (line != NULL && g_str_has_prefix (line, "Name:"))
+        {
+          *palette_name = g_strdup (g_strstrip (&line[5]));
+          if (gstyle_utf8_is_spaces (*palette_name))
+            g_clear_pointer (palette_name, g_free);
+
+          g_free (line);
+
+          return TRUE;
+        }
+    }
+
+  g_set_error (error, GSTYLE_PALETTE_ERROR, GSTYLE_PALETTE_ERROR_PARSE,
+               _("failed to parse line %i\n"), *line_count);
+
+  return FALSE;
+}
+
+static gboolean
+read_gpl_color_line (GDataInputStream  *stream,
+                     GdkRGBA           *rgba,
+                     gchar            **name,
+                     gint              *line_count,
+                     GError           **error)
+{
+  gchar *line;
+  gchar *cursor;
+  gchar *end;
+  gint value;
+
+  g_assert (G_IS_INPUT_STREAM (stream));
+  g_assert (rgba != NULL);
+  g_assert (name != NULL);
+  g_assert (line_count != NULL);
+
+  ++(*line_count);
+  while ((line = read_gpl_line (stream, error, NULL)))
+    if (*line >= '0' && *line <= '9')
+      break;
+    else
+    {
+      g_free (line);
+      ++(*line_count);
+    }
+
+  if (line == NULL)
+    return FALSE;
+
+  cursor = line;
+
+  rgba->alpha = 1.0;
+  value = strtol (cursor, &end, 10);
+  if (end != cursor && value >= 0 && value <= 255)
+    {
+      rgba->red = value / 255.0;
+      cursor = end;
+      value = strtol (cursor, &end, 10);
+      if (end != cursor && value >= 0 && value <= 255)
+        {
+          rgba->green = value / 255.0;
+          cursor = end;
+          value = strtol (cursor, &end, 10);
+          if (end != cursor && value >= 0 && value <= 255)
+            {
+              rgba->blue = value / 255.0;
+              cursor = end;
+              cursor = g_strstrip (cursor);
+              if (*cursor != '\0')
+                *name = g_strdup (cursor);
+              else
+                *name = NULL;
+
+              g_free (line);
+              return TRUE;
+            }
+        }
+    }
+
+  g_set_error (error, GSTYLE_PALETTE_ERROR, GSTYLE_PALETTE_ERROR_PARSE,
+               _("failed to parse line %i\n"), *line_count);
+
+  g_free (line);
+  return FALSE;
+}
+
+static GstylePalette *
+gstyle_palette_new_from_gpl (GFile         *file,
+                             GCancellable  *cancellable,
+                             GError       **error)
+{
+  g_autoptr(GDataInputStream) data_stream = NULL;
+  g_autoptr (GInputStream) stream = NULL;
+  GstylePalette *palette = NULL;
+  g_autofree gchar *palette_name = NULL;
+  g_autofree gchar *id = NULL;
+  GstyleColor *color;
+  gchar *color_name;
+  GdkRGBA rgba;
+  GError *tmp_error = NULL;
+  gint line_count = 1;
+  gboolean has_colors = FALSE;
+
+  g_assert (G_IS_FILE (file));
+
+  if ((stream = G_INPUT_STREAM (g_file_read (file, cancellable, &tmp_error))))
+    {
+      data_stream = g_data_input_stream_new (stream);
+      if (read_gpl_header (data_stream, &palette_name, &line_count, &tmp_error))
+        {
+          id = g_strcanon (g_strdup (palette_name), GSTYLE_PALETTE_ID_CHARSET, '_');
+          palette = g_object_new (GSTYLE_TYPE_PALETTE,
+                                 "id", id,
+                                 "name", palette_name,
+                                 "file", file,
+                                 NULL);
+
+          while (read_gpl_color_line (data_stream, &rgba, &color_name, &line_count, &tmp_error))
+            {
+              has_colors = TRUE;
+              color = gstyle_color_new_from_rgba (color_name, GSTYLE_COLOR_KIND_RGB_HEX6, &rgba);
+              gstyle_palette_add (palette, color, &tmp_error);
+              g_object_unref (color);
+              g_free (color_name);
+              if (tmp_error != NULL)
+                break;
+            }
+        }
+    }
+
+  if (tmp_error == NULL && !has_colors)
+    {
+      g_autofree gchar *uri = g_file_get_uri (file);
+
+      g_set_error (&tmp_error, GSTYLE_PALETTE_ERROR, GSTYLE_PALETTE_ERROR_EMPTY,
+                   _("%s : palette is empty\n"), uri);
+    }
+
+  if (tmp_error != NULL)
+    {
+      g_clear_object (&palette);
+      g_propagate_error (error, tmp_error);
+    }
+
+  return palette;
+}
+
+static int
+gstyle_palette_io_read_cb (void *user_data,
+                           char *buffer,
+                           int   len)
+{
+  g_assert (G_IS_INPUT_STREAM(user_data));
+  g_assert (buffer != NULL);
+
+  return g_input_stream_read ((GInputStream *)user_data, buffer, len, NULL, NULL);
+}
+
+static int
+gstyle_palette_io_close_cb (void *user_data)
+{
+  g_assert (G_IS_INPUT_STREAM(user_data));
+
+  return g_input_stream_close ((GInputStream *)user_data, NULL, NULL) ? 0 : -1;
+}
+
+static GstylePalette *
+gstyle_palette_new_from_xml (GFile         *file,
+                             GCancellable  *cancellable,
+                             GError       **error)
+{
+  g_autoptr(GInputStream) stream = NULL;
+  g_autofree gchar *uri = NULL;
+  GstylePalette *palette = NULL;
+  xmlTextReaderPtr reader;
+  GError *tmp_error = NULL;
+  gboolean has_colors = FALSE;
+  gint ret = -1;
+
+  g_assert (G_IS_FILE (file));
+
+  uri = g_file_get_uri (file);
+
+  if (!(stream = G_INPUT_STREAM (g_file_read (file, cancellable, &tmp_error))))
+    goto finish;
+
+  reader = xmlReaderForIO (gstyle_palette_io_read_cb,
+                           gstyle_palette_io_close_cb,
+                           stream,
+                           uri,
+                           NULL,
+                           XML_PARSE_RECOVER | XML_PARSE_NOBLANKS | XML_PARSE_COMPACT);
+
+  if (reader != NULL)
+    {
+      GstyleColor *color;
+      g_autofree gchar *id = NULL;
+      g_autofree gchar *name = NULL;
+
+      xmlTextReaderSetErrorHandler (reader, gstyle_palette_error_cb, NULL);
+
+      if (xmlTextReaderRead(reader) &&
+          gstyle_palette_xml_get_header (reader, &id, &name))
+        {
+          palette = g_object_new (GSTYLE_TYPE_PALETTE,
+                                  "id", id,
+                                  "name", name,
+                                  "file", file,
+                                  NULL);
+
+          ret = xmlTextReaderRead(reader);
+          while (ret == 1)
+            {
+              if (xmlTextReaderNodeType (reader) == XML_READER_TYPE_END_ELEMENT)
+                {
+                  ret = 0;
+                  break;
+                }
+
+              /* TODO: better naming */
+              color = gstyle_palette_xml_get_color (reader);
+              if (color == NULL)
+                {
+                  ret = -1;
+                  break;
+                }
+
+              gstyle_palette_add (palette, color, &tmp_error);
+              g_object_unref (color);
+              has_colors = TRUE;
+
+              ret = xmlTextReaderRead(reader);
+            }
+        }
+
+      if (ret != 0 || !has_colors)
+        {
+          g_clear_object (&palette);
+          g_set_error (&tmp_error, GSTYLE_PALETTE_ERROR, GSTYLE_PALETTE_ERROR_PARSE,
+                       _("%s : failed to parse\n"), uri);
+        }
+
+      xmlTextReaderClose(reader);
+      xmlFreeTextReader(reader);
+    }
+  else
+    g_set_error (&tmp_error, GSTYLE_PALETTE_ERROR, GSTYLE_PALETTE_ERROR_FILE,
+                 _("Unable to open %s\n"), uri);
+
+finish:
+
+  if (tmp_error)
+    g_propagate_error (error, tmp_error);
+
+  return palette;
+}
+
+/**
+ * gstyle_palette_new_from_file:
+ * @file: a #GFile
+ * @cancellable: A #GCancellable
+ * @error: (nullable): a #GError location or %NULL
+ *
+ * Load a palette from an .xml or .gpl file.
+ *
+ * Returns: A #GstylePalette.
+ */
+GstylePalette *
+gstyle_palette_new_from_file (GFile         *file,
+                              GCancellable  *cancellable,
+                              GError       **error)
+{
+  GstylePalette *palette = NULL;
+  g_autofree gchar *uri = NULL;
+  GError *tmp_error = NULL;
+
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  uri = g_file_get_uri (file);
+  if (g_str_has_suffix (uri, "xml"))
+    palette = gstyle_palette_new_from_xml (file, cancellable, &tmp_error);
+  else if (g_str_has_suffix (uri, "gpl"))
+    palette = gstyle_palette_new_from_gpl (file, cancellable, &tmp_error);
+  else
+    g_set_error (&tmp_error, GSTYLE_PALETTE_ERROR, GSTYLE_PALETTE_ERROR_FORMAT,
+                 _("%s : This file format is not supported\n"), uri);
+
+  /* TODO: check for duplicated color names */
+
+  if (tmp_error)
+    g_propagate_error (error, tmp_error);
+
+  return palette;
+}
+
+/**
+ * gstyle_palette_save_to_xml:
+ * @self: a #GstylePalette
+ * @file: a #GFile
+ * @error: (nullable): a #GError location or %NULL
+ *
+ * Save a palette to Gnome-Builder .xml palette format.
+ *
+ * Returns: %TRUE if succesfull, %FALSE otherwise.
+ */
+gboolean
+gstyle_palette_save_to_xml (GstylePalette  *self,
+                            GFile          *file,
+                            GError        **error)
+{
+  g_autofree gchar *file_path = NULL;
+  const gchar *id;
+  const gchar *name;
+  xmlDocPtr doc;
+  xmlNodePtr root_node;
+  xmlNodePtr palette_node;
+  xmlNodePtr color_node;
+  gint n_colors;
+  gint succes;
+
+  gchar *header = "Copyright (C) 2016 GNOME Builder Team at irc.gimp.net/#gnome-builder\n" \
+                  "This program is free software: you can redistribute it and/or modify\n" \
+                  "it under the terms of the GNU General Public License as published by\n" \
+                  "the Free Software Foundation, either version 3 of the License, or\n"    \
+                  "(at your option) any later version.\n\n"                                \
+                  "This program is distributed in the hope that it will be useful,\n"      \
+                  "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"       \
+                  "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"        \
+                  "GNU General Public License for more details.\n\n"                       \
+                  "You should have received a copy of the GNU General Public License\n"    \
+                  "along with this program.  If not, see <http://www.gnu.org/licenses/>\n";
+
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), FALSE);
+  g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+  doc = xmlNewDoc(CHAR_TO_XML ("1.0"));
+  root_node = xmlNewDocComment (doc, CHAR_TO_XML (header));
+  xmlDocSetRootElement(doc, root_node);
+  palette_node = xmlNewNode (NULL, CHAR_TO_XML ("palette"));
+  xmlAddSibling (root_node, palette_node);
+
+  id = gstyle_palette_get_id (self);
+  name = gstyle_palette_get_name (self);
+  xmlNewProp (palette_node, CHAR_TO_XML ("id"), CHAR_TO_XML (id));
+  xmlNewProp (palette_node, CHAR_TO_XML ("_name"), CHAR_TO_XML (name));
+
+  n_colors = gstyle_palette_get_len (self);
+  for (gint i = 0; i < n_colors; ++i)
+    {
+      const GstyleColor *color;
+      const gchar *color_name;
+      g_autofree gchar *color_string = NULL;
+
+      color = gstyle_palette_get_color_at_index (self, i);
+      color_name = gstyle_color_get_name ((GstyleColor *)color);
+
+      if (gstyle_color_get_kind ((GstyleColor *)color) == GSTYLE_COLOR_KIND_PREDEFINED)
+        color_string = gstyle_color_to_string ((GstyleColor *)color, GSTYLE_COLOR_KIND_RGB_HEX6);
+      else
+        color_string = gstyle_color_to_string ((GstyleColor *)color, GSTYLE_COLOR_KIND_ORIGINAL);
+
+      color_node = xmlNewChild (palette_node, NULL, CHAR_TO_XML ("color"), NULL);
+      xmlNewProp (color_node, CHAR_TO_XML ("name"), CHAR_TO_XML (color_name));
+      xmlNewProp (color_node, CHAR_TO_XML ("value"), CHAR_TO_XML (color_string));
+    }
+
+  file_path = g_file_get_path (file);
+  succes = xmlSaveFormatFileEnc (file_path, doc, "UTF-8", 1);
+  xmlFreeDoc(doc);
+
+  if (succes == -1)
+    {
+      g_set_error (error, GSTYLE_PALETTE_ERROR, GSTYLE_PALETTE_ERROR_FILE,
+                   _("Unable to save %s\n"), file_path);
+
+      return FALSE;
+    }
+  else
+    return TRUE;
+}
+
+/**
+ * gstyle_palette_set_name:
+ * @self: a #GstylePalette
+ * @name: palette name
+ *
+ */
+void
+gstyle_palette_set_name (GstylePalette *self,
+                         const gchar   *name)
+{
+  g_return_if_fail (GSTYLE_IS_PALETTE (self));
+
+  if (g_strcmp0 (self->name, name) != 0)
+    {
+      g_free (self->name);
+      self->name = g_strdup (name);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_NAME]);
+    }
+}
+
+/**
+ * gstyle_palette_set_id:
+ * @self: a #GstylePalette
+ * @id: palette id
+ *
+ */
+void
+gstyle_palette_set_id (GstylePalette *self,
+                       const gchar   *id)
+{
+  gint64 num_id;
+
+  g_return_if_fail (GSTYLE_IS_PALETTE (self));
+
+  g_free (self->id);
+  if (gstyle_str_empty0 (id))
+    {
+      num_id = g_get_real_time ();
+      self->id = g_strdup_printf ("gb-cp-%lu", num_id);
+    }
+  else if (g_strcmp0 (self->id, id) != 0)
+    self->id = g_strdup (id);
+}
+
+/**
+ * gstyle_palette_get_name:
+ * @self: a #GstylePalette
+ *
+ * Return the name of the palette.
+ *
+ * Returns: The palette's name.
+ */
+const gchar *
+gstyle_palette_get_name (GstylePalette *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), NULL);
+
+  return self->name;
+}
+
+/**
+ * gstyle_palette_get_id:
+ * @self: a #GstylePalette
+ *
+ * Return the palette id.
+ *
+ *
+ * Returns: The palette id string.
+ */
+const gchar *
+gstyle_palette_get_id (GstylePalette *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), NULL);
+
+  return self->id;
+}
+
+/**
+ * gstyle_palette_get_file:
+ * @self: a #GstylePalette
+ *
+ * Return the #GFile used to create the palette.
+ *
+ *
+ * Returns: (transfer full): a #GFile.
+ */
+GFile *
+gstyle_palette_get_file (GstylePalette *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), NULL);
+
+  return self->file;
+}
+
+/**
+ * gstyle_palette_get_len:
+ * @self: a #GstylePalette
+ *
+ * Return The number of colors in the palette.
+ *
+ *
+ * Returns: Palette's length.
+ */
+guint
+gstyle_palette_get_len (GstylePalette *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_PALETTE (self), 0);
+
+  return self->colors->len;
+}
+
+GstylePalette *
+gstyle_palette_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_PALETTE, NULL);
+}
+
+static void
+gstyle_palette_finalize (GObject *object)
+{
+  GstylePalette *self = GSTYLE_PALETTE (object);
+
+  g_ptr_array_unref (self->colors);
+  g_hash_table_unref (self->color_names);
+
+  g_free (self->name);
+  g_free (self->id);
+  g_clear_object (&self->file);
+
+  G_OBJECT_CLASS (gstyle_palette_parent_class)->finalize (object);
+}
+
+static void
+gstyle_palette_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  GstylePalette *self = GSTYLE_PALETTE (object);
+
+  switch (prop_id)
+    {
+    case PROP_ID:
+      g_value_set_string (value, self->id);
+      break;
+
+    case PROP_NAME:
+      g_value_set_string (value, self->name);
+      break;
+
+    case PROP_FILE:
+      g_value_set_object (value, self->file);
+      break;
+
+    case PROP_COLORS:
+      g_value_set_object (value, self->colors);
+      break;
+
+    case PROP_LEN:
+      g_value_set_uint (value, self->colors->len);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_palette_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  GstylePalette *self = GSTYLE_PALETTE (object);
+  GFile *file;
+
+  switch (prop_id)
+    {
+    case PROP_ID:
+      gstyle_palette_set_id (self, g_value_get_string (value));
+      break;
+
+    case PROP_NAME:
+      gstyle_palette_set_name (self, g_value_get_string (value));
+      break;
+
+    case PROP_FILE:
+      file = g_value_get_object (value);
+      self->file = file ? g_object_ref (file) : NULL;
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static GType
+gstyle_palette_list_model_get_item_type (GListModel *list)
+{
+  g_assert (GSTYLE_IS_PALETTE (list));
+
+  return GSTYLE_TYPE_PALETTE;
+}
+
+static guint
+gstyle_palette_list_model_get_n_items (GListModel *list)
+{
+  GstylePalette *self = (GstylePalette *)list;
+
+  g_assert (GSTYLE_IS_PALETTE (self));
+
+  return self->colors->len;
+}
+
+static gpointer
+gstyle_palette_list_model_get_item (GListModel *list,
+                                    guint       position)
+{
+  GstylePalette *self = (GstylePalette *)list;
+
+  g_assert (GSTYLE_IS_PALETTE (self));
+
+  if (position < self->colors->len)
+    return g_object_ref (g_ptr_array_index (self->colors, position));
+  else
+    return NULL;
+}
+
+static void
+gstyle_palette_list_model_iface_init (GListModelInterface *iface)
+{
+  iface->get_item_type = gstyle_palette_list_model_get_item_type;
+  iface->get_n_items = gstyle_palette_list_model_get_n_items;
+  iface->get_item = gstyle_palette_list_model_get_item;
+}
+
+static void
+gstyle_palette_class_init (GstylePaletteClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gstyle_palette_finalize;
+  object_class->get_property = gstyle_palette_get_property;
+  object_class->set_property = gstyle_palette_set_property;
+
+  properties [PROP_ID] =
+    g_param_spec_string ("id",
+                         "Palette id",
+                         "The id of the palette.",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_NAME] =
+    g_param_spec_string ("name",
+                         "Palette name",
+                         "The palette name.",
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT | 
G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_FILE] =
+    g_param_spec_object ("file",
+                         "File",
+                         "The uri, as a GFile, used to generate the palette.",
+                         G_TYPE_FILE,
+                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_COLORS] =
+    g_param_spec_object ("colors",
+                         "Colors",
+                         "An array of colors contained in the palette.",
+                         G_TYPE_FILE,
+                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_LEN] =
+    g_param_spec_uint ("len",
+                       "Palette length",
+                       "Palette length",
+                       0,
+                       G_MAXUINT,
+                       0,
+                       (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gstyle_palette_init (GstylePalette *self)
+{
+  self->colors = g_ptr_array_new_with_free_func (g_object_unref);
+  self->color_names = g_hash_table_new_full (g_str_hash,
+                                             g_str_equal,
+                                             NULL,
+                                             (GDestroyNotify)g_ptr_array_unref);
+}
diff --git a/contrib/gstyle/gstyle-palette.h b/contrib/gstyle/gstyle-palette.h
new file mode 100644
index 0000000..aea4202
--- /dev/null
+++ b/contrib/gstyle/gstyle-palette.h
@@ -0,0 +1,86 @@
+/* gstyle-palette.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_PALETTE_H
+#define GSTYLE_PALETTE_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <libxml/xmlreader.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include "gstyle-color.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_PALETTE_ERROR (gstyle_palette_error_quark())
+
+#define GSTYLE_TYPE_PALETTE (gstyle_palette_get_type())
+
+G_DECLARE_FINAL_TYPE (GstylePalette, gstyle_palette, GSTYLE, PALETTE, GObject)
+
+typedef enum
+{
+  GSTYLE_PALETTE_ERROR_DUP_COLOR_NAME,
+  GSTYLE_PALETTE_ERROR_EMPTY,
+  GSTYLE_PALETTE_ERROR_FILE,
+  GSTYLE_PALETTE_ERROR_FORMAT,
+  GSTYLE_PALETTE_ERROR_PARSE
+} GstylePaletteError;
+
+GQuark              gstyle_palette_error_quark           (void);
+
+GstylePalette      *gstyle_palette_new                   (void);
+GstylePalette      *gstyle_palette_new_from_file         (GFile          *file,
+                                                          GCancellable   *cancellable,
+                                                          GError        **error);
+gboolean            gstyle_palette_add                   (GstylePalette  *self,
+                                                          GstyleColor    *color,
+                                                          GError        **error);
+gboolean            gstyle_palette_add_at_index          (GstylePalette  *self,
+                                                          GstyleColor    *color,
+                                                          gint            position,
+                                                          GError        **error);
+GPtrArray          *gstyle_palette_get_colors            (GstylePalette  *self);
+const GstyleColor  *gstyle_palette_get_color_at_index    (GstylePalette  *self,
+                                                          guint           index);
+gint                gstyle_palette_get_index             (GstylePalette  *self,
+                                                          GstyleColor    *color);
+const gchar        *gstyle_palette_get_id                (GstylePalette  *self);
+guint               gstyle_palette_get_len               (GstylePalette  *self);
+const gchar        *gstyle_palette_get_name              (GstylePalette  *self);
+GFile              *gstyle_palette_get_file              (GstylePalette  *self);
+GPtrArray          *gstyle_palette_lookup                (GstylePalette  *self,
+                                                          const gchar    *name);
+gboolean            gstyle_palette_remove                (GstylePalette  *self,
+                                                          GstyleColor    *color);
+gboolean            gstyle_palette_remove_at_index       (GstylePalette  *self,
+                                                          gint            position);
+gboolean            gstyle_palette_save_to_xml           (GstylePalette  *self,
+                                                          GFile          *file,
+                                                          GError        **error);
+void                gstyle_palette_set_name              (GstylePalette  *self,
+                                                          const gchar    *name);
+void                gstyle_palette_set_id                (GstylePalette  *self,
+                                                          const gchar    *id);
+
+G_END_DECLS
+
+#endif /* GSTYLE_PALETTE_H */
diff --git a/contrib/gstyle/gstyle-private.h b/contrib/gstyle/gstyle-private.h
new file mode 100644
index 0000000..7a55e19
--- /dev/null
+++ b/contrib/gstyle/gstyle-private.h
@@ -0,0 +1,31 @@
+/* gstyle-private.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This file 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 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_PRIVATE_H
+#define GSTYLE_PRIVATE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#include "gstyle-color-predefined.h"
+#include "gstyle-utils.h"
+
+G_END_DECLS
+
+#endif /* GSTYLE_PRIVATE_H */
diff --git a/contrib/gstyle/gstyle-revealer.c b/contrib/gstyle/gstyle-revealer.c
new file mode 100644
index 0000000..ce98feb
--- /dev/null
+++ b/contrib/gstyle/gstyle-revealer.c
@@ -0,0 +1,341 @@
+/* gstyle-revealer.c
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This revealer is meant to stay an internal one and deal with specific color panel problems.
+ * and it only contain code to handle DOWN direction :
+ *   - specific handling of a GstyleColorWidget (containing a scrolled window)
+ *   - duration coded in hard.
+ *
+ * although not perfect because we don't control the container and children position,
+ * it's very aceptable solution.
+ */
+
+#include "gstyle-animation.h"
+#include "gstyle-palette-widget.h"
+
+#include "gstyle-revealer.h"
+
+struct _GstyleRevealer
+{
+  GtkBin     parent_instance;
+
+  GdkWindow *window;
+  gdouble    duration;
+  gdouble    offset;
+  gdouble    src_offset;
+  gdouble    dst_offset;
+  gulong     animation_handler_id;
+  gint64     animation_starttime;
+  gdouble    previous_height;
+  gint       max_height;
+
+  guint      revealed : 1;
+  guint      duration_set : 1;
+  guint      is_animating : 1;
+};
+
+/* TODO: use spped instead of duration */
+
+G_DEFINE_TYPE (GstyleRevealer, gstyle_revealer, GTK_TYPE_BIN)
+
+enum {
+  PROP_0,
+  N_PROPS
+};
+
+#define GSTYLE_REVEALER_DEFAULT_DURATION 500
+
+static void
+animate_stop (GstyleRevealer *self)
+{
+  g_assert (GSTYLE_IS_REVEALER (self));
+
+  if (self->animation_handler_id)
+    {
+      gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->animation_handler_id);
+      self->is_animating = FALSE;
+      self->animation_handler_id = 0;
+    }
+}
+
+static gboolean
+animation_tick_cb (GtkWidget     *widget,
+                   GdkFrameClock *frame_clock,
+                   gpointer       user_data)
+{
+  GstyleRevealer *self = (GstyleRevealer *)widget;
+  GtkWidget *child;
+  gint64 time;
+  gdouble time_offset;
+  gdouble ease_offset;
+
+  g_assert (GSTYLE_IS_REVEALER (self));
+  g_assert (frame_clock != NULL);
+
+  if (!self->is_animating)
+    return G_SOURCE_REMOVE;
+
+  time = gdk_frame_clock_get_frame_time (frame_clock);
+  time_offset = MIN ((time - self->animation_starttime) / ( 1000.0 * self->duration), 1.0);
+  ease_offset = gstyle_animation_ease_in_out_cubic (time_offset);
+  self->offset =  ease_offset * (self->dst_offset - self->src_offset) + self->src_offset;
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  if (time_offset == 1.0)
+    {
+      animate_stop (self);
+      self->offset = self->dst_offset;
+      self->revealed = !!(self->offset);
+
+      child = gtk_bin_get_child (GTK_BIN (self));
+      if (child != NULL)
+        gtk_widget_set_child_visible (child, self->revealed);
+
+      return G_SOURCE_REMOVE;
+    }
+  else
+    return G_SOURCE_CONTINUE;
+}
+
+void
+gstyle_revealer_set_reveal_child (GstyleRevealer *self,
+                                  gboolean        reveal)
+{
+  GtkWidget *child;
+  GtkAllocation allocation;
+
+  g_return_if_fail (GSTYLE_IS_REVEALER (self));
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child == NULL || (!self->is_animating && reveal == self->revealed))
+    return;
+
+  animate_stop (self);
+
+  if (!self->duration_set)
+    self->duration = gstyle_animation_check_enable_animation () ? GSTYLE_REVEALER_DEFAULT_DURATION : 0;
+
+  if (reveal)
+    {
+      gtk_widget_get_allocated_size (GTK_WIDGET (self), &allocation, NULL);
+
+      self->src_offset = self->offset;
+      self->dst_offset = 1.0;
+    }
+  else
+    {
+      self->src_offset = self->offset;
+      self->dst_offset = 0.0;
+    }
+
+  if (GSTYLE_IS_PALETTE_WIDGET (child))
+    self->max_height = allocation.height;
+  else
+    self->max_height = G_MAXINT;
+
+  gtk_widget_set_child_visible (child, TRUE);
+
+  if (self->duration == 0)
+    {
+      animate_stop (self);
+      gtk_widget_queue_resize (GTK_WIDGET (self));
+    }
+  else if (!self->animation_handler_id)
+    {
+      self->animation_starttime = g_get_monotonic_time();
+      self->animation_handler_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), animation_tick_cb, self, 
NULL);
+      self->is_animating = TRUE;
+    }
+}
+
+static void
+gstyle_revealer_size_allocate (GtkWidget     *widget,
+                               GtkAllocation *allocation)
+{
+  GstyleRevealer *self = (GstyleRevealer *)widget;
+  GtkRequisition min_child_req, nat_child_req;
+  GtkAllocation child_allocation;
+  GtkWidget *child;
+
+  g_assert (GSTYLE_IS_REVEALER (self));
+  g_assert (allocation != NULL);
+
+  gtk_widget_set_allocation (widget, allocation);
+  if (gtk_widget_get_realized (GTK_WIDGET (self)))
+    gdk_window_move_resize (self->window,
+                            allocation->x,
+                            allocation->y,
+                            allocation->width,
+                            allocation->height);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child == NULL)
+    return;
+
+  if (!gtk_widget_get_visible (child))
+    return;
+
+  gtk_widget_get_preferred_size (child, &min_child_req, &nat_child_req);
+
+  child_allocation.width = allocation->width;
+  child_allocation.height = MAX (min_child_req.height, allocation->height);
+  child_allocation.x = 0;
+
+  if (GSTYLE_IS_PALETTE_WIDGET (child))
+    {
+      if (nat_child_req.height > allocation->height)
+        child_allocation.y = allocation->height * (self->offset - 1.0);
+      else
+        child_allocation.y = nat_child_req.height * (self->offset - 1.0);
+    }
+  else
+    child_allocation.y = 0;
+
+  gtk_widget_size_allocate (child, &child_allocation);
+
+  allocation->y = 0;
+  gtk_widget_set_clip (child, allocation);
+}
+
+GstyleRevealer *
+gstyle_revealer_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_REVEALER, NULL);
+}
+
+static void
+gstyle_revealer_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gstyle_revealer_parent_class)->finalize (object);
+}
+
+static void
+gstyle_revealer_get_preferred_width (GtkWidget *widget,
+                                     gint      *min_width,
+                                     gint      *nat_width)
+{
+  GstyleRevealer *self = (GstyleRevealer *)widget;
+  GtkWidget *child;
+
+  g_assert (GSTYLE_IS_REVEALER (self));
+
+  *min_width = *nat_width = 1;
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child != NULL)
+    gtk_widget_get_preferred_width (child, min_width, nat_width);
+}
+
+static void
+gstyle_revealer_get_preferred_height (GtkWidget *widget,
+                                      gint      *min_height,
+                                      gint      *nat_height)
+{
+  GstyleRevealer *self = (GstyleRevealer *)widget;
+  gint child_min_height;
+  gint child_nat_height;
+
+  g_assert (GSTYLE_IS_REVEALER (self));
+
+  GTK_WIDGET_CLASS (gstyle_revealer_parent_class)->get_preferred_height (widget, &child_min_height, 
&child_nat_height);
+
+  *min_height = 0;
+  *nat_height = MIN (self->max_height, child_nat_height) * self->offset;
+}
+
+static void
+gstyle_revealer_get_preferred_height_for_width (GtkWidget *widget,
+                                                gint       width,
+                                                gint      *min_height,
+                                                gint      *nat_height)
+{
+  gstyle_revealer_get_preferred_height (widget, min_height, nat_height);
+}
+
+static void
+gstyle_revealer_realize (GtkWidget *widget)
+{
+  GstyleRevealer *self = (GstyleRevealer *)widget;
+  GtkAllocation alloc;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  g_assert (GSTYLE_IS_REVEALER (self));
+
+  gtk_widget_get_allocation (GTK_WIDGET (self), &alloc);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.width = alloc.width;
+  attributes.height = alloc.height;
+  attributes.x = alloc.x;
+  attributes.y = alloc.y;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+  attributes.event_mask = gtk_widget_get_events (widget);
+
+  self->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
+  gtk_widget_register_window (widget, self->window);
+  gtk_widget_set_window (GTK_WIDGET (self), self->window);
+
+  gtk_widget_set_realized (widget, TRUE);
+}
+
+static void
+gstyle_revealer_add (GtkContainer *container,
+                     GtkWidget    *child)
+{
+  GstyleRevealer *self = (GstyleRevealer *)container;
+
+  g_assert (GSTYLE_IS_REVEALER (self));
+
+  gtk_widget_set_parent_window (child, self->window);
+  gtk_widget_set_child_visible (child, self->revealed);
+
+  GTK_CONTAINER_CLASS (gstyle_revealer_parent_class)->add (container, child);
+}
+
+static void
+gstyle_revealer_class_init (GstyleRevealerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gstyle_revealer_finalize;
+
+  container_class->add = gstyle_revealer_add;
+
+  widget_class->size_allocate = gstyle_revealer_size_allocate;
+  widget_class->get_preferred_width = gstyle_revealer_get_preferred_width;
+  widget_class->get_preferred_height = gstyle_revealer_get_preferred_height;
+  widget_class->get_preferred_height_for_width = gstyle_revealer_get_preferred_height_for_width;
+  widget_class->realize = gstyle_revealer_realize;
+}
+
+static void
+gstyle_revealer_init (GstyleRevealer *self)
+{
+  gtk_widget_set_has_window (GTK_WIDGET (self), TRUE);
+
+  self->duration = 500.0;
+  self->duration_set = TRUE;
+  self->max_height = G_MAXINT;
+}
diff --git a/contrib/gstyle/gstyle-revealer.h b/contrib/gstyle/gstyle-revealer.h
new file mode 100644
index 0000000..b159873
--- /dev/null
+++ b/contrib/gstyle/gstyle-revealer.h
@@ -0,0 +1,37 @@
+/* gstyle-revealer.h
+ *
+ * Copyright (C) 2016 Sebastien Lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_REVEALER_H
+#define GSTYLE_REVEALER_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_REVEALER (gstyle_revealer_get_type())
+
+G_DECLARE_FINAL_TYPE (GstyleRevealer, gstyle_revealer, GSTYLE, REVEALER, GtkBin)
+
+GstyleRevealer   *gstyle_revealer_new                  (void);
+void              gstyle_revealer_set_reveal_child     (GstyleRevealer *self,
+                                                        gboolean        reveal);
+
+G_END_DECLS
+
+#endif /* GSTYLE_REVEALER_H */
diff --git a/contrib/gstyle/gstyle-slidein.c b/contrib/gstyle/gstyle-slidein.c
new file mode 100644
index 0000000..c79e73a
--- /dev/null
+++ b/contrib/gstyle/gstyle-slidein.c
@@ -0,0 +1,1328 @@
+/* gstyle-slidein.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Initial ideas based on Gnome Builder Pnl dock system :
+ * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ */
+
+#define G_LOG_DOMAIN "gstyle-slidein"
+
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+
+#include "gstyle-animation.h"
+#include "gstyle-css-provider.h"
+#include "gstyle-utils.h"
+
+#include "gstyle-slidein.h"
+
+struct _GstyleSlidein
+{
+  GtkEventBox                  parent_instance;
+
+  GstyleCssProvider           *default_provider;
+  GtkWidget                   *overlay_child;
+  GdkWindow                   *overlay_window;
+
+  gint64                       animation_starttime;
+  gdouble                      offset;
+  gdouble                      src_offset;
+  gdouble                      dst_offset;
+  gdouble                      slide_fraction;
+  gdouble                      duration;
+  guint                        slide_margin;
+
+  gulong                       revealed_handler_id;
+  gulong                       animation_handler_id;
+
+  GstyleSlideinDirectionType   direction_type : 3;
+  GstyleSlideinDirectionType   direction_type_reverse : 3;
+  GstyleSlideinDirectionType   real_direction;
+  guint                        interpolate_size : 1;
+  guint                        revealed : 1;
+  guint                        transition_done : 1;
+  guint                        duration_set : 1;
+  guint                        is_opening : 1;
+  guint                        is_closing : 1;
+};
+
+static void gstyle_slidein_init_buildable_iface (GtkBuildableIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GstyleSlidein, gstyle_slidein, GTK_TYPE_EVENT_BOX, 0,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gstyle_slidein_init_buildable_iface))
+
+enum {
+  PROP_0,
+  PROP_DIRECTION_TYPE,
+  PROP_DURATION,
+  PROP_INTERPOLATE_SIZE,
+  PROP_SLIDE_FRACTION,
+  PROP_SLIDE_MARGIN,
+  PROP_REVEALED,
+  N_PROPS
+};
+
+enum {
+  CLOSING,
+  OPENING,
+  REVEALED,
+  N_SIGNALS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+static guint       signals[N_SIGNALS];
+
+static inline GtkOrientation
+get_orientation (GstyleSlidein *self)
+{
+  if (self->direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_UP ||
+      self->direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_DOWN)
+    return GTK_ORIENTATION_VERTICAL;
+  else
+    return GTK_ORIENTATION_HORIZONTAL;
+}
+
+GstyleSlideinDirectionType
+gstyle_slidein_get_direction_type (GstyleSlidein *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), GSTYLE_SLIDEIN_DIRECTION_TYPE_NONE);
+
+  return self->direction_type;
+}
+
+/**
+ * gstyle_slidein_set_direction_type:
+ * @direction_type: a #GstyleSlideinDirectionType
+ *
+ * Set the type of animation direction.
+ *
+ */
+void
+gstyle_slidein_set_direction_type (GstyleSlidein              *self,
+                                   GstyleSlideinDirectionType  direction_type)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+
+  if (self->direction_type != direction_type)
+    {
+      self->direction_type = direction_type;
+
+      if (direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT)
+          self->direction_type_reverse = GSTYLE_SLIDEIN_DIRECTION_TYPE_RIGHT;
+      else if (direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_RIGHT)
+          self->direction_type_reverse = GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT;
+      else if (direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_UP)
+          self->direction_type_reverse = GSTYLE_SLIDEIN_DIRECTION_TYPE_DOWN;
+      else if (direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_DOWN)
+          self->direction_type_reverse = GSTYLE_SLIDEIN_DIRECTION_TYPE_UP;
+      else if (direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_NONE)
+          self->direction_type_reverse = GSTYLE_SLIDEIN_DIRECTION_TYPE_NONE;
+
+      gtk_widget_queue_resize (GTK_WIDGET (self));
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DIRECTION_TYPE]);
+    }
+}
+
+/**
+ * gstyle_slidein_set_interpolate_size:
+ * @interpolate_size: %TRUE to interpolate the size
+ *
+ * Set whether or not we size the slidein according to all its children
+ * (regular and slide) or just the regular one.
+ *
+ */
+void
+gstyle_slidein_set_interpolate_size (GstyleSlidein *self,
+                                     gboolean       interpolate_size)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+
+  if (self->interpolate_size != interpolate_size)
+    {
+      self->interpolate_size = interpolate_size;
+
+      gtk_widget_queue_resize (GTK_WIDGET (self));
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INTERPOLATE_SIZE]);
+    }
+}
+
+/**
+ * gstyle_slidein_get_interpolate_size:
+ *
+ * Get the interpolate-size set by gstyle_slidein_set_interpolate_size().
+ *
+ * Returns: %TRUE if we interpolate the size, %FALSE otherwise.
+ */
+gboolean
+gstyle_slidein_get_interpolate_size (GstyleSlidein *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), FALSE);
+
+  return self->interpolate_size;
+}
+
+/**
+ * gstyle_slidein_set_slide_fraction:
+ * @slide_fraction: fraction of the slide compared to the total size
+ *
+ * Set the fraction used by the slide compared to the total size of the slidein,
+ * in the direction of the animation (so horizontal or vertical).
+ *
+ */
+void
+gstyle_slidein_set_slide_fraction (GstyleSlidein *self,
+                                   gdouble        slide_fraction)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+
+  if (slide_fraction != self->slide_fraction)
+    {
+      self->slide_fraction = slide_fraction;
+
+      gtk_widget_queue_resize (GTK_WIDGET (self));
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SLIDE_FRACTION]);
+    }
+}
+
+/**
+ * gstyle_slidein_get_slide_fraction:
+ *
+ * Get the slide_fraction set by gstyle_slidein_set_slide_fraction().
+ *
+ * Returns: the slide_fraction.
+ */
+gdouble
+gstyle_slidein_get_slide_fraction (GstyleSlidein *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), 0);
+
+  return self->slide_fraction;
+}
+
+/**
+ * gstyle_slidein_set_slide_margin:
+ * @slide_margin: margin.
+ *
+ * Set the margin left when the slide is opened, in pixels.
+ *
+ */
+void
+gstyle_slidein_set_slide_margin (GstyleSlidein *self,
+                                 guint          slide_margin)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+
+  if (slide_margin != self->slide_margin)
+    {
+      self->slide_margin = slide_margin;
+
+      gtk_widget_queue_resize (GTK_WIDGET (self));
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SLIDE_MARGIN]);
+    }
+}
+
+/**
+ * gstyle_slidein_get_slide_margin:
+ *
+ * Get the slide_margin set by gstyle_slidein_set_slide_margin().
+ *
+ * Returns: the slide_margin.
+ */
+guint
+gstyle_slidein_get_slide_margin (GstyleSlidein *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), 0);
+
+  return self->slide_margin;
+}
+
+/**
+ * gstyle_slidein_reset_duration:
+ *
+ * Reset the time taken to animate the slide to its default value.
+ *
+ */
+void
+gstyle_slidein_reset_duration (GstyleSlidein *self)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+
+  self->duration = 0;
+  self->duration_set = FALSE;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
+}
+
+/**
+ * gstyle_slidein_set_duration:
+ * @duration: a time in ms
+ *
+ * Set the time taken to animation the slide  to the custom @duration value, in ms.
+ *
+ */
+void
+gstyle_slidein_set_duration (GstyleSlidein *self,
+                             gdouble        duration)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+
+  self->duration = duration;
+  self->duration_set = TRUE;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DURATION]);
+}
+
+/**
+ * gstyle_slidein_get_duration:
+ *
+ * Get the time set to animate the slide.
+ *
+ * Returns: a time in ms.
+ */
+gdouble
+gstyle_slidein_get_duration (GstyleSlidein *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), 0.0);
+
+  return self->duration;
+}
+
+static gdouble
+compute_duration (GstyleSlidein *self)
+{
+  GtkWidget *child;
+  GtkRequisition min_req_size;
+  GtkRequisition nat_req_size;
+  gdouble duration = 0.0;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  gtk_widget_get_preferred_size (child, &min_req_size, &nat_req_size);
+
+  if (get_orientation (self) == GTK_ORIENTATION_HORIZONTAL)
+    duration = MAX (300, (nat_req_size.width - self->slide_margin) * self->slide_fraction * 1.2);
+  else
+    duration = MAX (300, (nat_req_size.height - self->slide_margin) * self->slide_fraction * 1.2);
+
+  return duration;
+}
+
+static void
+animate_stop (GstyleSlidein *self)
+{
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  if (self->animation_handler_id)
+    {
+      gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->animation_handler_id);
+      self->is_closing = self->is_opening = FALSE;
+      self->animation_handler_id = 0;
+    }
+}
+
+static void
+animation_done_cb (GstyleSlidein *self)
+{
+  GstyleSlideinDirectionType animation_direction;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  if (self->is_opening)
+    {
+      animate_stop (self);
+      animation_direction = self->direction_type;
+      self->revealed = TRUE;
+
+      gtk_grab_add (GTK_WIDGET (self));
+      gtk_event_box_set_above_child (GTK_EVENT_BOX (self), TRUE);
+      gtk_widget_set_can_focus (self->overlay_child, TRUE);
+      gtk_widget_grab_focus (self->overlay_child);
+    }
+  else if (self->is_closing)
+    {
+      animate_stop (self);
+      animation_direction = self->direction_type_reverse;
+      self->revealed = FALSE;
+
+      gtk_event_box_set_above_child (GTK_EVENT_BOX (self), FALSE);
+    }
+  else
+    g_assert_not_reached ();
+
+  self->is_closing = self->is_opening = FALSE;
+  self->offset = self->dst_offset;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_REVEALED]);
+  g_signal_emit (self, signals [REVEALED], 0, animation_direction, self->revealed);
+}
+
+static gboolean
+animation_tick_cb (GtkWidget     *widget,
+                   GdkFrameClock *frame_clock,
+                   gpointer       user_data)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+  gint64 time;
+  gdouble time_offset;
+  gdouble ease_offset;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+  g_assert (frame_clock != NULL);
+
+  if (!self->is_closing && !self->is_opening)
+    return G_SOURCE_REMOVE;
+
+  time = gdk_frame_clock_get_frame_time (frame_clock);
+  time_offset = MIN ((time - self->animation_starttime) / ( 1000.0 * self->duration), 1.0);
+  ease_offset = gstyle_animation_ease_in_out_cubic (time_offset);
+  self->offset =  ease_offset * (self->dst_offset - self->src_offset) + self->src_offset;
+
+  gtk_widget_queue_resize (GTK_WIDGET (self));
+
+  if (time_offset == 1.0)
+    {
+      animation_done_cb (self);
+      return G_SOURCE_REMOVE;
+    }
+  else
+    return G_SOURCE_CONTINUE;
+}
+
+/* src_offset and dst_offset need to be in [0.0, 1.0] range */
+static gboolean
+animate (GstyleSlidein *self,
+         gdouble        target_offset)
+{
+  GtkWidget *child;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+  g_assert (0.0 <= target_offset && target_offset <= 1.0);
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child == NULL || self->overlay_child == NULL)
+    return FALSE;
+
+  animate_stop (self);
+
+  if (!self->duration_set)
+    self->duration = gstyle_animation_check_enable_animation () ? compute_duration (self) : 0;
+
+  self->src_offset = self->offset;
+  self->dst_offset = target_offset;
+  gtk_widget_set_child_visible (child, TRUE);
+
+  if (self->src_offset == self->dst_offset)
+    return FALSE;
+
+  if (self->src_offset < self->dst_offset)
+    {
+      self->is_opening = TRUE;
+      g_signal_emit (self, signals [OPENING], 0);
+    }
+  else
+    {
+      self->is_closing = TRUE;
+      g_signal_emit (self, signals [CLOSING], 0);
+    }
+
+  if (self->duration == 0)
+    {
+      self->offset = target_offset;
+      animation_done_cb (self);
+      gtk_widget_queue_resize (GTK_WIDGET (self));
+    }
+  else if (!self->animation_handler_id)
+    {
+      self->animation_starttime = g_get_monotonic_time();
+      self->animation_handler_id = gtk_widget_add_tick_callback (GTK_WIDGET (self),
+                                                                 animation_tick_cb,
+                                                                 self,
+                                                                 NULL);
+    }
+
+  return TRUE;
+}
+
+/**
+ * gstyle_slidein_get_animation_state:
+ * @direction: (out): slide animation state
+ *
+ * Get the animation state of the slide :
+ * %TRUE if the slide is currently animated, %FALSE otherwise.
+ *direction contains %TRUE if opening, %FALSE if closing.
+ *
+ * Returns: %TRUE if animating, %FALSE otherwise.
+ *
+ */
+gboolean
+gstyle_slidein_get_animation_state (GstyleSlidein *self,
+                                    gboolean      *direction)
+{
+  gboolean is_animate;
+
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), FALSE);
+
+  is_animate = (self->is_opening || self->is_closing);
+  if (is_animate)
+    *direction = self->is_opening;
+  else
+    *direction = self->revealed;
+
+  return is_animate;
+}
+
+/**
+ * gstyle_slidein_reveal_slide:
+ * @reveal: %TRUE to reveal or %FALSE to close the slide
+ *
+ * Reveal or close the slide.
+ *
+ * Returns: #TRUE if the action can be executed, otherwise, %FALSE if the slide is already
+ *   in its final position, that is revealed or closed.
+ */
+gboolean
+gstyle_slidein_reveal_slide (GstyleSlidein *self,
+                             gboolean       reveal)
+{
+  GtkStyleContext *context;
+  GtkStateFlags state;
+
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), FALSE);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  state = gtk_style_context_get_state (context);
+
+  if (get_orientation (self) == GTK_ORIENTATION_HORIZONTAL)
+    self->real_direction = (!!(state & GTK_STATE_FLAG_DIR_LTR)) ? self->direction_type
+                                                                : self->direction_type_reverse;
+  else
+    self->real_direction = self->direction_type;
+
+  return animate (self, reveal ? 1.0 : 0.0);
+}
+
+/**
+ * gstyle_slidein_get_revealed:
+ *
+ * Get the state of the slide, revealed or not.
+ *
+ * Returns: %TRUE if the slide is already revealed, %FALSE otherwise.
+ */
+gboolean
+gstyle_slidein_get_revealed (GstyleSlidein *self)
+{
+  g_return_val_if_fail (GSTYLE_IS_SLIDEIN (self), FALSE);
+
+  return self->revealed;
+}
+
+static gboolean
+gstyle_slidein_event_box_key_pressed_cb (GstyleSlidein *self,
+                                         GdkEventKey   *event,
+                                         GtkWidget     *widget)
+{
+  GtkWidget *focus;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+  g_assert (event != NULL);
+  g_assert (GTK_IS_WIDGET (widget));
+
+  focus = gtk_window_get_focus (GTK_WINDOW (gtk_widget_get_toplevel (widget)));
+  if (focus == NULL)
+    return GDK_EVENT_PROPAGATE;
+
+  if (event->keyval == GDK_KEY_Escape && !GTK_IS_ENTRY (focus))
+    {
+      gstyle_slidein_reveal_slide (self, FALSE);
+      return GDK_EVENT_STOP;
+    }
+
+  if (gtk_widget_is_ancestor (focus, widget))
+    return gtk_widget_event (focus, (GdkEvent*) event);
+
+  return GDK_EVENT_PROPAGATE;
+}
+
+static void
+gstyle_slidein_compute_child_allocation (GstyleSlidein *self,
+                                         GtkAllocation  parent_alloc,
+                                         GtkAllocation *child_alloc)
+{
+  GtkRequisition min_child_req, nat_child_req;
+  gint slide_max_visible_size;
+  gint margin;
+  gint offset_x = 0;
+  gint offset_y = 0;
+
+  child_alloc->width = parent_alloc.width;
+  child_alloc->height = parent_alloc.height;
+
+  gtk_widget_get_preferred_size (self->overlay_child, &min_child_req, &nat_child_req);
+
+  /* TODO: handle padding / margin */
+
+  if (get_orientation (self) == GTK_ORIENTATION_HORIZONTAL)
+    {
+      margin = MIN (self->slide_margin, parent_alloc.width);
+      slide_max_visible_size = parent_alloc.width - margin;
+      child_alloc->width = MAX (MAX (slide_max_visible_size * self->slide_fraction, 1), min_child_req.width);
+
+      if (self->real_direction == GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT)
+        offset_x = parent_alloc.width - (child_alloc->width * self->offset) + 0.5;
+      else
+        offset_x = (self->offset - 1) * child_alloc->width + 0.5;
+    }
+  else
+    {
+      margin = MIN (self->slide_margin, parent_alloc.height);
+      slide_max_visible_size = parent_alloc.height - margin;
+      child_alloc->height =  MAX (MAX (slide_max_visible_size * self->slide_fraction, 1), 
min_child_req.height);
+
+       if (self->direction_type == GSTYLE_SLIDEIN_DIRECTION_TYPE_UP)
+        offset_y = parent_alloc.height - (child_alloc->height * self->offset) + 0.5;
+      else
+        offset_y = (self->offset - 1) * child_alloc->height + 0.5;
+    }
+
+  child_alloc->x = parent_alloc.x + offset_x;
+  child_alloc->y = parent_alloc.y + offset_y;
+}
+
+static GdkWindow *
+gstyle_slidein_create_child_window (GstyleSlidein *self)
+{
+  GtkWidget *widget = GTK_WIDGET (self);
+  GtkAllocation parent_alloc;
+  GtkAllocation child_alloc;
+  GdkWindow *window;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  gtk_widget_get_allocation (GTK_WIDGET (self), &parent_alloc);
+  gstyle_slidein_compute_child_allocation (self, parent_alloc, &child_alloc);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.width = child_alloc.width;
+  attributes.height = child_alloc.height;
+  attributes.x = child_alloc.x;
+  attributes.y = child_alloc.y;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+  attributes.event_mask = gtk_widget_get_events (widget);
+
+  window = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask);
+  gtk_widget_register_window (widget, window);
+  gtk_widget_set_parent_window (self->overlay_child, window);
+
+  return window;
+}
+
+static gboolean
+event_window_button_press_event_cb (GstyleSlidein *self,
+                                    GdkEvent      *event,
+                                    GstyleSlidein *unused)
+{
+  GdkEventButton *button_event = (GdkEventButton *)event;
+  GtkAllocation alloc;
+  GtkAllocation child_alloc;
+  gboolean is_in_slide;
+  GtkWidget *src_widget;
+  gint dest_x, dest_y;
+  gint x1, y1;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  src_widget = gtk_get_event_widget (event);
+  gtk_widget_translate_coordinates (src_widget, GTK_WIDGET (self->overlay_child),
+                                    button_event->x, button_event->y,
+                                    &dest_x, &dest_y);
+
+  gtk_widget_get_allocated_size (self->overlay_child, &child_alloc, NULL);
+  x1 = alloc.x + child_alloc.width;
+  y1 = alloc.y + child_alloc.height;
+
+  is_in_slide = (alloc.x <= dest_x && dest_x <= x1 && alloc.y <= dest_y && dest_y <= y1);
+  if (!is_in_slide)
+    {
+      gtk_grab_remove (GTK_WIDGET (self));
+      gstyle_slidein_reveal_slide (self, FALSE);
+
+      return GDK_EVENT_PROPAGATE;
+    }
+  else
+    return GDK_EVENT_STOP;
+}
+
+static void
+gstyle_slidein_remove (GtkContainer *container,
+                       GtkWidget    *widget)
+{
+  GstyleSlidein *self = (GstyleSlidein *)container;
+  gboolean was_visible;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  if (widget == self->overlay_child)
+    {
+      if (self->overlay_window != NULL)
+        {
+          was_visible = gtk_widget_get_visible (widget);
+          gtk_widget_unregister_window (GTK_WIDGET (container), self->overlay_window);
+          gdk_window_destroy (self->overlay_window);
+        }
+
+      gtk_widget_unparent (widget);
+      self->overlay_child = NULL;
+      self->overlay_window = NULL;
+
+      if (was_visible)
+        gtk_widget_queue_resize(GTK_WIDGET(self));
+    }
+  else
+    GTK_CONTAINER_CLASS (gstyle_slidein_parent_class)->remove (container, widget);
+}
+
+/**
+ * gstyle_slidein_remove_slide:
+ *
+ * Remove, if any, the slide #GtkWidget.
+ *
+ */
+void
+gstyle_slidein_remove_slide (GstyleSlidein *self)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+
+  if (self->overlay_child != NULL)
+    gstyle_slidein_remove (GTK_CONTAINER (self), self->overlay_child);
+}
+
+/**
+ * gstyle_slidein_add_slide:
+ * @slide: a #GtkWidget
+ *
+ * Set the #GtkWidget to use as a slide.
+ *
+ */
+void
+gstyle_slidein_add_slide (GstyleSlidein *self,
+                          GtkWidget     *slide)
+{
+  g_return_if_fail (GSTYLE_IS_SLIDEIN (self));
+  g_return_if_fail (GTK_IS_WIDGET (slide));
+
+  gstyle_slidein_remove_slide (self);
+
+  /* TODO: cchoose only one naming: overlay or slide */
+  self->overlay_child = slide;
+  if (gtk_widget_get_realized (GTK_WIDGET (self)))
+    self->overlay_window = gstyle_slidein_create_child_window (self);
+
+  gtk_widget_set_parent (slide, GTK_WIDGET (self));
+  if(gtk_widget_get_visible(slide))
+    gtk_widget_queue_resize(GTK_WIDGET(self));
+}
+
+static void
+gstyle_slidein_add_child (GtkBuildable *buildable,
+                          GtkBuilder   *builder,
+                          GObject      *child,
+                          const gchar  *type)
+{
+  GstyleSlidein *self = (GstyleSlidein *)buildable;
+
+  g_assert (GSTYLE_SLIDEIN (self));
+  g_assert (GTK_IS_BUILDER (builder));
+  g_assert (G_IS_OBJECT (child));
+
+  if (!GTK_IS_WIDGET (child))
+    {
+      g_warning ("Attempt to add a child of type \"%s\" to a \"%s\"",
+                 G_OBJECT_TYPE_NAME (child), G_OBJECT_TYPE_NAME (self));
+      return;
+    }
+
+  if (type != NULL && g_strcmp0 (type, "slide") == 0)
+    gstyle_slidein_add_slide (GSTYLE_SLIDEIN (buildable), GTK_WIDGET (child));
+  else if (type == NULL)
+    GTK_CONTAINER_CLASS (gstyle_slidein_parent_class)->add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
+  else
+    GTK_BUILDER_WARN_INVALID_CHILD_TYPE (buildable, type);
+}
+
+static void
+gstyle_slidein_overlay_child_allocate (GstyleSlidein *self,
+                                       GtkAllocation *alloc)
+{
+  GtkAllocation child_alloc = { 0, };
+  gboolean visible;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+  g_assert (alloc != NULL);
+
+  if (self->overlay_child != NULL)
+    {
+      visible = gtk_widget_get_visible (self->overlay_child);
+       if (self->overlay_window != NULL && gtk_widget_get_mapped (GTK_WIDGET (self)))
+        {
+          if (visible)
+            gdk_window_show (self->overlay_window);
+          else if (gdk_window_is_visible (self->overlay_window))
+            gdk_window_hide (self->overlay_window);
+        }
+
+      if (!visible)
+        return;
+
+      gstyle_slidein_compute_child_allocation (self, *alloc, &child_alloc);
+
+      if (self->overlay_window != NULL)
+        gdk_window_move_resize (self->overlay_window,
+                                child_alloc.x, child_alloc.y,
+                                child_alloc.width, child_alloc.height);
+
+      child_alloc.x = 0;
+      child_alloc.y = 0;
+      gtk_widget_size_allocate (self->overlay_child, &child_alloc);
+    }
+}
+
+static void
+gstyle_slidein_size_allocate (GtkWidget     *widget,
+                              GtkAllocation *allocation)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+  g_assert (allocation != NULL);
+
+  GTK_WIDGET_CLASS (gstyle_slidein_parent_class)->size_allocate (widget, allocation);
+
+  gstyle_slidein_overlay_child_allocate (self, allocation);
+}
+
+static void
+gstyle_slidein_get_preferred_width (GtkWidget *widget,
+                                    gint      *min_width,
+                                    gint      *nat_width)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+  GtkWidget *child;
+  gint min_width_slide_based;
+  gint nat_width_slide_based;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  *min_width = *nat_width = 1;
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child != NULL)
+    gtk_widget_get_preferred_width (child, min_width, nat_width);
+
+  if (self->interpolate_size ||
+      (self->overlay_child != NULL && gtk_widget_get_visible (self->overlay_child)))
+    {
+      gtk_widget_get_preferred_width (self->overlay_child, &min_width_slide_based, &nat_width_slide_based);
+      if (get_orientation (self) == GTK_ORIENTATION_HORIZONTAL)
+        {
+          if (!self->interpolate_size)
+            {
+              min_width_slide_based *= self->offset;
+              nat_width_slide_based *= self->offset;
+            }
+
+          if (self->slide_fraction > 0)
+            {
+              min_width_slide_based /= self->slide_fraction;
+              nat_width_slide_based /= self->slide_fraction;
+            }
+
+          min_width_slide_based += self->slide_margin;
+          nat_width_slide_based += self->slide_margin;
+        }
+
+      /* TODO: add dynamic grow/shrink mode */
+      *min_width = MAX (*min_width, min_width_slide_based);
+      *nat_width = MAX (*nat_width, nat_width_slide_based);
+    }
+  else
+    {
+      *min_width = MAX (*min_width, self->slide_margin);
+      *nat_width = MAX (*nat_width, self->slide_margin);
+    }
+}
+
+static void
+gstyle_slidein_get_preferred_height (GtkWidget *widget,
+                                     gint      *min_height,
+                                     gint      *nat_height)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+  GtkWidget *child;
+  gint min_height_slide_based;
+  gint nat_height_slide_based;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  *min_height = *nat_height = 1;
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child != NULL)
+    gtk_widget_get_preferred_width (child, min_height, nat_height);
+
+  if (self->interpolate_size ||
+      (self->overlay_child != NULL && gtk_widget_get_visible (self->overlay_child)))
+    {
+      gtk_widget_get_preferred_height (self->overlay_child, &min_height_slide_based, 
&nat_height_slide_based);
+      if (get_orientation (self) == GTK_ORIENTATION_VERTICAL)
+        {
+          if (!self->interpolate_size)
+            {
+              min_height_slide_based *= self->offset;
+              nat_height_slide_based *= self->offset;
+            }
+
+          if (self->slide_fraction > 0)
+            {
+              min_height_slide_based /= self->slide_fraction;
+              nat_height_slide_based /= self->slide_fraction;
+            }
+
+          min_height_slide_based += self->slide_margin;
+          nat_height_slide_based += self->slide_margin;
+        }
+
+      /* TODO: add dynamic grow/shrink mode */
+      *min_height = MAX (*min_height, min_height_slide_based);
+      *nat_height = MAX (*nat_height, nat_height_slide_based);
+    }
+  else
+    {
+      *min_height = MAX (*min_height, self->slide_margin);
+      *nat_height = MAX (*nat_height, self->slide_margin);
+    }
+}
+
+static void
+gstyle_slidein_realize (GtkWidget *widget)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  GTK_WIDGET_CLASS (gstyle_slidein_parent_class)->realize (widget);
+  gtk_widget_set_realized (widget, TRUE);
+
+  if (self->overlay_window == NULL)
+    self->overlay_window = gstyle_slidein_create_child_window (self);
+}
+
+static void
+gstyle_slidein_unrealize (GtkWidget *widget)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  if (self->overlay_child != NULL && self->overlay_window != NULL)
+    {
+      gtk_widget_set_parent_window (self->overlay_child, NULL);
+      gtk_widget_unregister_window (widget, self->overlay_window);
+      gdk_window_destroy (self->overlay_window);
+      self->overlay_window = NULL;
+    }
+
+  GTK_WIDGET_CLASS (gstyle_slidein_parent_class)->unrealize (widget);
+}
+
+static void
+gstyle_slidein_map (GtkWidget *widget)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  GTK_WIDGET_CLASS (gstyle_slidein_parent_class)->map (widget);
+
+  if (self->overlay_child != NULL &&
+      self->overlay_window != NULL &&
+      gtk_widget_get_visible (self->overlay_child) &&
+      gtk_widget_get_child_visible (self->overlay_child))
+    {
+       gdk_window_show (self->overlay_window);
+       g_signal_connect_swapped (self, "button-press-event",
+                                 G_CALLBACK(event_window_button_press_event_cb),
+                                 self);
+    }
+}
+
+static void
+gstyle_slidein_unmap (GtkWidget *widget)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  if (self->overlay_child != NULL &&
+      self->overlay_window != NULL &&
+      gtk_widget_is_visible (self->overlay_child))
+    {
+      gdk_window_hide (self->overlay_window );
+      g_signal_handlers_disconnect_by_func (self->overlay_child,
+                                            event_window_button_press_event_cb,
+                                            self);
+    }
+
+  GTK_WIDGET_CLASS (gstyle_slidein_parent_class)->unmap (widget);
+}
+
+static gboolean
+gstyle_slidein_draw (GtkWidget *widget,
+                     cairo_t   *cr)
+{
+  GstyleSlidein *self = (GstyleSlidein *)widget;
+  GtkStyleContext *context;
+  GtkAllocation shade_box;
+  GtkWidget *child;
+  GdkRGBA rgba;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+  g_assert (cr != NULL);
+
+  /* To draw the shade effect in between the regular child and the slides,
+   * we bypass gtk_event_box_draw (we use a windowless one so not a problem),
+   * and provide your own container draw implementation.
+   */
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child == NULL)
+    return GDK_EVENT_STOP;
+
+  gtk_container_propagate_draw (GTK_CONTAINER (self), child, cr);
+
+  if (self->offset > 0.0)
+    {
+      context = gtk_widget_get_style_context (widget);
+      gtk_style_context_save (context);
+      gtk_style_context_add_class (context, "shade");
+      gtk_style_context_get_color (context, gtk_style_context_get_state (context), &rgba);
+      gtk_style_context_restore (context);
+      rgba.alpha = rgba.alpha * self->offset;
+
+      /* We shade the whole surface in case of slide tranparency */
+      gtk_widget_get_allocated_size (widget, &shade_box, NULL);
+      cairo_rectangle (cr, shade_box.x, shade_box.y, shade_box.width, shade_box.height);
+      gdk_cairo_set_source_rgba (cr, &rgba);
+      cairo_fill (cr);
+    }
+
+  if (self->overlay_child != NULL)
+   gtk_container_propagate_draw (GTK_CONTAINER (self), self->overlay_child, cr);
+
+  return GDK_EVENT_STOP;
+}
+
+static void
+gstyle_slidein_forall (GtkContainer *container,
+                       gboolean      include_internals,
+                       GtkCallback   callback,
+                       gpointer      callback_data)
+{
+  GstyleSlidein *self = (GstyleSlidein *)container;
+  GtkWidget *child;
+
+  g_assert (GSTYLE_IS_SLIDEIN (self));
+
+  child = gtk_bin_get_child (GTK_BIN (self));
+  if (child)
+    (* callback) (child, callback_data);
+
+  if (self->overlay_child)
+    (* callback) (self->overlay_child, callback_data);
+}
+
+GtkWidget *
+gstyle_slidein_new (void)
+{
+  return g_object_new (GSTYLE_TYPE_SLIDEIN, NULL);
+}
+
+static void
+gstyle_slidein_finalize (GObject *object)
+{
+  GstyleSlidein *self = (GstyleSlidein *)object;
+
+  g_clear_object (&self->default_provider);
+  g_clear_object (&self->overlay_child);
+
+  G_OBJECT_CLASS (gstyle_slidein_parent_class)->finalize (object);
+}
+
+static void
+gstyle_slidein_get_property (GObject    *object,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  GstyleSlidein *self = GSTYLE_SLIDEIN (object);
+
+  switch (prop_id)
+    {
+    case PROP_DIRECTION_TYPE:
+      g_value_set_enum (value, gstyle_slidein_get_direction_type (self));
+      break;
+
+    case PROP_DURATION:
+      g_value_set_double (value, gstyle_slidein_get_duration (self));
+      break;
+
+    case PROP_INTERPOLATE_SIZE:
+      g_value_set_boolean (value, gstyle_slidein_get_interpolate_size (self));
+      break;
+
+    case PROP_REVEALED:
+      g_value_set_boolean (value, gstyle_slidein_get_revealed (self));
+      break;
+
+    case PROP_SLIDE_FRACTION:
+      g_value_set_double (value, gstyle_slidein_get_slide_fraction (self));
+      break;
+
+    case PROP_SLIDE_MARGIN:
+      g_value_set_uint (value, gstyle_slidein_get_slide_margin (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_slidein_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  GstyleSlidein *self = GSTYLE_SLIDEIN (object);
+
+  switch (prop_id)
+    {
+    case PROP_DIRECTION_TYPE:
+      gstyle_slidein_set_direction_type (self, g_value_get_enum (value));
+      break;
+
+    case PROP_DURATION:
+      gstyle_slidein_set_duration (self, g_value_get_double (value));
+      break;
+
+    case PROP_INTERPOLATE_SIZE:
+      gstyle_slidein_set_interpolate_size (self, g_value_get_boolean (value));
+      break;
+
+    case PROP_SLIDE_FRACTION:
+      gstyle_slidein_set_slide_fraction (self, g_value_get_double (value));
+      break;
+
+    case PROP_SLIDE_MARGIN:
+      gstyle_slidein_set_slide_margin (self, g_value_get_uint (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gstyle_slidein_class_init (GstyleSlideinClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+  object_class->finalize = gstyle_slidein_finalize;
+  object_class->get_property = gstyle_slidein_get_property;
+  object_class->set_property = gstyle_slidein_set_property;
+
+  widget_class->size_allocate = gstyle_slidein_size_allocate;
+  widget_class->get_preferred_width = gstyle_slidein_get_preferred_width;
+  widget_class->get_preferred_height = gstyle_slidein_get_preferred_height;
+  widget_class->realize = gstyle_slidein_realize;
+  widget_class->unrealize = gstyle_slidein_unrealize;
+  widget_class->map = gstyle_slidein_map;
+  widget_class->unmap = gstyle_slidein_unmap;
+  widget_class->draw = gstyle_slidein_draw;
+
+  container_class->remove = gstyle_slidein_remove;
+  container_class->forall = gstyle_slidein_forall;
+
+  properties [PROP_DURATION] =
+    g_param_spec_double ("duration",
+                         "duration",
+                         "slide animation time in ms",
+                         0.0,
+                         G_MAXDOUBLE,
+                         0.0,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_INTERPOLATE_SIZE] =
+    g_param_spec_boolean ("interpolate-size",
+                          "interpolate-size",
+                          "interpolate-size",
+                          FALSE,
+                          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_SLIDE_FRACTION] =
+    g_param_spec_double ("slide-fraction",
+                         "slide-fraction",
+                         "fraction to show when releaving the slide",
+                         0.0,
+                         1.0,
+                         1.0,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_SLIDE_MARGIN] =
+    g_param_spec_uint ("slide-margin",
+                       "slide-margin",
+                       "margin to keep when releaving the slide",
+                       0,
+                       G_MAXUINT,
+                       0,
+                       (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_REVEALED] =
+    g_param_spec_boolean ("revealed",
+                          "revealed",
+                          "Whether the slidein is revealed",
+                          FALSE,
+                          (G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_DIRECTION_TYPE] =
+    g_param_spec_enum ("direction-type",
+                       "direction-type",
+                       "direction-type",
+                       GSTYLE_TYPE_SLIDEIN_DIRECTION_TYPE,
+                       GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT,
+                       (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  /**
+   * GstyleSlidein::revealed:
+   * @self: #GstyleSlidein instance.
+   * @direction_type: type of opening direction.
+   * @revealed: the revealed state of the slide.
+   *
+   * Emitted when the revealed state of the slide child change.
+   * Notice that this only append after the duration time
+   */
+  signals[REVEALED] = g_signal_new ("revealed",
+                                    GSTYLE_TYPE_SLIDEIN,
+                                    G_SIGNAL_RUN_FIRST,
+                                    0,
+                                    NULL, NULL, NULL,
+                                    G_TYPE_NONE,
+                                    2,
+                                    GSTYLE_TYPE_SLIDEIN_DIRECTION_TYPE,
+                                    G_TYPE_BOOLEAN);
+
+  /**
+   * GstyleSlidein::closing:
+   * @self: #GstyleSlidein instance.
+   *
+   * Emitted when the slide start closing.
+   */
+  signals[CLOSING] = g_signal_new ("closing",
+                                   GSTYLE_TYPE_SLIDEIN,
+                                   G_SIGNAL_RUN_FIRST,
+                                   0,
+                                   NULL, NULL, NULL,
+                                   G_TYPE_NONE,
+                                   0);
+
+  /**
+   * GstyleSlidein::opening:
+   * @self: #GstyleSlidein instance.
+   *
+   * Emitted when the slide start opening.
+   */
+  signals[OPENING] = g_signal_new ("opening",
+                                   GSTYLE_TYPE_SLIDEIN,
+                                   G_SIGNAL_RUN_FIRST,
+                                   0,
+                                   NULL, NULL, NULL,
+                                   G_TYPE_NONE,
+                                   0);
+
+  gtk_widget_class_set_css_name (widget_class, "gstyleslidein");
+}
+
+static void
+gstyle_slidein_init (GstyleSlidein *self)
+{
+  GtkStyleContext *context;
+
+  g_signal_connect_swapped (self,
+                            "key-press-event",
+                            G_CALLBACK (gstyle_slidein_event_box_key_pressed_cb),
+                            self);
+
+  gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
+  gtk_event_box_set_visible_window (GTK_EVENT_BOX (self), FALSE);
+  gtk_event_box_set_above_child (GTK_EVENT_BOX (self), FALSE);
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self));
+  self->default_provider = gstyle_css_provider_init_default (gtk_style_context_get_screen (context));
+
+  self->direction_type = GSTYLE_SLIDEIN_DIRECTION_TYPE_RIGHT;
+  self->direction_type_reverse = GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT;
+  self->duration = 0.0;
+  self->duration_set = TRUE;
+}
+
+static void
+gstyle_slidein_init_buildable_iface (GtkBuildableIface *iface)
+{
+  iface->add_child = gstyle_slidein_add_child;
+}
+
+GType
+gstyle_slidein_type_get_type (void)
+{
+  static GType type_id;
+  static const GEnumValue values[] = {
+    { GSTYLE_SLIDEIN_DIRECTION_TYPE_NONE, "GSTYLE_SLIDEIN_DIRECTION_TYPE_NONE", "none" },
+    { GSTYLE_SLIDEIN_DIRECTION_TYPE_RIGHT, "GSTYLE_SLIDEIN_DIRECTION_TYPE_RIGHT", "right" },
+    { GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT, "GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT", "left" },
+    { GSTYLE_SLIDEIN_DIRECTION_TYPE_UP, "GSTYLE_SLIDEIN_DIRECTION_TYPE_UP", "up" },
+    { GSTYLE_SLIDEIN_DIRECTION_TYPE_DOWN, "GSTYLE_SLIDEIN_DIRECTION_TYPE_DOWN", "down" },
+    { 0 }
+  };
+
+  if (g_once_init_enter (&type_id))
+    {
+      GType _type_id;
+
+      _type_id = g_enum_register_static ("GstyleSlideinDirectionType", values);
+      g_once_init_leave (&type_id, _type_id);
+    }
+
+  return type_id;
+}
diff --git a/contrib/gstyle/gstyle-slidein.h b/contrib/gstyle/gstyle-slidein.h
new file mode 100644
index 0000000..1691193
--- /dev/null
+++ b/contrib/gstyle/gstyle-slidein.h
@@ -0,0 +1,64 @@
+/* gstyle-slidein.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_SLIDEIN_H
+#define GSTYLE_SLIDEIN_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_SLIDEIN_DIRECTION_TYPE (gstyle_slidein_type_get_type())
+
+typedef enum
+{
+  GSTYLE_SLIDEIN_DIRECTION_TYPE_NONE,
+  GSTYLE_SLIDEIN_DIRECTION_TYPE_RIGHT,
+  GSTYLE_SLIDEIN_DIRECTION_TYPE_LEFT,
+  GSTYLE_SLIDEIN_DIRECTION_TYPE_UP,
+  GSTYLE_SLIDEIN_DIRECTION_TYPE_DOWN,
+} GstyleSlideinDirectionType;
+
+#define GSTYLE_TYPE_SLIDEIN (gstyle_slidein_get_type())
+
+G_DECLARE_FINAL_TYPE (GstyleSlidein, gstyle_slidein, GSTYLE, SLIDEIN, GtkEventBox)
+
+GType                        gstyle_slidein_type_get_type                    (void);
+
+GtkWidget                   *gstyle_slidein_new                              (void);
+void                         gstyle_slidein_add_slide                        (GstyleSlidein               
*self,
+                                                                              GtkWidget                   
*slide);
+void                         gstyle_slidein_remove_slide                     (GstyleSlidein               
*self);
+gboolean                     gstyle_slidein_reveal_slide                     (GstyleSlidein               
*self,
+                                                                              gboolean                     
reveal);
+
+GstyleSlideinDirectionType   gstyle_slidein_get_direction_type               (GstyleSlidein               
*self);
+gboolean                     gstyle_slidein_get_interpolate_size             (GstyleSlidein               
*self);
+gboolean                     gstyle_slidein_get_revealed                     (GstyleSlidein               
*self);
+gdouble                      gstyle_slidein_get_slide_fraction               (GstyleSlidein               
*self);
+
+void                         gstyle_slidein_set_direction_type               (GstyleSlidein               
*self,
+                                                                              GstyleSlideinDirectionType   
direction_type);
+void                         gstyle_slidein_set_interpolate_size             (GstyleSlidein               
*self,
+                                                                              gboolean                     
interpolate_size);
+void                         gstyle_slidein_set_slide_fraction               (GstyleSlidein               
*self,
+                                                                              gdouble                      
slide_fraction);
+G_END_DECLS
+
+#endif /* GSTYLE_SLIDEIN_H */
diff --git a/contrib/gstyle/gstyle-types.h b/contrib/gstyle/gstyle-types.h
new file mode 100644
index 0000000..30b9534
--- /dev/null
+++ b/contrib/gstyle/gstyle-types.h
@@ -0,0 +1,34 @@
+/* gstyle-types.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_TYPES_H
+#define GSTYLE_TYPES_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstyleCielab            GstyleCielab;
+typedef struct _GstyleHSV               GstyleHSV;
+typedef struct _GstyleXYZ               GstyleXYZ;
+typedef struct _GstyleColorItem         GstyleColorItem;
+
+G_END_DECLS
+
+#endif /* GSTYLE_TYPES_H */
+
diff --git a/contrib/gstyle/gstyle-utils.c b/contrib/gstyle/gstyle-utils.c
new file mode 100644
index 0000000..7ed4b73
--- /dev/null
+++ b/contrib/gstyle/gstyle-utils.c
@@ -0,0 +1,172 @@
+/* gstyle-utils.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gstyle-utils.h"
+
+gboolean
+gstyle_str_empty0 (const gchar *str)
+{
+  return (str == NULL) || (str[0] == '\0');
+}
+
+gboolean
+gstyle_utf8_is_spaces (const gchar *str)
+{
+  gunichar c;
+
+  if (str == NULL)
+    return FALSE;
+
+  while (g_unichar_isspace (c = g_utf8_get_char (str)))
+    str = g_utf8_next_char (str);
+
+  return (c == '\0');
+}
+
+typedef enum
+{
+  CORNER_TOP_LEFT,
+  CORNER_TOP_RIGHT,
+  CORNER_BOTTOM_LEFT,
+  CORNER_BOTTOM_RIGHT
+} Corner;
+
+static void
+draw_corner (cairo_t *cr,
+             gdouble  x,
+             gdouble  y,
+             gdouble  radius,
+             Corner   corner)
+{
+  switch (corner)
+    {
+    case CORNER_TOP_LEFT:
+      cairo_arc (cr, x + radius, y + radius, radius, -G_PI, -G_PI_2);
+      break;
+
+    case CORNER_TOP_RIGHT:
+      cairo_arc (cr, x - radius, y + radius, radius, -G_PI_2, 0.0);
+      break;
+
+    case CORNER_BOTTOM_RIGHT:
+      cairo_arc (cr, x - radius, y - radius, radius, 0.0, G_PI_2);
+      break;
+
+    case CORNER_BOTTOM_LEFT:
+      cairo_arc (cr, x + radius, y - radius, radius, G_PI_2, G_PI);
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+}
+
+void
+draw_cairo_round_box (cairo_t      *cr,
+                      GdkRectangle  rect,
+                      gint          tl_radius,
+                      gint          tr_radius,
+                      gint          bl_radius,
+                      gint          br_radius)
+{
+  gdouble right = rect.x + rect.width;
+  gdouble bottom = rect.y + rect.height;
+
+  cairo_new_sub_path (cr);
+  cairo_move_to (cr, rect.x, rect.y + tl_radius);
+
+  if (tl_radius > 0)
+    draw_corner (cr, rect.x, rect.y, tl_radius, CORNER_TOP_LEFT);
+
+  cairo_line_to (cr, right - tr_radius, rect.y);
+
+  if (tr_radius > 0)
+    draw_corner (cr, right, rect.y, tr_radius, CORNER_TOP_RIGHT);
+
+  cairo_line_to (cr, right, bottom - br_radius);
+
+  if (br_radius > 0)
+    draw_corner (cr, right, bottom, br_radius, CORNER_BOTTOM_RIGHT);
+
+  cairo_line_to (cr, rect.x + bl_radius, bottom);
+
+  if (br_radius > 0)
+    draw_corner (cr, rect.x, bottom, bl_radius, CORNER_BOTTOM_LEFT);
+
+  cairo_close_path (cr);
+}
+
+void
+gstyle_utils_get_rect_resized_box (GdkRectangle  src_rect,
+                                   GdkRectangle *dst_rect,
+                                   GtkBorder    *offset)
+{
+  dst_rect->x = src_rect.x + offset->left;
+  dst_rect->y = src_rect.y + offset->top;
+  dst_rect->width = src_rect.width - (offset->left + offset->right);
+  dst_rect->height = src_rect.height - (offset->top + offset->bottom);
+
+  if (dst_rect->width < 1)
+    {
+      dst_rect->width = 1;
+      dst_rect->x = src_rect.x + src_rect.width / 2;
+    }
+
+  if (dst_rect->height < 1)
+    {
+      dst_rect->height = 1;
+      dst_rect->y = src_rect.y + src_rect.height / 2;
+    }
+}
+
+cairo_pattern_t *
+gstyle_utils_get_checkered_pattern (void)
+{
+  static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
+                                   0x00, 0xFF, 0x00, 0x00 };
+  cairo_surface_t *surface;
+  cairo_pattern_t *pattern;
+
+  surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A8, 2, 2, 4);
+  pattern = cairo_pattern_create_for_surface (surface);
+  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+  cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
+  cairo_surface_destroy (surface);
+
+  return pattern;
+}
+
+void
+gstyle_utils_get_contrasted_rgba (GdkRGBA  rgba,
+                                  GdkRGBA *dst_rgba)
+{
+  guint brightness;
+
+  brightness = rgba.red * 299 + rgba.green * 587 + rgba.blue * 114;
+  if (brightness > 500)
+    {
+      dst_rgba->red = dst_rgba->green = dst_rgba->blue = 0.0;
+    }
+  else
+    {
+      dst_rgba->red = dst_rgba->green = dst_rgba->blue = 1.0;
+    }
+
+  rgba.alpha = 1.0;
+}
diff --git a/contrib/gstyle/gstyle-utils.h b/contrib/gstyle/gstyle-utils.h
new file mode 100644
index 0000000..8bae505
--- /dev/null
+++ b/contrib/gstyle/gstyle-utils.h
@@ -0,0 +1,93 @@
+/* gstyle-utils.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_UTILS_H
+#define GSTYLE_UTILS_H
+
+#include <glib.h>
+#include <cairo.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+gboolean              gstyle_str_empty0                  (const gchar     *str);
+gboolean              gstyle_utf8_is_spaces              (const gchar     *str);
+void                  draw_cairo_round_box               (cairo_t         *cr,
+                                                          GdkRectangle     rect,
+                                                          gint             tl_radius,
+                                                          gint             tr_radius,
+                                                          gint             bl_radius,
+                                                          gint             br_radius);
+void                  gstyle_utils_get_rect_resized_box  (GdkRectangle     src_rect,
+                                                          GdkRectangle    *dst_rect,
+                                                          GtkBorder       *offset);
+cairo_pattern_t      *gstyle_utils_get_checkered_pattern (void);
+void                  gstyle_utils_get_contrasted_rgba   (GdkRGBA          rgba,
+                                                          GdkRGBA         *dst_rgba);
+
+static inline guint32
+pack_rgba24 (GdkRGBA *rgba)
+{
+  guint red, green, blue, alpha;
+  guint32 result;
+
+  alpha = CLAMP (rgba->alpha * 255, 0, 255);
+  red = CLAMP (rgba->red * 255, 0, 255);
+  green = CLAMP (rgba->green * 255, 0, 255);
+  blue = CLAMP (rgba->blue * 255, 0, 255);
+  result = (alpha << 24) | (red << 16) | (green << 8) | blue;
+
+  return result;
+}
+
+static inline void
+unpack_rgba24 (guint32  val,
+               GdkRGBA *rgba)
+{
+  rgba->blue = (val & 0xFF) / 255.0;
+  val >>= 8;
+  rgba->green = (val & 0xFF) / 255.0;
+  val >>= 8;
+  rgba->red = (val & 0xFF) / 255.0;
+  val >>= 8;
+  rgba->alpha = (val & 0xFF) / 255.0;
+}
+
+static inline gboolean
+gstyle_utils_cmp_border (GtkBorder border1,
+                         GtkBorder border2)
+{
+  if (border1.left != border2.left ||
+      border1.right != border2.right ||
+      border1.top != border2.top ||
+      border1.bottom != border2.bottom)
+    return FALSE;
+  else
+    return TRUE;
+}
+
+#define gstyle_clear_weak_pointer(ptr) \
+  (*(ptr) ? (g_object_remove_weak_pointer((GObject*)*(ptr), (gpointer*)ptr),*(ptr)=NULL,1) : 0)
+
+#define gstyle_set_weak_pointer(ptr,obj) \
+  
((obj!=*(ptr))?(gstyle_clear_weak_pointer(ptr),*(ptr)=obj,((obj)?g_object_add_weak_pointer((GObject*)obj,(gpointer*)ptr),NULL:NULL),1):0)
+
+G_END_DECLS
+
+#endif /* GSTYLE_UTILS_H */
diff --git a/contrib/gstyle/gstyle-xyz.c b/contrib/gstyle/gstyle-xyz.c
new file mode 100644
index 0000000..afe602c
--- /dev/null
+++ b/contrib/gstyle/gstyle-xyz.c
@@ -0,0 +1,64 @@
+/* gstyle-xyz.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "gstyle-xyz"
+
+#include "gstyle-xyz.h"
+
+G_DEFINE_BOXED_TYPE (GstyleXYZ, gstyle_xyz, gstyle_xyz_copy, gstyle_xyz_free)
+
+/**
+ * GstyleXYZ:
+ * @x: Tristimulus X value.
+ * @y: Tristimulus Y value.
+ * @z: Tristimulus Z value.
+ * @alpha: The opacity of the color in [0, 1] range.
+ *
+ * A #GstyleXYZ is used to represent a color in
+ * the CIE 1931 XYZ color space.
+ */
+
+/**
+ * gstyle_xyz_copy:
+ * @self: a #GstyleXYZ
+ *
+ * Makes a copy of a #GstyleXYZ.
+ *
+ * The result must be freed through gstyle_xyz_free().
+ *
+ * Returns: a newly allocated #GstyleXYZ with the same content as @self.
+ *
+ */
+GstyleXYZ *
+gstyle_xyz_copy (const GstyleXYZ *self)
+{
+  return g_slice_dup (GstyleXYZ, self);
+}
+
+/**
+ * gstyle_xyz_free:
+ * @self: a #GstyleXYZ
+ *
+ * Frees a #GstyleXYZ created with gstyle_xyz_copy().
+ *
+ */
+void
+gstyle_xyz_free (GstyleXYZ *self)
+{
+  g_slice_free (GstyleXYZ, self);
+}
diff --git a/contrib/gstyle/gstyle-xyz.h b/contrib/gstyle/gstyle-xyz.h
new file mode 100644
index 0000000..1b3550f
--- /dev/null
+++ b/contrib/gstyle/gstyle-xyz.h
@@ -0,0 +1,45 @@
+/* gstyle-xyz.h
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GSTYLE_XYZ_H
+#define GSTYLE_XYZ_H
+
+#include <glib.h>
+
+#include "gstyle-types.h"
+
+G_BEGIN_DECLS
+
+#define GSTYLE_TYPE_XYZ (gstyle_xyz_get_type ())
+
+struct _GstyleXYZ
+{
+  gdouble x;
+  gdouble y;
+  gdouble z;
+  gdouble alpha;
+};
+
+GType          gstyle_xyz_get_type                (void) G_GNUC_CONST;
+
+GstyleXYZ     *gstyle_xyz_copy                    (const GstyleXYZ  *self);
+void           gstyle_xyz_free                    (GstyleXYZ        *self);
+
+G_END_DECLS
+
+#endif /* GSTYLE_XYZ_H */
diff --git a/contrib/gstyle/gstyle.gresource.xml b/contrib/gstyle/gstyle.gresource.xml
new file mode 100644
index 0000000..4a9a003
--- /dev/null
+++ b/contrib/gstyle/gstyle.gresource.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/libgstyle">
+    <file compressed="true" alias="ui/gstyle-color-panel.ui">ui/gstyle-color-panel.ui</file>
+    <file compressed="true" alias="ui/gstyle-palette-widget.ui">ui/gstyle-palette-widget.ui</file>
+
+    <file compressed="true" alias="theme/gstyle.css">theme/gstyle.css</file>
+
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-horizontal.png">assets/color-scale-slider-horizontal.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-horizontal-hover.png">assets/color-scale-slider-horizontal-hover.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-horizontal-active.png">assets/color-scale-slider-horizontal-active.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-horizontal-insensitive.png">assets/color-scale-slider-horizontal-insensitive.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-horizontal-backdrop.png">assets/color-scale-slider-horizontal-backdrop.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-horizontal-backdrop-insensitive.png">assets/color-scale-slider-horizontal-backdrop-insensitive.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-vertical.png">assets/color-scale-slider-vertical.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-vertical-hover.png">assets/color-scale-slider-vertical-hover.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-vertical-active.png">assets/color-scale-slider-vertical-active.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-vertical-insensitive.png">assets/color-scale-slider-vertical-insensitive.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-vertical-backdrop.png">assets/color-scale-slider-vertical-backdrop.png</file>
+    <file preprocess='to-pixdata' 
alias="colorscale/color-scale-slider-vertical-backdrop-insensitive.png">assets/color-scale-slider-vertical-backdrop-insensitive.png</file>
+
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-horizontal 2 
png">assets/color-scale-slider-horizontal 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-horizontal-hover 2 
png">assets/color-scale-slider-horizontal-hover 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-horizontal-active 2 
png">assets/color-scale-slider-horizontal-active 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-horizontal-insensitive 2 
png">assets/color-scale-slider-horizontal-insensitive 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-horizontal-backdrop 2 
png">assets/color-scale-slider-horizontal-backdrop 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-horizontal-backdrop-insensitive 2 
png">assets/color-scale-slider-horizontal-backdrop-insensitive 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-vertical 2 
png">assets/color-scale-slider-vertical 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-vertical-hover 2 
png">assets/color-scale-slider-vertical-hover 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-vertical-active 2 
png">assets/color-scale-slider-vertical-active 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-vertical-insensitive 2 
png">assets/color-scale-slider-vertical-insensitive 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-vertical-backdrop 2 
png">assets/color-scale-slider-vertical-backdrop 2 png</file>
+    <file preprocess='to-pixdata' alias="colorscale/color-scale-slider-vertical-backdrop-insensitive 2 
png">assets/color-scale-slider-vertical-backdrop-insensitive 2 png</file>
+
+    <file alias="icons/scalable/actions/eyedropper-symbolic.svg">assets/eyedropper-symbolic.svg</file>
+
+    <file alias="icons/unit-percent-symbolic.svg">assets/unit-percent-symbolic.svg</file>
+    <file alias="icons/unit-degree-symbolic.svg">assets/unit-degree-symbolic.svg</file>
+  </gresource>
+</gresources>
diff --git a/contrib/gstyle/tests/Makefile.am b/contrib/gstyle/tests/Makefile.am
new file mode 100644
index 0000000..1e830ff
--- /dev/null
+++ b/contrib/gstyle/tests/Makefile.am
@@ -0,0 +1,94 @@
+EXTRA_DIST =
+
+gstyle_cflags =                              \
+       $(DEBUG_CFLAGS)                      \
+       $(GSTYLE_CFLAGS)                     \
+       -I$(top_srcdir)/contrib/gstyle       \
+       -DTEST_DATA_DIR="\"$(abs_builddir)/data\"" \
+       $(NULL)
+
+gstyle_libs =                                               \
+       $(GSTYLE_LIBS)                                      \
+       $(top_builddir)/contrib/gstyle/libgstyle-private.la \
+       $(NULL)
+
+tests_cflags =                   \
+       $(egg_cflags)            \
+       $(gstyle_cflags)         \
+       $(NULL)
+
+tests_libs =                                          \
+       $(gstyle_libs)                                \
+       $(top_builddir)/contrib/egg/libegg-private.la \
+       $(NULL)
+
+tests_ldflags =         \
+       -export-dynamic \
+       $(NULL)
+
+misc_programs =
+
+TESTS_ENVIRONMENT =                                 \
+       GB_IN_TREE_PLUGINS=1                        \
+       G_TEST_SRCDIR="$(abs_srcdir)"               \
+       G_TEST_BUILDDIR="$(abs_builddir)"           \
+       G_DEBUG=gc-friendly                         \
+       GSETTINGS_BACKEND=memory                    \
+       MALLOC_CHECK_=2                             \
+       MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256)) \
+       $(NULL)
+
+LOG_COMPILER = $(top_srcdir)/build/autotools/tap-test
+
+misc_programs = test-gstyle-color
+test_gstyle_color_SOURCES = test-gstyle-color.c
+test_gstyle_color_CFLAGS = $(tests_cflags)
+test_gstyle_color_LDADD =  $(tests_libs)
+
+misc_programs += test-gstyle-color-panel
+test_gstyle_color_panel_SOURCES = test-gstyle-color-panel.c
+test_gstyle_color_panel_CFLAGS = $(tests_cflags)
+test_gstyle_color_panel_LDADD = $(tests_libs)
+
+misc_programs += test-gstyle-color-plane
+test_gstyle_color_plane_SOURCES = test-gstyle-color-plane.c
+test_gstyle_color_plane_CFLAGS = $(tests_cflags)
+test_gstyle_color_plane_LDADD = $(tests_libs)
+
+misc_programs += test-gstyle-color-scale
+test_gstyle_color_scale_SOURCES = test-gstyle-color-scale.c
+test_gstyle_color_scale_CFLAGS = $(tests_cflags)
+test_gstyle_color_scale_LDADD = $(tests_libs)
+
+misc_programs += test-gstyle-color-widget
+test_gstyle_color_widget_SOURCES = test-gstyle-color-widget.c
+test_gstyle_color_widget_CFLAGS = $(tests_cflags)
+test_gstyle_color_widget_LDADD = $(tests_libs)
+
+misc_programs += test-gstyle-palette
+test_gstyle_palette_SOURCES = test-gstyle-palette.c
+test_gstyle_palette_CFLAGS = $(tests_cflags)
+test_gstyle_palette_LDADD = $(tests_libs)
+
+misc_programs += test-gstyle-palette-widget
+test_gstyle_palette_widget_SOURCES = test-gstyle-palette-widget.c
+test_gstyle_palette_widget_CFLAGS = $(tests_cflags)
+test_gstyle_palette_widget_LDADD = $(tests_libs)
+
+misc_programs += test-gstyle-parse
+test_gstyle_parse_SOURCES = test-gstyle-parse.c
+test_gstyle_parse_CFLAGS = $(tests_cflags)
+test_gstyle_parse_LDADD = $(tests_libs)
+
+if ENABLE_TESTS
+noinst_PROGRAMS = $(TESTS) $(misc_programs)
+endif
+
+check_PROGRAMS = $(TESTS) $(misc_programs)
+
+EXTRA_DIST +=            \
+       data/palette.gpl \
+       data/palette.xml \
+       $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/contrib/gstyle/tests/data/gstyle-color-editor.ui 
b/contrib/gstyle/tests/data/gstyle-color-editor.ui
new file mode 100644
index 0000000..e74c9fe
--- /dev/null
+++ b/contrib/gstyle/tests/data/gstyle-color-editor.ui
@@ -0,0 +1,280 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkBox" id="editor_box">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkEntry" id="entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GstyleColorPlane" id="plane">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="expand">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkComboBox" id="mode_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="model">mode_store</property>
+        <child>
+          <object class="GtkCellRendererText"/>
+          <attributes>
+            <attribute name="text">1</attribute>
+          </attributes>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkGrid">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="row_spacing">6</property>
+        <property name="column_spacing">6</property>
+        <property name="row_homogeneous">True</property>
+        <property name="column_homogeneous">True</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Hue</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Saturation</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Value</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Cielab l</property>
+          </object>
+          <packing>
+            <property name="left_attach">2</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Cielab a</property>
+          </object>
+          <packing>
+            <property name="left_attach">2</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Cielab b</property>
+          </object>
+          <packing>
+            <property name="left_attach">2</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Red</property>
+          </object>
+          <packing>
+            <property name="left_attach">4</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Green</property>
+          </object>
+          <packing>
+            <property name="left_attach">4</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Blue</property>
+          </object>
+          <packing>
+            <property name="left_attach">4</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="hsv_h_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="hsv_s_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="hsv_v_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">1</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="cielab_l_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="digits">-1</property>
+          </object>
+          <packing>
+            <property name="left_attach">3</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="cielab_a_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">3</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="cielab_b_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">3</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="rgb_green_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">5</property>
+            <property name="top_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="rgb_blue_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">5</property>
+            <property name="top_attach">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScale" id="rgb_red_scale">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="round_digits">1</property>
+            <property name="digits">3</property>
+          </object>
+          <packing>
+            <property name="left_attach">5</property>
+            <property name="top_attach">0</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+  </object>
+   <object class="GtkListStore" id="mode_store">
+    <columns>
+      <column type="GstyleColorPlaneMode"/>
+      <column type="gchararray"/>
+    </columns>
+  </object>
+</interface>
diff --git a/contrib/gstyle/tests/data/palette.gpl b/contrib/gstyle/tests/data/palette.gpl
new file mode 100644
index 0000000..d8b868b
--- /dev/null
+++ b/contrib/gstyle/tests/data/palette.gpl
@@ -0,0 +1,142 @@
+GIMP Palette
+Name: SVG
+#
+  0   0   0    black (#000000)
+105 105 105    dimgray (#696969)
+128 128 128    gray (#808080)
+169 169 169    darkgray (#A9A9A9)
+192 192 192    silver (#C0C0C0)
+211 211 211    lightgray (#D3D3D3)
+220 220 220    gainsboro (#DCDCDC)
+245 245 245    whitesmoke (#F5F5F5)
+255 255 255    white (#FFFFFF)
+188 143 143    rosybrown (#BC8F8F)
+205  92  92    indianred (#CD5C5C)
+165  42  42    brown (#A52A2A)
+178  34  34    firebrick (#B22222)
+240 128 128    lightcoral (#F08080)
+128   0   0    maroon (#800000)
+139   0   0    darkred (#8B0000)
+255   0   0    red (#FF0000)
+255 250 250    snow (#FFFAFA)
+255 228 225    mistyrose (#FFE4E1)
+250 128 114    salmon (#FA8072)
+255  99  71    tomato (#FF6347)
+233 150 122    darksalmon (#E9967A)
+255 127  80    coral (#FF7F50)
+255  69   0    orangered (#FF4500)
+255 160 122    lightsalmon (#FFA07A)
+160  82  45    sienna (#A0522D)
+255 245 238    seashell (#FFF5EE)
+210 105  30    chocolate (#D2691E)
+139  69  19    saddlebrown (#8B4513)
+244 164  96    sandybrown (#F4A460)
+255 218 185    peachpuff (#FFDAB9)
+205 133  63    peru (#CD853F)
+250 240 230    linen (#FAF0E6)
+255 228 196    bisque (#FFE4C4)
+255 140   0    darkorange (#FF8C00)
+222 184 135    burlywood (#DEB887)
+210 180 140    tan (#D2B48C)
+250 235 215    antiquewhite (#FAEBD7)
+255 222 173    navajowhite (#FFDEAD)
+255 235 205    blanchedalmond (#FFEBCD)
+255 239 213    papayawhip (#FFEFD5)
+255 228 181    moccasin (#FFE4B5)
+255 165   0    orange (#FFA500)
+245 222 179    wheat (#F5DEB3)
+253 245 230    oldlace (#FDF5E6)
+255 250 240    floralwhite (#FFFAF0)
+184 134  11    darkgoldenrod (#B8860B)
+218 165  32    goldenrod (#DAA520)
+255 248 220    cornsilk (#FFF8DC)
+255 215   0    gold (#FFD700)
+240 230 140    khaki (#F0E68C)
+255 250 205    lemonchiffon (#FFFACD)
+238 232 170    palegoldenrod (#EEE8AA)
+189 183 107    darkkhaki (#BDB76B)
+245 245 220    beige (#F5F5DC)
+250 250 210    lightgoldenrodyellow (#FAFAD2)
+128 128   0    olive (#808000)
+255 255   0    yellow (#FFFF00)
+255 255 224    lightyellow (#FFFFE0)
+255 255 240    ivory (#FFFFF0)
+107 142  35    olivedrab (#6B8E23)
+154 205  50    yellowgreen (#9ACD32)
+ 85 107  47    darkolivegreen (#556B2F)
+173 255  47    greenyellow (#ADFF2F)
+127 255   0    chartreuse (#7FFF00)
+124 252   0    lawngreen (#7CFC00)
+143 188 143    darkseagreen (#8FBC8F)
+ 34 139  34    forestgreen (#228B22)
+ 50 205  50    limegreen (#32CD32)
+144 238 144    lightgreen (#90EE90)
+152 251 152    palegreen (#98FB98)
+  0 100   0    darkgreen (#006400)
+  0 128   0    green (#008000)
+  0 255   0    lime (#00FF00)
+240 255 240    honeydew (#F0FFF0)
+ 46 139  87    seagreen (#2E8B57)
+ 60 179 113    mediumseagreen (#3CB371)
+  0 255 127    springgreen (#00FF7F)
+245 255 250    mintcream (#F5FFFA)
+  0 250 154    mediumspringgreen (#00FA9A)
+102 205 170    mediumaquamarine (#66CDAA)
+127 255 212    aquamarine (#7FFFD4)
+ 64 224 208    turquoise (#40E0D0)
+ 32 178 170    lightseagreen (#20B2AA)
+ 72 209 204    mediumturquoise (#48D1CC)
+ 47  79  79    darkslategray (#2F4F4F)
+175 238 238    paleturquoise (#AFEEEE)
+  0 128 128    teal (#008080)
+  0 139 139    darkcyan (#008B8B)
+  0 255 255    cyan (#00FFFF)
+224 255 255    lightcyan (#E0FFFF)
+240 255 255    azure (#F0FFFF)
+  0 206 209    darkturquoise (#00CED1)
+ 95 158 160    cadetblue (#5F9EA0)
+176 224 230    powderblue (#B0E0E6)
+173 216 230    lightblue (#ADD8E6)
+  0 191 255    deepskyblue (#00BFFF)
+135 206 235    skyblue (#87CEEB)
+135 206 250    lightskyblue (#87CEFA)
+ 70 130 180    steelblue (#4682B4)
+240 248 255    aliceblue (#F0F8FF)
+ 30 144 255    dodgerblue (#1E90FF)
+112 128 144    slategray (#708090)
+119 136 153    lightslategray (#778899)
+176 196 222    lightsteelblue (#B0C4DE)
+100 149 237    cornflowerblue (#6495ED)
+ 65 105 225    royalblue (#4169E1)
+ 25  25 112    midnightblue (#191970)
+230 230 250    lavender (#E6E6FA)
+  0   0 128    navy (#000080)
+  0   0 139    darkblue (#00008B)
+  0   0 205    mediumblue (#0000CD)
+  0   0 255    blue (#0000FF)
+248 248 255    ghostwhite (#F8F8FF)
+106  90 205    slateblue (#6A5ACD)
+ 72  61 139    darkslateblue (#483D8B)
+123 104 238    mediumslateblue (#7B68EE)
+147 112 219    mediumpurple (#9370DB)
+138  43 226    blueviolet (#8A2BE2)
+ 75   0 130    indigo (#4B0082)
+153  50 204    darkorchid (#9932CC)
+148   0 211    darkviolet (#9400D3)
+186  85 211    mediumorchid (#BA55D3)
+216 191 216    thistle (#D8BFD8)
+221 160 221    plum (#DDA0DD)
+238 130 238    violet (#EE82EE)
+128   0 128    purple (#800080)
+139   0 139    darkmagenta (#8B008B)
+255   0 255    magenta (#FF00FF)
+218 112 214    orchid (#DA70D6)
+199  21 133    mediumvioletred (#C71585)
+255  20 147    deeppink (#FF1493)
+255 105 180    hotpink (#FF69B4)
+255 240 245    lavenderblush (#FFF0F5)
+219 112 147    palevioletred (#DB7093)
+220  20  60    crimson (#DC143C)
+255 192 203    pink (#FFC0CB)
+255 182 193    lightpink (#FFB6C1)
+102  51 153     rebeccapurple (#663399)
diff --git a/contrib/gstyle/tests/data/palette.xml b/contrib/gstyle/tests/data/palette.xml
new file mode 100644
index 0000000..f62c42d
--- /dev/null
+++ b/contrib/gstyle/tests/data/palette.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+-->
+<palette id="basic" _name="Basic">
+
+  <color name="color_hex6"           value="#808080"/>
+  <color name="color_hex3"           value="#1aF"/>
+  <color name="color_rgb"            value="rgb(100, 200, 50)"/>
+  <color name="color_rgb_percent"    value="rgb(10%, 50%, 70%)"/>
+  <color name="color_rgba"           value="rgba(0, 10, 70, 1)"/>
+  <color name="color_rgba_percent"   value="rgba(10%, 50%, 40%, 0.5)"/>
+  <color name="color_hsl"            value="hsl(100, 100%, 50%)"/>
+  <color name="color_hsla"           value="hsla(400, 50%, 40%, 0.5)"/>
+  <color name="color_named"          value="aliceblue"/>
+
+</palette>
diff --git a/contrib/gstyle/tests/test-gstyle-color-panel.c b/contrib/gstyle/tests/test-gstyle-color-panel.c
new file mode 100644
index 0000000..fd232cf
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-color-panel.c
@@ -0,0 +1,78 @@
+/* test-gstyle-color-panel.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-color-panel.h"
+
+static void
+test_color_panel (void)
+{
+  GtkWidget *window;
+  GtkWidget *box;
+  GstyleColorPanel *color_panel;
+  GstylePaletteWidget *palette_widget;
+  GstylePalette *palette;
+  GFile *file;
+
+  gtk_init (NULL, NULL);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_default_size (GTK_WINDOW (window), 400,900);
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "orientation", GTK_ORIENTATION_VERTICAL,
+                      "expand", TRUE,
+                      "spacing", 1,
+                      NULL);
+
+  color_panel = g_object_new (GSTYLE_TYPE_COLOR_PANEL, NULL);
+  g_object_ref (color_panel);
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (color_panel));
+
+  palette_widget = gstyle_color_panel_get_palette_widget (color_panel);
+
+  file = g_file_new_for_path (TEST_DATA_DIR"/palette.gpl");
+  palette = gstyle_palette_new_from_file (file, NULL, NULL);
+  gstyle_palette_widget_add (palette_widget, palette);
+  g_object_unref (file);
+
+  file = g_file_new_for_path (TEST_DATA_DIR"/palette.xml");
+  palette = gstyle_palette_new_from_file (file, NULL, NULL);
+  gstyle_palette_widget_add (palette_widget, palette);
+  g_object_unref (file);
+
+  gtk_container_add (GTK_CONTAINER (window), box);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  gtk_widget_show_all (window);
+  gtk_main ();
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/Gstyle/colorpanel", test_color_panel);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/tests/test-gstyle-color-plane.c b/contrib/gstyle/tests/test-gstyle-color-plane.c
new file mode 100644
index 0000000..811fe16
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-color-plane.c
@@ -0,0 +1,142 @@
+/* test-gstyle-color-plane.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-color-plane.h"
+
+static void
+mode_changed (GstyleColorPlane *self,
+              GtkComboBox      *mode_box)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *mode_store;
+  GstyleColorPlaneMode mode;
+
+  g_assert (GSTYLE_IS_COLOR_PLANE (self));
+  g_assert (GTK_IS_COMBO_BOX (mode_box));
+
+  mode_store = gtk_combo_box_get_model (mode_box);
+  if (gtk_combo_box_get_active_iter (mode_box, &iter))
+    {
+      gtk_tree_model_get (mode_store, &iter, 0, &mode, -1);
+      gstyle_color_plane_set_mode (self, mode);
+    }
+}
+
+static void
+test_color_plane (void)
+{
+  g_autoptr (GtkBuilder) builder = NULL;
+  GtkWidget *window;
+  GtkWidget *mode_box;
+  GtkListStore *mode_store;
+  GtkWidget *hue_scale;
+  GtkWidget *saturation_scale;
+  GtkWidget *value_scale;
+  GtkWidget *cielab_l_scale;
+  GtkWidget *cielab_a_scale;
+  GtkWidget *cielab_b_scale;
+  GtkWidget *red_scale;
+  GtkWidget *green_scale;
+  GtkWidget *blue_scale;
+  GtkWidget *box;
+  GstyleColorPlane *plane;
+  GError *error = NULL;
+
+  gtk_init (NULL, NULL);
+  builder = gtk_builder_new ();
+
+  gtk_builder_add_from_file (builder, TEST_DATA_DIR"/gstyle-color-editor.ui", &error);
+  g_assert_no_error (error);
+
+  plane = GSTYLE_COLOR_PLANE (gtk_builder_get_object (builder, "plane"));
+
+  hue_scale = GTK_WIDGET (gtk_builder_get_object (builder, "hsv_h_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (hue_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_HSV_H));
+
+  saturation_scale = GTK_WIDGET (gtk_builder_get_object (builder, "hsv_s_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (saturation_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_HSV_S));
+
+  value_scale = GTK_WIDGET (gtk_builder_get_object (builder, "hsv_v_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (value_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_HSV_V));
+
+  cielab_l_scale = GTK_WIDGET (gtk_builder_get_object (builder, "cielab_l_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (cielab_l_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_LAB_L));
+
+  cielab_a_scale = GTK_WIDGET (gtk_builder_get_object (builder, "cielab_a_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (cielab_a_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_LAB_A));
+
+  cielab_b_scale = GTK_WIDGET (gtk_builder_get_object (builder, "cielab_b_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (cielab_b_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_LAB_A));
+
+  red_scale = GTK_WIDGET (gtk_builder_get_object (builder, "rgb_red_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (red_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_RGB_RED));
+
+  green_scale = GTK_WIDGET (gtk_builder_get_object (builder, "rgb_green_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (green_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_RGB_RED));
+
+  blue_scale = GTK_WIDGET (gtk_builder_get_object (builder, "rgb_blue_scale"));
+  gtk_range_set_adjustment (GTK_RANGE (blue_scale),
+                            gstyle_color_plane_get_component_adjustment (plane, 
GSTYLE_COLOR_COMPONENT_RGB_BLUE));
+
+  mode_box = GTK_WIDGET (gtk_builder_get_object (builder, "mode_box"));
+  mode_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "mode_store"));
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_HUE, 1, "Hsv Hue", -1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_SATURATION, 1, "Hsv 
Saturation", -1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_BRIGHTNESS, 1, "Hsv 
Brightness (Value)", -1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_CIELAB_L, 1, "CieLab 
L*", -1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_CIELAB_A, 1, "CieLab 
a*", -1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_CIELAB_B, 1, "CieLab 
b*", -1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_RED, 1, "rgb red", -1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_GREEN, 1, "rgb green", 
-1);
+  gtk_list_store_insert_with_values (mode_store, NULL, -1, 0, GSTYLE_COLOR_PLANE_MODE_BLUE, 1, "rgb blue", 
-1);
+
+  gtk_combo_box_set_active (GTK_COMBO_BOX (mode_box), 0);
+  g_signal_connect_swapped (mode_box, "changed", G_CALLBACK (mode_changed), plane);
+
+  box = GTK_WIDGET (gtk_builder_get_object (builder, "editor_box"));
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_container_add (GTK_CONTAINER (window), box);
+  gtk_window_set_default_size (GTK_WINDOW (window), 400,400);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  gtk_widget_show_all (window);
+  gtk_main ();
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/Gstyle/colorplane", test_color_plane);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/tests/test-gstyle-color-scale.c b/contrib/gstyle/tests/test-gstyle-color-scale.c
new file mode 100644
index 0000000..43f6544
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-color-scale.c
@@ -0,0 +1,70 @@
+/* test-gstyle-color-scale.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-color-scale.h"
+
+static void
+test_color_scale (void)
+{
+  GtkWidget *window;
+  GtkWidget *box;
+  GstyleColorScale *color_scale;
+  GtkAdjustment *adj;
+
+  gtk_init (NULL, NULL);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_default_size (GTK_WINDOW (window), 400,100);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "orientation", GTK_ORIENTATION_HORIZONTAL,
+                      "expand", TRUE,
+                      "spacing", 1,
+                      NULL);
+
+  gtk_container_add (GTK_CONTAINER (window), box);
+
+  adj = gtk_adjustment_new (0.0, 0.0, 360.0, 0.1, 1.0, 0.0);
+  color_scale = g_object_new (GSTYLE_TYPE_COLOR_SCALE,
+                              "adjustment", adj,
+                              "draw-value", FALSE,
+                              "expand", TRUE,
+                              "valign", GTK_ALIGN_CENTER,
+                              "halign", GTK_ALIGN_FILL,
+                              NULL);
+
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (color_scale));
+
+  gtk_widget_show_all (window);
+  gtk_main ();
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_add_func ("/Gstyle/colorscale", test_color_scale);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/tests/test-gstyle-color-widget.c b/contrib/gstyle/tests/test-gstyle-color-widget.c
new file mode 100644
index 0000000..83c82d1
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-color-widget.c
@@ -0,0 +1,85 @@
+/* test-gstyle-color-widget.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-color-widget.h"
+
+static GstyleColorWidget *
+create_color_swatch (const gchar *color_str)
+{
+  GstyleColor *color;
+  GstyleColorWidget *swatch;
+
+  color = gstyle_color_new_from_string ("test", color_str);
+
+  swatch = g_object_new (GSTYLE_TYPE_COLOR_WIDGET,
+                         "halign", GTK_ALIGN_FILL,
+                         "color", color,
+                         "name-visible", FALSE,
+                         "fallback-name-visible", FALSE,
+                         NULL);
+
+  return swatch;
+}
+
+static void
+test_color_widget (void)
+{
+  GtkWidget *window;
+  GtkWidget *box;
+  GstyleColorWidget *swatch;
+
+  gtk_init (NULL, NULL);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_default_size (GTK_WINDOW (window), 200,100);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "orientation", GTK_ORIENTATION_HORIZONTAL,
+                      "expand", TRUE,
+                      "spacing", 1,
+                      NULL);
+
+  gtk_container_add (GTK_CONTAINER (window), box);
+
+  swatch = create_color_swatch ("#5080FF");
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (swatch));
+
+  swatch = create_color_swatch ("#8010A0");
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (swatch));
+
+  swatch = create_color_swatch ("rgba(0, 100, 200, 0.5)");
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (swatch));
+
+  gtk_widget_show_all (window);
+  gtk_main ();
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_add_func ("/Gstyle/colorwidget", test_color_widget);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/tests/test-gstyle-color.c b/contrib/gstyle/tests/test-gstyle-color.c
new file mode 100644
index 0000000..4cdaf5b
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-color.c
@@ -0,0 +1,397 @@
+/* test-gstyle-color.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-color.h"
+#include "gstyle-color-component.h"
+#include "gstyle-cielab.h"
+#include "gstyle-color-convert.h"
+#include "gstyle-color-item.h"
+#include "gstyle-xyz.h"
+
+typedef struct
+{
+  gdouble l1;
+  gdouble a1;
+  gdouble b1;
+
+  gdouble l2;
+  gdouble a2;
+  gdouble b2;
+
+  gdouble delta_e;
+} ColorItem;
+
+static ColorItem lab_table[] =
+{
+  {   0,  100, -100,   0,  100, -100, 0.0 },
+  {   0, -100,  100,   0, -100,  100, 0.0 },
+  {   0,    0,  100,   0,    0,  100, 0.0 },
+  { 100,  100,  100, 100,  100,  100, 0.0 },
+  { 100,    0,    0, 100,    0,    0, 0.0 },
+  {  53,   80,   67,  47,   67,   47, 8.372140 },
+  {  10,   20,   30,  10,   20,   31, 0.518452 },
+  {  10,  -10,   10,  11,   -9,    9, 1.184177 },
+  { 100, -128,    0,  99, -128,    5, 1.817340 },
+  {  75,  -50,    0,  70,  -50,    5, 4.708821 },
+  { 0 }
+};
+
+/* TODO: use a speific color table with results to compare */
+static void
+test_deltae (void)
+{
+  ColorItem *item;
+  GstyleCielab lab1, lab2;
+  gdouble calc_delta_e, delta_e;
+
+  printf ("\n");
+
+  for (gint n = 0; n < G_N_ELEMENTS (lab_table); ++n)
+    {
+      item = &lab_table[n];
+      lab1.l = item->l1;
+      lab1.a = item->a1;
+      lab1.b = item->b1;
+      lab2.l = item->l2;
+      lab2.a = item->a2;
+      lab2.b = item->b2;
+      delta_e = item->delta_e;
+
+      calc_delta_e = gstyle_color_delta_e (&lab1, &lab2);
+      printf ("lab(%f, %f, %f) vs lab(%f, %f, %f) deltaE (%f): %f\n",
+              lab1.l, lab1.a, lab1.b,
+              lab2.l, lab2.a, lab2.b,
+              delta_e, calc_delta_e);
+
+      g_assert (delta_e > calc_delta_e - 1e-3 && delta_e < calc_delta_e + 1e-3);
+    }
+}
+
+#define RGB_INC (1.0 / 255.0)
+#define RGB_SAMPLES (255.0 * 255.0 * 255.0)
+
+#define HSV_H_INC (1.0 / 360.0)
+#define HSV_SV_INC (1.0 / 100.0)
+#define HSV_SAMPLES (360.0 * 100.0 * 100.0)
+
+#define LAB_L_INC (1.0)
+#define LAB_AB_INC (1.0)
+#define LAB_SAMPLES (100.0 * 256.0 * 256.0)
+
+static void
+delta_rgb ()
+{
+  GdkRGBA src_rgba,dst_rgba;
+  GdkRGBA max_src_r_rgba, max_src_g_rgba, max_src_b_rgba;
+  GdkRGBA max_dst_r_rgba;
+  G_GNUC_UNUSED GdkRGBA max_dst_g_rgba, max_dst_b_rgba ;
+  GstyleXYZ xyz, max_r_xyz, max_g_xyz, max_b_xyz;
+  gdouble r, g, b;
+  GdkRGBA delta_rgba;
+  gdouble dr_max = 0.0;
+  gdouble dg_max = 0.0;
+  gdouble db_max = 0.0;
+  gdouble dr_min = 0.0;
+  gdouble dg_min = 0.0;
+  gdouble db_min = 0.0;
+  gdouble dr_moy = 0.0;
+  gdouble dg_moy = 0.0;
+  gdouble db_moy = 0.0;
+  gdouble start_time, time;
+
+  start_time = g_get_monotonic_time ();
+
+  max_src_r_rgba.alpha = 0.0;
+  max_src_g_rgba.alpha = 0.0;
+  max_src_b_rgba.alpha = 0.0;
+  max_dst_r_rgba.alpha = 0.0;
+  max_dst_g_rgba.alpha = 0.0;
+  max_dst_b_rgba.alpha = 0.0;
+
+  /* rgb to xyz */
+  for (r = 0.0; r <= 1.0; r += RGB_INC)
+    {
+      for (g = 0.0; g <= 1.0; g += RGB_INC)
+        {
+          for (b = 0.0; b <= 1.0; b += RGB_INC)
+            {
+              src_rgba.red = r;
+              src_rgba.green = g;
+              src_rgba.blue = b;
+
+              gstyle_color_convert_rgb_to_xyz (&src_rgba, &xyz);
+              gstyle_color_convert_xyz_to_rgb (&xyz, &dst_rgba);
+
+              delta_rgba.red = src_rgba.red - dst_rgba.red;
+              delta_rgba.green = src_rgba.green - dst_rgba.green;
+              delta_rgba.blue = src_rgba.blue - dst_rgba.blue;
+
+              dr_moy += ABS (delta_rgba.red);
+              dg_moy += ABS (delta_rgba.green);
+              db_moy += ABS (delta_rgba.blue);
+
+              if (ABS (delta_rgba.red) > dr_max)
+                {
+                  dr_max = ABS (delta_rgba.red);
+                  max_src_r_rgba = src_rgba;
+                  max_dst_r_rgba = dst_rgba;
+                  max_r_xyz = xyz;
+                }
+
+              if (ABS (delta_rgba.green) > dg_max)
+                {
+                  dg_max = ABS (delta_rgba.green);
+                  max_src_g_rgba = src_rgba;
+                  max_dst_g_rgba = dst_rgba;
+                  max_g_xyz = xyz;
+                }
+
+              if (ABS (delta_rgba.blue) > db_max)
+                {
+                  db_max = ABS (delta_rgba.blue);
+                  max_src_b_rgba = src_rgba;
+                  max_dst_b_rgba = dst_rgba;
+                  max_b_xyz = xyz;
+                }
+
+              dr_min = MIN (dr_min, ABS (delta_rgba.red));
+              dg_min = MIN (dg_min, ABS (delta_rgba.green));
+              db_min = MIN (db_min, ABS (delta_rgba.blue));
+            }
+        }
+    }
+
+  time = g_get_monotonic_time () - start_time;
+  dr_moy /= 255.0 * 255.0 * 255.0;
+  dg_moy /= 255.0 * 255.0 * 255.0;
+  db_moy /= 255.0 * 255.0 * 255.0;
+
+  printf ("\nRGB -> XYZ -> RGB:\n");
+  printf ("red:\n\tΔmax: %f%% (normalized/255: %f)\n\tΔmin: %f%% (normalized/255: %f)\n\tΔmoy: 
%f%%(normalized/255: %f)\n\n",
+          dr_max, dr_max * 255.0, dr_min, dr_min * 255.0, dr_moy, dr_moy * 255.0);
+  printf ("green:\n\tΔmax: %f%% (normalized/255: %f)\n\tΔmin: %f%% (normalized/255: %f)\n\tΔmoy: 
%f%%(normalized/255: %f)\n\n",
+          dg_max, dg_max * 255.0, dg_min, dg_min * 255.0, dg_moy, dg_moy * 255.0);
+  printf ("blue:\n\tΔmax: %f%% (normalized/255: %f)\n\tΔmin: %f%% (normalized/255: %f)\n\tΔmoy: 
%f%%(normalized/255: %f)\n\n",
+          db_max, db_max * 255.0, db_min, db_min * 255.0, db_moy, db_moy * 255.0);
+
+  printf ("time micro sec: %f (per sample:%f) sec: %f\n\n", time, time / RGB_SAMPLES, time / 1.0e6);
+
+  printf ("max red src rgba:%s dst rgba:%s xyz:(%f, %f, %f)\n",
+          gdk_rgba_to_string (&max_src_r_rgba), gdk_rgba_to_string (&max_dst_r_rgba), max_r_xyz.x, 
max_r_xyz.y, max_r_xyz.z);
+  printf ("max green src rgba:%s dst rgba:%s xyz:(%f, %f, %f)\n",
+          gdk_rgba_to_string (&max_src_g_rgba), gdk_rgba_to_string (&max_dst_r_rgba), max_g_xyz.x, 
max_g_xyz.y, max_g_xyz.z);
+  printf ("max blue src rgba:%s dst rgba:%s xyz:(%f, %f, %f)\n",
+          gdk_rgba_to_string (&max_src_b_rgba), gdk_rgba_to_string (&max_dst_r_rgba), max_b_xyz.x, 
max_b_xyz.y, max_b_xyz.z);
+}
+
+static void
+delta_hsv ()
+{
+  gdouble src_h, src_s, src_v;
+  gdouble dst_h, dst_s, dst_v;
+  GstyleXYZ xyz;
+  gdouble dh = 0.0;
+  gdouble ds = 0.0;
+  gdouble dv = 0.0;
+  gdouble dh_max = 0.0;
+  gdouble ds_max = 0.0;
+  gdouble dv_max = 0.0;
+  gdouble dh_min = 0.0;
+  gdouble ds_min = 0.0;
+  gdouble dv_min = 0.0;
+  gdouble dh_moy = 0.0;
+  gdouble ds_moy = 0.0;
+  gdouble dv_moy = 0.0;
+  gdouble start_time, time;
+  gdouble max_src_hsv_h = 0.0;
+  gdouble max_src_hsv_s = 0.0;
+  gdouble max_src_hsv_v = 0.0;
+  gdouble max_dst_hsv_h = 0.0;
+  gdouble max_dst_hsv_s = 0.0;
+  gdouble max_dst_hsv_v = 0.0;
+
+  start_time = g_get_monotonic_time ();
+
+  /* rgb to xyz */
+  for (src_h = 0.0; src_h <= 1.0; src_h += HSV_H_INC)
+    {
+      for (src_s = 0.0; src_s <= 1.0; src_s += HSV_SV_INC)
+        {
+          for (src_v = 0.0; src_v <= 1.0; src_v += HSV_SV_INC)
+            {
+              gstyle_color_convert_hsv_to_xyz (src_h, src_s, src_v, &xyz);
+              gstyle_color_convert_xyz_to_hsv (&xyz, &dst_h, &dst_s, &dst_v);
+
+              dh = dst_h - src_h;
+              ds = dst_s - src_s;
+              dv = dst_v - src_v;
+
+              dh_moy += ABS (dh);
+              ds_moy += ABS (ds);
+              dv_moy += ABS (dv);
+
+              if (ABS(dh) > dh_max)
+                {
+                  dh_max = ABS (dh);
+                  max_src_hsv_h = src_h;
+                  max_src_hsv_s = src_s;
+                  max_src_hsv_v = src_v;
+                  max_dst_hsv_h = dst_h;
+                  max_dst_hsv_h = dst_s;
+                  max_dst_hsv_h = dst_v;
+                }
+
+              if (ABS(ds) > ds_max)
+                {
+                  ds_max = ABS (ds);
+                  max_src_hsv_h = src_h;
+                  max_src_hsv_s = src_s;
+                  max_src_hsv_v = src_v;
+                  max_dst_hsv_h = dst_h;
+                  max_dst_hsv_s = dst_s;
+                  max_dst_hsv_v = dst_v;
+                }
+
+              if (ABS(dv) > dv_max)
+                {
+                  dv_max = ABS (dv);
+                  max_src_hsv_h = src_h;
+                  max_src_hsv_s = src_s;
+                  max_src_hsv_v = src_v;
+                  max_dst_hsv_h = dst_h;
+                  max_dst_hsv_s = dst_s;
+                  max_dst_hsv_v = dst_v;
+                }
+
+              dh_min = MIN (dh_min, ABS (dh));
+              ds_min = MIN (ds_min, ABS (ds));
+              dv_min = MIN (dv_min, ABS (dv));
+            }
+        }
+    }
+
+  time = g_get_monotonic_time () - start_time;
+  dh_moy /= 360.0 * 100.0 * 100.0;
+  ds_moy /= 255.0 * 100.0 * 100.0;
+  dv_moy /= 255.0 * 100.0 * 100.0;
+
+  printf ("\nHSV -> XYZ -> HSV:\n");
+  printf ("hue:\n\tΔmax: %f%% (norm/360:%f)\n\tΔmin:%f%% (norm/360:%f)\n\tΔmoy:%f%% (norm/360:%f)\n\n",
+          dh_max, dh_max * 360.0, dh_min, dh_min * 360.0, dh_moy, dh_moy * 360.0);
+  printf ("saturation:\n\tΔmax:%f%% (norm/100:%f)\n\tΔmin:%f%% (norm/100:%f)\n\tΔmoy:%f%% (norm/100:%f)\n\n",
+          ds_max, ds_max * 100.0, ds_min, ds_min * 100.0, ds_moy, ds_moy * 100.0);
+  printf ("value:\n\tΔmax:%f%% (norm/100:%f)\n\tΔmin:%f%% (norm/100:%f)\n\tΔmoy:%f%% (norm/100:%f)\n\n",
+          dv_max, dv_min * 100.0, dv_min, dv_min * 100.0, dv_moy, dv_moy * 100.0);
+
+  printf ("time micro sec: %f (per sample:%f) sec: %f\n\n", time, time / HSV_SAMPLES, time / 1.0e6);
+
+  printf ("max hue src hsv(%f,%f,%f) dst hsv(%f,%f,%f)\n",
+          max_src_hsv_h, max_src_hsv_s, max_src_hsv_v,
+          max_dst_hsv_h, max_dst_hsv_s, max_dst_hsv_v);
+}
+
+static void
+delta_lab ()
+{
+  GstyleXYZ xyz;
+  GstyleCielab src_lab;
+  GstyleCielab dst_lab;
+  gdouble dl = 0.0;
+  gdouble da = 0.0;
+  gdouble db = 0.0;
+  gdouble dl_max = 0.0;
+  gdouble da_max = 0.0;
+  gdouble db_max = 0.0;
+  gdouble dl_min = 0.0;
+  gdouble da_min = 0.0;
+  gdouble db_min = 0.0;
+  gdouble dl_moy = 0.0;
+  gdouble da_moy = 0.0;
+  gdouble db_moy = 0.0;
+  gdouble start_time, time;
+
+  start_time = g_get_monotonic_time ();
+
+  /* rgb to xyz */
+  for (src_lab.l = 0.0; src_lab.l <= 100.0; src_lab.l += LAB_L_INC)
+    {
+      for (src_lab.a = -128.0; src_lab.a <= 128.0; src_lab.a += LAB_AB_INC)
+        {
+          for (src_lab.b = -128.0; src_lab.b <= 128.0; src_lab.b += LAB_AB_INC)
+            {
+              gstyle_color_convert_cielab_to_xyz (&src_lab, &xyz);
+              gstyle_color_convert_xyz_to_cielab (&xyz, &dst_lab);
+
+              dl = src_lab.l - dst_lab.l;
+              da = src_lab.a - dst_lab.a;
+              db = src_lab.b - dst_lab.b;
+
+              dl_moy += ABS (dl);
+              da_moy += ABS (da);
+              db_moy += ABS (db);
+
+              dl_max = MAX (dl_max, ABS (dl));
+              da_max = MAX (da_max, ABS (da));
+              db_max = MAX (db_max, ABS (db));
+
+              dl_min = MIN (dl_min, ABS (dl));
+              da_min = MIN (da_min, ABS (da));
+              db_min = MIN (db_min, ABS (db));
+            }
+        }
+    }
+
+  time = g_get_monotonic_time () - start_time;
+  dl_moy /= 100.0 * 256.0 * 256.0;
+  da_moy /= 100.0 * 256.0 * 256.0;
+  db_moy /= 100.0 * 256.0 * 256.0;
+
+  printf ("\nLAB -> XYZ -> LAB:\n");
+  printf ("L* in [0, 100]:\n\tΔl max: %f%%\n\tΔl min:%f%%\n\tΔl moy:%f%%\n\n",
+          dl_max, dl_min, dl_moy);
+  printf ("a* in [-128, +128]:\n\tΔa max: %f%%\n\tΔa min:%f\n\tΔa moy:%f%%\n\n",
+          da_max, da_min, da_moy);
+  printf ("b* in [-128, +128]:\n\tΔb max: %f%%\n\tΔb min:%f%%\n\tΔb moy:%f%%\n\n",
+          db_max, db_min, db_moy);
+
+  printf ("time micro sec: %f (per sample:%f) sec: %f\n\n", time, time / LAB_SAMPLES, time / 1.0e6);
+}
+
+static void
+test_conversion (void)
+{
+  delta_rgb ();
+  delta_hsv ();
+  delta_lab ();
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/Gstyle/deltaE", test_deltae);
+  g_test_add_func ("/Gstyle/conversion", test_conversion);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/tests/test-gstyle-palette-widget.c 
b/contrib/gstyle/tests/test-gstyle-palette-widget.c
new file mode 100644
index 0000000..296165e
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-palette-widget.c
@@ -0,0 +1,76 @@
+/* test-gstyle-palette-widget.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-palette-widget.h"
+
+static void
+test_palette_widget (void)
+{
+  GtkWidget *window;
+  GtkWidget *box;
+  GstylePaletteWidget *palette_widget;
+  GstylePalette *palette;
+  GFile *file;
+
+  gtk_init (NULL, NULL);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_default_size (GTK_WINDOW (window), 400,900);
+
+  box = g_object_new (GTK_TYPE_BOX,
+                      "orientation", GTK_ORIENTATION_HORIZONTAL,
+                      "expand", TRUE,
+                      "spacing", 1,
+                      NULL);
+
+  palette_widget = g_object_new (GSTYLE_TYPE_PALETTE_WIDGET, NULL);
+  gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (palette_widget));
+
+  file = g_file_new_for_path (TEST_DATA_DIR"/palette.gpl");
+  palette = gstyle_palette_new_from_file (file, NULL, NULL);
+  gstyle_palette_widget_add (palette_widget, palette);
+  g_object_unref (file);
+
+  file = g_file_new_for_path (TEST_DATA_DIR"/palette.xml");
+  palette = gstyle_palette_new_from_file (file, NULL, NULL);
+  gstyle_palette_widget_add (palette_widget, palette);
+  g_object_unref (file);
+
+  gstyle_palette_widget_show_palette (palette_widget, palette);
+
+  gtk_container_add (GTK_CONTAINER (window), box);
+  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+  gtk_widget_show_all (window);
+  gtk_main ();
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/Gstyle/palettewidget", test_palette_widget);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/tests/test-gstyle-palette.c b/contrib/gstyle/tests/test-gstyle-palette.c
new file mode 100644
index 0000000..2df7078
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-palette.c
@@ -0,0 +1,74 @@
+/* test-gstyle-palette.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-palette.h"
+
+static GstylePalette *
+load_palette (gchar *name)
+{
+  GstylePalette *palette;
+  g_autoptr (GFile) file = NULL;
+  g_autofree gchar *uri = NULL;
+  g_autofree gchar *path;
+  GError *error = NULL;
+  GCancellable *cancellable = NULL;
+
+  path = g_strdup_printf (TEST_DATA_DIR"/%s", name);
+  file = g_file_new_for_path (path);
+  palette = gstyle_palette_new_from_file (file, cancellable, &error);
+  if (palette == NULL)
+    printf ("error: %s\n", error->message);
+
+  uri = g_file_get_uri (file);
+
+  printf ("Palette:\n\turi:'%s'\n\tname:'%s'\n\tid:'%s'\n\tnb colors:%i\n",
+          uri,
+          gstyle_palette_get_name (palette),
+          gstyle_palette_get_id (palette),
+          gstyle_palette_get_len (palette));
+
+  return palette;
+}
+
+static void
+test_palette (void)
+{
+  GstylePalette *palette;
+
+  printf ("\n");
+  palette = load_palette ("palette.xml");
+  g_object_unref (palette);
+
+  palette = load_palette ("palette.gpl");
+  g_object_unref (palette);
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/Gstyle/palette", test_palette);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/tests/test-gstyle-parse.c b/contrib/gstyle/tests/test-gstyle-parse.c
new file mode 100644
index 0000000..9db0643
--- /dev/null
+++ b/contrib/gstyle/tests/test-gstyle-parse.c
@@ -0,0 +1,152 @@
+/* test-gstyle-parse.c
+ *
+ * Copyright (C) 2016 sebastien lafargue <slafargue gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "gstyle-color.h"
+#include "gstyle-color-convert.h"
+#include "gstyle-color-item.h"
+
+typedef struct
+{
+  gchar *rgb;
+
+  gdouble h;
+  gdouble s;
+  gdouble l;
+  gdouble a;
+} ColorItem;
+
+static ColorItem rgba_table[] =
+{
+  { "#000000",                    0,   0,   0, 1   },
+  { "#102030",                   16,  32,  48, 1   },
+  { "#FFFFFF",                  255, 255, 255, 1   },
+  { "#808080",                  128, 128, 128, 1   },
+  { "#1aF",                      17, 170, 255, 1   },
+  { "rgb(100, 200, 50)",        100, 200,  50, 1   },
+  { "rgb(10%, 50%, 70%)",        26, 128, 179, 1   },
+  { "rgba(10%, 50%, 40%, 0.5)",  26, 128, 102, 0.5 },
+  { "rgba(0, 10, 70, 1)",         0,  10,  70, 1   },
+  { "hsl(100, 100%, 50%)",       85, 255,   0, 1   },
+  { "hsl(250, 50%, 70%)",       153, 140, 217, 1   },
+  { "hsla(40, 50%, 40%, 0.5)",  153, 119,  51, 0.5 },
+  { "hsla(10, 10%, 70%, 1)",    186, 173, 171, 1   },
+  { "aliceblue",                240, 248, 255, 1   },
+  { "darkgray",                 169, 169, 169, 1   },
+  { "peru",                     205, 133,  63, 1   },
+  { 0 }
+};
+
+static void
+test_parse_text (void)
+{
+  GPtrArray *items;
+
+  static const gchar *text = "line-background=\"rgba(235,202,210,.4)\"\n"
+                             "foreground=\"rgba(100%, 50%, 25%,.4)\"\n"
+                             "color: #8d9091;\n"
+                             "color: #123;\n"
+                             "background-color: hsl(65, 70%, 72%);\n"
+                             "text-shadow: 0 1px black;";
+
+  printf ("\n");
+  items = gstyle_color_parse (text);
+  for (gint i = 0; i < items->len; ++i)
+    {
+      gchar *str;
+      const GstyleColor *color;
+      GstyleColorItem *item;
+      guint start, len;
+
+      item = g_ptr_array_index (items, i);
+      color = gstyle_color_item_get_color (item);
+      start = gstyle_color_item_get_start (item);
+      len = gstyle_color_item_get_len (item);
+      str = gstyle_color_to_string ((GstyleColor *)color, GSTYLE_COLOR_KIND_ORIGINAL);
+
+      printf ("item(%i,%i): '%s'\n", start, len, str);
+      g_free (str);
+    }
+
+  g_ptr_array_free (items, TRUE);
+}
+
+static void
+test_parse_string (void)
+{
+  ColorItem *item;
+  GstyleColor *color;
+  GdkRGBA rgba;
+  GstyleColorKind kind;
+  GstyleCielab lab;
+
+  printf ("\n");
+  for (item = rgba_table; item->rgb != NULL; item++)
+    {
+      g_autofree gchar *str_hex3 = NULL;
+      g_autofree gchar *str_hex6 = NULL;
+      g_autofree gchar *str_rgba = NULL;
+      g_autofree gchar *str_rgba_percent = NULL;
+      g_autofree gchar *str_hsla = NULL;
+      g_autofree gchar *str_original = NULL;
+      g_autofree gchar *dst_str = NULL;
+
+      color = gstyle_color_new_from_string (NULL, item->rgb);
+
+      str_hex3 = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGB_HEX3);
+      str_hex6 = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGB_HEX6);
+      str_rgba = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGBA);
+      str_rgba_percent = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_RGBA_PERCENT);
+      str_hsla = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_HSLA);
+      str_original = gstyle_color_to_string (color, GSTYLE_COLOR_KIND_ORIGINAL);
+
+      gstyle_color_fill_rgba (color, &rgba);
+      gstyle_color_convert_rgb_to_cielab (&rgba, &lab);
+
+      kind = gstyle_color_get_kind (color);
+      dst_str = gstyle_color_to_string (color, kind);
+
+      printf ("dst:'%s'\n", dst_str);
+
+
+      printf ("\n----- '%s': rgba: kind:%i\n%s\n%s\n%s\n%s\n%s\n Original: %s\n",
+              item->rgb, kind,
+              str_hex3, str_hex6, str_rgba, str_rgba_percent, str_hsla, str_original);
+
+      printf ("lab : L=%.3f a=%.3f b=%.3f\n", lab.l, lab.a, lab.b);
+
+      g_assert (g_ascii_strcasecmp (item->rgb, dst_str) == 0);
+      g_object_unref (color);
+      printf ("\n");
+    }
+}
+
+int
+main (gint   argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/Gstyle/parse_string", test_parse_string);
+  g_test_add_func ("/Gstyle/parse_text", test_parse_text);
+
+  return g_test_run ();
+}
diff --git a/contrib/gstyle/theme/gstyle.css b/contrib/gstyle/theme/gstyle.css
new file mode 100644
index 0000000..d3fa24d
--- /dev/null
+++ b/contrib/gstyle/theme/gstyle.css
@@ -0,0 +1,120 @@
+/* GstyleColorScale */
+
+gstylecolorscale {
+  padding: 12px;
+  background-clip: content-box;
+}
+
+gstylecolorscale highlight {
+  border: none;
+  padding: 0px;
+  margin: 0px;
+  background: transparent;
+}
+
+gstylecolorscale trough {
+  padding: 0px;
+  margin: 0px;
+  background: transparent;
+  border: none;
+  border-radius: 0px;
+  outline-offset: 6px;
+  -gtk-outline-radius: 0px;
+}
+
+gstylecolorscale contents {
+  border: solid white 1px;
+  padding: 0px;
+  margin: 0px;
+  background: transparent;
+}
+
+gstylecolorscale.horizontal contents{
+  min-height: 20px;
+}
+
+gstylecolorscale.vertical contents{
+  min-width: 20px;
+}
+
+gstylecolorscale.horizontal slider {
+  padding: 0px;
+  margin: -12px;
+  min-width: 0px;
+  min-height: 44px;
+  border: none;
+  box-shadow: none;
+  background-position: center;
+  background-size: auto 28px;
+  background-repeat: no-repeat;
+}
+
+gstylecolorscale.vertical slider {
+  padding: 0px;
+  margin: -12px;
+  min-width: 44px;
+  min-height: 0px;
+  border: none;
+  box-shadow: none;
+  background-position: center;
+  background-size: 28px auto;
+  background-repeat: no-repeat;
+}
+
+gstylecolorscale.horizontal slider {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical 2 png"));
+}
+gstylecolorscale.horizontal slider:backdrop {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-backdrop.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-backdrop 2 png"));
+}
+gstylecolorscale.horizontal slider:hover {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-hover.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-hover 2 png"));
+}
+gstylecolorscale.horizontal slider:disabled {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-insensitive.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-insensitive 2 png"));
+}
+gstylecolorscale.horizontal slider:backdrop:disabled {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-backdrop-insensitive.png"),
 url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-backdrop-insensitive 2 png"));
+}
+gstylecolorscale.horizontal slider:active {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-active.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-vertical-active 2 png"));
+}
+
+gstylecolorscale.vertical slider {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal 2 png"));
+}
+gstylecolorscale.vertical slider:backdrop {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-backdrop.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-backdrop 2 png"));
+}
+gstylecolorscale.vertical slider:hover {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-hover.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-hover 2 png"));
+}
+gstylecolorscale.vertical slider:disabled {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-insensitive.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-insensitive 2 png"));
+}
+gstylecolorscale.vertical slider:backdrop:disabled {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-backdrop-insensitive.png"),
 url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-backdrop-insensitive 2 png"));
+}
+gstylecolorscale.vertical slider:active {
+  background-image: 
-gtk-scaled(url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-active.png"), 
url("resource:///org/gnome/libgstyle/colorscale/color-scale-slider-horizontal-active 2 png"));
+}
+
+/* GstyleColorWidget */
+
+gstylecolorwidget label {
+  padding: 12px;
+}
+
+gstylecolorwidget {
+  background-color: white;
+}
+
+/* GstyleColorPanel */
+
+gstylecolorpanel revealer button.toggle {
+  margin: 6px;
+}
+
+gstyleslidein.shade {
+  color: rgba(77, 78, 83, 0.8);
+}
diff --git a/contrib/gstyle/ui/gstyle-color-panel.ui b/contrib/gstyle/ui/gstyle-color-panel.ui
new file mode 100644
index 0000000..66b7591
--- /dev/null
+++ b/contrib/gstyle/ui/gstyle-color-panel.ui
@@ -0,0 +1,1011 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="GstyleColorPanel" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="vexpand">True</property>
+    <property name="orientation">vertical</property>
+    <child>
+      <object class="GstyleSlidein" id="prefs_slidein">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="direction-type">right</property>
+        <property name="slide-fraction">1.0</property>
+        <property name="interpolate-size">true</property>
+        <property name="slide-margin">30</property>
+        <property name="duration">500</property>
+        <property name="hexpand">False</property>
+        <property name="vexpand">True</property>
+        <child>
+          <object class="GtkPaned">
+            <property name="visible">True</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="wide-handle">1</property>
+            <property name="orientation">vertical</property>
+            <property name="position">250</property>
+            <child>
+              <object class="GtkGrid">
+                <property name="name">editor_grid</property>
+                <property name="visible">1</property>
+                <property name="vexpand">False</property>
+                <property name="valign">fill</property>
+                <child>
+                  <object class="GstyleColorScale" id="ref_scale">
+                    <property name="kind">custom-data</property>
+                    <property name="visible">1</property>
+                    <property name="inverted">1</property>
+                    <property name="can_focus">1</property>
+                    <property name="halign">center</property>
+                    <property name="orientation">vertical</property>
+                    <property name="round_digits">1</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GstyleColorPlane" id="color_plane">
+                    <property name="width_request">150</property>
+                    <property name="height_request">150</property>
+                    <property name="expand">1</property>
+                    <property name="halign">fill</property>
+                    <property name="visible">1</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="swatchs_box">
+                    <property name="name">swatchs_box</property>
+                    <property name="visible">1</property>
+                    <property name="hexpand">1</property>
+                    <property name="homogeneous">1</property>
+                    <child>
+                      <object class="GstyleColorWidget" id="new_swatch">
+                        <property name="name">new_swatch</property>
+                        <property name="visible">1</property>
+                        <property name="vexpand">0</property>
+                        <property name="can_focus">1</property>
+                        <property name="receives_default">1</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GstyleColorWidget" id="old_swatch">
+                        <property name="name">old_swatch</property>
+                        <property name="name-visible">0</property>
+                        <property name="fallback-name-visible">0</property>
+                        <property name="visible">1</property>
+                        <property name="vexpand">0</property>
+                        <property name="can_focus">1</property>
+                        <property name="receives_default">1</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">2</property>
+                    <property name="width">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="picker_button">
+                    <property name="name">picker_button</property>
+                    <property name="visible">1</property>
+                    <property name="can_focus">1</property>
+                    <property name="receives_default">1</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                    <style>
+                      <class name="flat"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="icon-name">eyedropper-symbolic</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GstyleColorScale" id="alpha_scale">
+                    <property name="name">alpha_scale</property>
+                    <property name="kind">alpha</property>
+                    <property name="visible">1</property>
+                    <property name="can_focus">1</property>
+                    <property name="round_digits">1</property>
+                    <property name="hexpand">1</property>
+                    <property name="halign">fill</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="paned_box">
+                <property name="visible">1</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkBox" id="components_box1">
+                    <property name="orientation">vertical</property>
+                    <property name="visible">1</property>
+                    <child>
+                      <object class="GtkBox" id="components_controls">
+                        <property name="name">components_controls</property>
+                        <property name="visible">1</property>
+                        <child>
+                          <object class="GtkToggleButton" id="components_toggle">
+                            <property name="hexpand">1</property>
+                            <property name="xalign">0</property>
+                            <property name="visible">1</property>
+                            <property name="label" translatable="yes">Color Components</property>
+                          </object>
+                          <packing>
+                            <property name="expand">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkToggleButton" id="components_prefs_button">
+                            <property name="name">components_prefs_button</property>
+                            <property name="action-name">gstyle-pages-prefs.toggle-components-page</property>
+                            <property name="action-target">true</property>
+                            <property name="visible">1</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <style>
+                              <class name="image-button"/>
+                            </style>
+                            <child>
+                              <object class="GtkImage">
+                                <property name="icon-name">open-menu-symbolic</property>
+                                <property name="visible">true</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="pack-type">end</property>
+                            <property name="expand">0</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <style>
+                          <class name="reveal-bar"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GstyleRevealer" id="scale_reveal">
+                        <property name="visible">1</property>
+                        <child>
+                          <object class="GtkBox" id="scale_box">
+                            <property name="name">scale_box</property>
+                            <property name="visible">1</property>
+                            <property name="orientation">vertical</property>
+                            <child>
+                              <object class="GtkGrid" id="hsv_grid">
+                                <property name="visible">1</property>
+                                <child>
+                                  <object class="GtkToggleButton" id="hsv_h_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">H</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToggleButton" id="hsv_s_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">S</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToggleButton" id="hsv_v_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">V</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="hsv_h_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="hsv_s_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="hsv_v_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="hsv_h_spin">
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="hsv_s_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="hsv_v_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkGrid" id="lab_grid">
+                                <property name="visible">1</property>
+                                <child>
+                                  <object class="GtkToggleButton" id="lab_l_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">L*</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToggleButton" id="lab_a_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">a*</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToggleButton" id="lab_b_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">b*</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="lab_l_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="lab_a_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="lab_b_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="lab_l_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="lab_a_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="lab_b_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkGrid" id="rgb_grid">
+                                <property name="visible">1</property>
+                                <child>
+                                  <object class="GtkToggleButton" id="rgb_red_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">R</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToggleButton" id="rgb_green_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">G</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkToggleButton" id="rgb_blue_toggle">
+                                    <property name="visible">1</property>
+                                    <property name="label" translatable="yes">B</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="rgb_red_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="rgb_green_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GstyleColorScale" id="rgb_blue_scale">
+                                    <property name="kind">custom-data</property>
+                                    <property name="visible">1</property>
+                                    <property name="can_focus">1</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="round_digits">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="rgb_red_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="rgb_green_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSpinButton" id="rgb_blue_spin">
+                                    <property name="visible">1</property>
+                                    <property name="hexpand">0</property>
+                                    <property name="halign">start</property>
+                                    <property name="valign">center</property>
+                                    <property name="width-chars">6</property>
+                                    <property name="can_focus">1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkBox" id="string_box1">
+                    <property name="orientation">vertical</property>
+                    <property name="visible">1</property>
+                    <child>
+                      <object class="GtkBox" id="strings_controls">
+                        <property name="name">strings_controls</property>
+                        <property name="visible">1</property>
+                        <child>
+                          <object class="GtkToggleButton" id="strings_toggle">
+                            <property name="hexpand">1</property>
+                            <property name="xalign">0</property>
+                            <property name="visible">1</property>
+                            <property name="label" translatable="yes">Color strings</property>
+                          </object>
+                          <packing>
+                            <property name="expand">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkToggleButton" id="color_strings_prefs_button">
+                            <property name="name">color_strings_prefs_button</property>
+                            <property 
name="action-name">gstyle-pages-prefs.toggle-colorstrings-page</property>
+                            <property name="action-target">true</property>
+                            <property name="visible">1</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <style>
+                              <class name="image-button"/>
+                            </style>
+                            <child>
+                              <object class="GtkImage">
+                                <property name="icon-name">open-menu-symbolic</property>
+                                <property name="visible">true</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="pack-type">end</property>
+                            <property name="expand">0</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <style>
+                          <class name="reveal-bar"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GstyleRevealer" id="string_reveal">
+                        <property name="visible">1</property>
+                        <child>
+                          <object class="GtkBox" id="strings_box">
+                            <property name="name">strings_box</property>
+                            <property name="orientation">vertical</property>
+                            <property name="visible">1</property>
+                            <child>
+                              <object class="GtkSearchEntry" id="search_color_entry">
+                                <property name="name">search_color_entry</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="primary_icon_name">edit-find-symbolic</property>
+                                <property name="primary_icon_activatable">False</property>
+                                <property name="primary_icon_sensitive">False</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkGrid">
+                                <property name="visible">1</property>
+                                <property name="name">string_grid</property>
+                                <child>
+                                  <object class="GtkLabel" id="hex3_label">
+                                    <property name="visible">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">HEX3</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="hex6_label">
+                                    <property name="visible">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">HEX6</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="rgb_label">
+                                    <property name="visible">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">RGB</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="rgba_label">
+                                    <property name="visible">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">RGBA</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="hsl_label">
+                                    <property name="visible">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">HSL</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">4</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="hsla_label">
+                                    <property name="visible">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="label" translatable="yes">HSLA</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">0</property>
+                                    <property name="top_attach">5</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="res_hex3_label">
+                                    <property name="visible">1</property>
+                                    <property name="halign">fill</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="selectable">1</property>
+                                    <style>
+                                      <class name="selectable"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="res_hex6_label">
+                                    <property name="visible">1</property>
+                                    <property name="halign">fill</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="selectable">1</property>
+                                    <style>
+                                      <class name="selectable"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="res_rgb_label">
+                                    <property name="visible">1</property>
+                                    <property name="halign">fill</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="selectable">1</property>
+                                    <style>
+                                      <class name="selectable"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">2</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="res_rgba_label">
+                                    <property name="visible">1</property>
+                                    <property name="halign">fill</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="selectable">1</property>
+                                    <style>
+                                      <class name="selectable"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">3</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="res_hsl_label">
+                                    <property name="visible">1</property>
+                                    <property name="halign">fill</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="selectable">1</property>
+                                    <style>
+                                      <class name="selectable"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">4</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="res_hsla_label">
+                                    <property name="visible">1</property>
+                                    <property name="halign">fill</property>
+                                    <property name="hexpand">1</property>
+                                    <property name="xalign">0</property>
+                                    <property name="selectable">1</property>
+                                    <style>
+                                      <class name="selectable"/>
+                                    </style>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="top_attach">5</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkBox" id="palette_box1">
+                    <property name="orientation">vertical</property>
+                    <property name="visible">1</property>
+                    <child>
+                      <object class="GtkBox" id="palette_controls">
+                        <property name="name">palette_controls</property>
+                        <property name="visible">1</property>
+                        <child>
+                          <object class="GtkToggleButton" id="palette_toggle">
+                            <property name="name">palette_toggle</property>
+                            <property name="hexpand">1</property>
+                            <property name="xalign">0</property>
+                            <property name="visible">1</property>
+                            <child>
+                              <object class="GtkLabel">
+                                <property name="width-chars">20</property>
+                                <property name="ellipsize">end</property>
+                                <property name="label" translatable="yes">Palettes</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkToggleButton" id="palettes_list_prefs_button">
+                            <property name="name">palettes_list_prefs_button</property>
+                            <property 
name="action-name">gstyle-pages-prefs.toggle-paletteslist-page</property>
+                            <property name="action-target">true</property>
+                            <property name="visible">1</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <style>
+                              <class name="image-button"/>
+                            </style>
+                            <child>
+                              <object class="GtkImage">
+                                <property name="icon-name">applications-graphics-symbolic</property>
+                                <property name="visible">true</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="pack-type">end</property>
+                            <property name="expand">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkToggleButton" id="palettes_prefs_button">
+                            <property name="name">palettes_prefs_button</property>
+                            <property name="action-name">gstyle-pages-prefs.toggle-palettes-page</property>
+                            <property name="action-target">true</property>
+                            <property name="visible">1</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <style>
+                              <class name="image-button"/>
+                            </style>
+                            <child>
+                              <object class="GtkImage">
+                                <property name="icon-name">open-menu-symbolic</property>
+                                <property name="visible">true</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="pack-type">end</property>
+                            <property name="expand">0</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <style>
+                          <class name="reveal-bar"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GstyleRevealer" id="palette_reveal">
+                        <property name="visible">1</property>
+                        <child>
+                          <object class="GstylePaletteWidget" id="palette_widget">
+                            <property name="visible">1</property>
+                            <property name="expand">true</property>
+                            <property name="placeholder">palette_widget_placeholder</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkBox" id="expand_box">
+                  <property name="visible">1</property>
+                  <property name="orientation">vertical</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">1</property>
+                <property name="shrink">0</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+        <child type="slide">
+          <object class="GtkStack" id="prefs_stack">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="interpolate_size">True</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkSizeGroup" id="size_toggle">
+    <widgets>
+      <widget name="hsv_h_toggle"/>
+      <widget name="hsv_s_toggle"/>
+      <widget name="hsv_v_toggle"/>
+      <widget name="lab_l_toggle"/>
+      <widget name="lab_a_toggle"/>
+      <widget name="lab_b_toggle"/>
+      <widget name="rgb_red_toggle"/>
+      <widget name="rgb_green_toggle"/>
+      <widget name="rgb_blue_toggle"/>
+    </widgets>
+  </object>
+  <object class="GtkBox" id="palette_widget_placeholder">
+    <property name="expand">true</property>
+    <property name="orientation">vertical</property>
+    <property name="spacing">12</property>
+    <property name="visible">true</property>
+    <child>
+      <object class="GtkImage">
+        <property name="icon-name">applications-graphics-symbolic</property>
+        <property name="pixel-size">64</property>
+        <property name="visible">true</property>
+        <style>
+          <class name="dim-label"/>
+        </style>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel">
+        <property name="label" translatable="yes">No open palettes</property>
+        <property name="visible">true</property>
+        <style>
+          <class name="dim-label"/>
+        </style>
+        <attributes>
+          <attribute name="scale" value="2.0"/>
+          <attribute name="weight" value="bold"/>
+        </attributes>
+      </object>
+    </child>
+    <child>
+      <object class="GtkLabel">
+        <property name="label" translatable="yes">Load or generate a palette by using the 
preferences</property>
+        <property name="wrap">true</property>
+        <property name="visible">true</property>
+        <style>
+          <class name="dim-label"/>
+        </style>
+      </object>
+    </child>
+  </object>
+  <object class="GtkPopover" id="palette_list_popover">
+    <property name="focus-on-click">false</property>
+    <property name="name">palette_popover</property>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="min-content-width">150</property>
+        <property name="max-content-width">400</property>
+        <property name="max-content-height">400</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkListBox" id="palette_list">
+            <property name="selection-mode">browse</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkPopover" id="search_strings_popover">
+    <property name="focus-on-click">false</property>
+    <property name="name">search_strings_popover</property>
+    <property name="width-request">300</property>
+    <property name="expand">0</property>
+    <property name="position">left</property>
+    <property name="modal">0</property>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="min-content-height">47</property>
+        <property name="max-content-width">400</property>
+        <property name="max-content-height">400</property>
+        <property name="expand">true</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkListBox" id="search_strings_list">
+            <property name="selection-mode">browse</property>
+            <property name="expand">true</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/contrib/gstyle/ui/gstyle-palette-widget.ui b/contrib/gstyle/ui/gstyle-palette-widget.ui
new file mode 100644
index 0000000..05f4171
--- /dev/null
+++ b/contrib/gstyle/ui/gstyle-palette-widget.ui
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.18"/>
+  <template class="GstylePaletteWidget" parent="GtkBin">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="vexpand">True</property>
+    <child>
+      <object class="GtkStack" id="view_stack">
+        <property name="visible">True</property>
+        <property name="expand">true</property>
+        <property name="vhomogeneous">false</property>
+        <child>
+          <object class="GtkScrolledWindow" id="list_scrolled_window">
+            <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+            <property name="visible">true</property>
+            <property name="expand">true</property>
+            <child>
+              <object class="GtkViewport" id="list_viewport">
+                <property name="expand">False</property>
+                <property name="valign">start</property>
+                <property name="visible">true</property>
+                <child>
+                  <object class="GtkListBox" id="listbox">
+                    <property name="name">palette_listbox</property>
+                    <property name="visible">True</property>
+                    <property name="expand">False</property>
+                    <property name="valign">start</property>
+                    <property name="selection-mode">single</property>
+                    <property name="activate-on-single-click">0</property>
+                    <property name="can_focus">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">list</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="flow_scrolled_window">
+            <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+            <property name="visible">true</property>
+            <property name="expand">true</property>
+            <child>
+              <object class="GtkViewport" id="flow_viewport">
+                <property name="expand">False</property>
+                <property name="valign">start</property>
+                <property name="visible">true</property>
+                <child>
+                  <object class="GtkFlowBox" id="flowbox">
+                    <property name="name">palette_flowbox</property>
+                    <property name="visible">True</property>
+                    <property name="selection-mode">single</property>
+                    <property name="min-children-per-line">2</property>
+                    <property name="max-children-per-line">10</property>
+                    <property name="column-spacing">0</property>
+                    <property name="row-spacing">0</property>
+                    <property name="homogeneous">true</property>
+                    <property name="expand">False</property>
+                    <property name="valign">start</property>
+                    <property name="can_focus">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="name">flow</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="placeholder_box">
+            <property name="visible">True</property>
+            <property name="expand">true</property>
+            <property name="valign">center</property>
+            <property name="can_focus">False</property>
+            <property name="margin">6</property>
+          </object>
+          <packing>
+            <property name="name">placeholder</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkPopover" id="palette_popover">
+    <property name="focus-on-click">false</property>
+    <property name="name">palette_popover</property>
+    <child>
+      <object class="GtkScrolledWindow">
+        <property name="min-content-width">150</property>
+        <property name="max-content-width">300</property>
+        <property name="max-content-height">600</property>
+        <property name="visible">true</property>
+        <child>
+          <object class="GtkListBox" id="palette_list">
+            <property name="selection-mode">browse</property>
+            <property name="visible">true</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 84b0fef..98798a6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -4,6 +4,10 @@ contrib/egg/egg-animation.c
 contrib/egg/egg-date-time.c
 contrib/egg/egg-file-chooser-entry.c
 contrib/egg/egg-search-bar.c
+contrib/gstyle/gstyle-palette.c
+contrib/gstyle/gstyle-color-panel.c
+contrib/gstyle/gstyle-color-plane.c
+contrib/gstyle/gstyle-palette-widget.c
 contrib/pnl/pnl-animation.c
 contrib/search/trie.c
 contrib/tmpl/tmpl-parser.c


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]