]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkcolorsel.c
Merge libgdk and libgtk
[~andy/gtk] / gtk / gtkcolorsel.c
index 29d828189e488938d7f1f4d09739d87b71708b4f..2f029ac333227b2997909679eb47afc8b4f725c2 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include <config.h>
-#include "gdkconfig.h"
-#include <math.h>
+#include "config.h"
 
-#include "gdk/gdkkeysyms.h"
 #include "gtkcolorsel.h"
+
+#include <math.h>
+#include <string.h>
+
+#include "gdk/gdk.h"
 #include "gtkhsv.h"
 #include "gtkwindow.h"
 #include "gtkselection.h"
 #include "gtksettings.h"
 #include "gtkstock.h"
 #include "gtkaccessible.h"
+#include "gtksizerequest.h"
 #include "gtkprivate.h"
 #include "gtkintl.h"
-#include "gtkalias.h"
 
-#include <string.h>
+
+/**
+ * SECTION:gtkcolorsel
+ * @Short_description: A widget used to select a color
+ * @Title: GtkColorSelection
+ *
+ * The #GtkColorSelection is a widget that is used to select
+ * a color.  It consists of a color wheel and number of sliders
+ * and entry boxes for color parameters such as hue, saturation,
+ * value, red, green, blue, and opacity.  It is found on the standard
+ * color selection dialog box #GtkColorSelectionDialog.
+ */
+
+
+/* Keep it in sync with gtksettings.c:default_color_palette */
+#define DEFAULT_COLOR_PALETTE   "black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90"
 
 /* Number of elements in the custom palatte */
 #define GTK_CUSTOM_PALETTE_WIDTH 10
 #define GTK_CUSTOM_PALETTE_HEIGHT 2
 
+#define CUSTOM_PALETTE_ENTRY_WIDTH   20
+#define CUSTOM_PALETTE_ENTRY_HEIGHT  20
+
+/* The cursor for the dropper */
+#define DROPPER_WIDTH 17
+#define DROPPER_HEIGHT 17
+#define DROPPER_STRIDE (DROPPER_WIDTH * 4)
+#define DROPPER_X_HOT 2
+#define DROPPER_Y_HOT 16
+
+#define SAMPLE_WIDTH  64
+#define SAMPLE_HEIGHT 28
+#define CHECK_SIZE 16  
+#define BIG_STEP 20
+
 /* Conversion between 0->1 double and and guint16. See
  * scale_round() below for more general conversions
  */
 #define SCALE(i) (i / 65535.)
 #define UNSCALE(d) ((guint16)(d * 65535 + 0.5))
-
+#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
 
 enum {
   COLOR_CHANGED,
@@ -83,7 +115,8 @@ enum {
   PROP_HAS_PALETTE,
   PROP_HAS_OPACITY_CONTROL,
   PROP_CURRENT_COLOR,
-  PROP_CURRENT_ALPHA
+  PROP_CURRENT_ALPHA,
+  PROP_CURRENT_RGBA
 };
 
 enum {
@@ -97,9 +130,8 @@ enum {
   COLORSEL_NUM_CHANNELS
 };
 
-typedef struct _ColorSelectionPrivate ColorSelectionPrivate;
 
-struct _ColorSelectionPrivate
+struct _GtkColorSelectionPrivate
 {
   guint has_opacity : 1;
   guint has_palette : 1;
@@ -136,13 +168,15 @@ struct _ColorSelectionPrivate
   /* Window for grabbing on */
   GtkWidget *dropper_grab_widget;
   guint32    grab_time;
+  GdkDevice *keyboard_device;
+  GdkDevice *pointer_device;
 
   /* Connection to settings */
   gulong settings_connection;
 };
 
 
-static void gtk_color_selection_destroy                (GtkObject               *object);
+static void gtk_color_selection_destroy                (GtkWidget               *widget);
 static void gtk_color_selection_finalize        (GObject                *object);
 static void update_color                       (GtkColorSelection       *colorsel);
 static void gtk_color_selection_set_property    (GObject                 *object,
@@ -163,7 +197,7 @@ static gboolean gtk_color_selection_grab_broken (GtkWidget               *widget
 static void     gtk_color_selection_set_palette_color   (GtkColorSelection *colorsel,
                                                          gint               index,
                                                          GdkColor          *color);
-static void    set_focus_line_attributes                (GtkWidget         *drawing_area,
+static void     set_focus_line_attributes               (GtkWidget         *drawing_area,
                                                         cairo_t           *cr,
                                                         gint              *focus_width);
 static void     default_noscreen_change_palette_func    (const GdkColor    *colors,
@@ -174,1138 +208,1596 @@ static void     default_change_palette_func             (GdkScreen       *screen,
 static void     make_control_relations                  (AtkObject         *atk_obj,
                                                          GtkWidget         *widget);
 static void     make_all_relations                      (AtkObject         *atk_obj,
-                                                         ColorSelectionPrivate *priv);
+                                                         GtkColorSelectionPrivate *priv);
+
+static void    hsv_changed                             (GtkWidget         *hsv,
+                                                        gpointer           data);
+static void    get_screen_color                        (GtkWidget         *button);
+static void    adjustment_changed                      (GtkAdjustment     *adjustment,
+                                                        gpointer           data);
+static void    opacity_entry_changed                   (GtkWidget         *opacity_entry,
+                                                        gpointer           data);
+static void    hex_changed                             (GtkWidget         *hex_entry,
+                                                        gpointer           data);
+static gboolean hex_focus_out                           (GtkWidget                *hex_entry, 
+                                                        GdkEventFocus     *event,
+                                                        gpointer           data);
+static void    color_sample_new                        (GtkColorSelection *colorsel);
+static void    make_label_spinbutton                   (GtkColorSelection *colorsel,
+                                                        GtkWidget        **spinbutton,
+                                                        gchar             *text,
+                                                        GtkWidget         *table,
+                                                        gint               i,
+                                                        gint               j,
+                                                        gint               channel_type,
+                                                        const gchar       *tooltip);
+static void    make_palette_frame                      (GtkColorSelection *colorsel,
+                                                        GtkWidget         *table,
+                                                        gint               i,
+                                                        gint               j);
+static void    set_selected_palette                    (GtkColorSelection *colorsel,
+                                                        int                x,
+                                                        int                y);
+static void    set_focus_line_attributes               (GtkWidget         *drawing_area,
+                                                        cairo_t           *cr,
+                                                        gint              *focus_width);
+static gboolean mouse_press                            (GtkWidget         *invisible,
+                                                        GdkEventButton    *event,
+                                                        gpointer           data);
+static void  palette_change_notify_instance (GObject    *object,
+                                            GParamSpec *pspec,
+                                            gpointer    data);
+static void update_palette (GtkColorSelection *colorsel);
+static void shutdown_eyedropper (GtkWidget *widget);
 
 static guint color_selection_signals[LAST_SIGNAL] = { 0 };
 
-static const gchar default_colors[] = "black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90";
-
 static GtkColorSelectionChangePaletteFunc noscreen_change_palette_hook = default_noscreen_change_palette_func;
 static GtkColorSelectionChangePaletteWithScreenFunc change_palette_hook = default_change_palette_func;
 
-/* The cursor for the dropper */
-#define DROPPER_WIDTH 17
-#define DROPPER_HEIGHT 17
-#define DROPPER_X_HOT 2
-#define DROPPER_Y_HOT 16
-
-
 static const guchar dropper_bits[] = {
-  0xff, 0x8f, 0x01, 0xff, 0x77, 0x01, 0xff, 0xfb, 0x00, 0xff, 0xf8, 0x00,
-  0x7f, 0xff, 0x00, 0xff, 0x7e, 0x01, 0xff, 0x9d, 0x01, 0xff, 0xd8, 0x01,
-  0x7f, 0xd4, 0x01, 0x3f, 0xee, 0x01, 0x1f, 0xff, 0x01, 0x8f, 0xff, 0x01,
-  0xc7, 0xff, 0x01, 0xe3, 0xff, 0x01, 0xf3, 0xff, 0x01, 0xfd, 0xff, 0x01,
-  0xff, 0xff, 0x01, };
-
-static const guchar dropper_mask[] = {
-  0x00, 0x70, 0x00, 0x00, 0xf8, 0x00, 0x00, 0xfc, 0x01, 0x00, 0xff, 0x01,
-  0x80, 0xff, 0x01, 0x00, 0xff, 0x00, 0x00, 0x7f, 0x00, 0x80, 0x3f, 0x00,
-  0xc0, 0x3f, 0x00, 0xe0, 0x13, 0x00, 0xf0, 0x01, 0x00, 0xf8, 0x00, 0x00,
-  0x7c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0d, 0x00, 0x00,
-  0x02, 0x00, 0x00, };
-
-
-/*
- *
- * The Sample Color
- *
- */
-#define SAMPLE_WIDTH  64
-#define SAMPLE_HEIGHT 28
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377"
+  "\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\0\0\0\377"
+  "\0\0\0\377\0\0\0\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377"
+  "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377"
+  "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0"
+  "\0\377\0\0\0\377\0\0\0\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\0\0\0\377\0\0\0\377\0"
+  "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377"
+  "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
+  "\0\0\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\0\0\0\377\0\0"
+  "\0\377\0\0\0\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377"
+  "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\377\377"
+  "\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
+  "\0\0\0\377\377\377\377\377\0\0\0\377\377\377\377\377\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377"
+  "\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\0\0\0\0\0\377\377"
+  "\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0"
+  "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377"
+  "\377\377\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377"
+  "\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\0\0"
+  "\0\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0\0\0\377\0\0\0"
+  "\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"};
 
-static void color_sample_draw_sample (GtkColorSelection *colorsel, int which);
-static void color_sample_update_samples (GtkColorSelection *colorsel);
+G_DEFINE_TYPE (GtkColorSelection, gtk_color_selection, GTK_TYPE_VBOX)
 
 static void
-set_color_internal (GtkColorSelection *colorsel,
-                   gdouble           *color)
+gtk_color_selection_class_init (GtkColorSelectionClass *klass)
 {
-  ColorSelectionPrivate *priv;
-  gint i;
+  GObjectClass *gobject_class;
+  GtkWidgetClass *widget_class;
   
-  priv = colorsel->private_data;
-  priv->changing = TRUE;
-  priv->color[COLORSEL_RED] = color[0];
-  priv->color[COLORSEL_GREEN] = color[1];
-  priv->color[COLORSEL_BLUE] = color[2];
-  priv->color[COLORSEL_OPACITY] = color[3];
-  gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
-                 priv->color[COLORSEL_GREEN],
-                 priv->color[COLORSEL_BLUE],
-                 &priv->color[COLORSEL_HUE],
-                 &priv->color[COLORSEL_SATURATION],
-                 &priv->color[COLORSEL_VALUE]);
-  if (priv->default_set == FALSE)
-    {
-      for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
-       priv->old_color[i] = priv->color[i];
-    }
-  priv->default_set = TRUE;
-  priv->default_alpha_set = TRUE;
-  update_color (colorsel);
-}
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = gtk_color_selection_finalize;
+  gobject_class->set_property = gtk_color_selection_set_property;
+  gobject_class->get_property = gtk_color_selection_get_property;
 
-static void
-set_color_icon (GdkDragContext *context,
-               gdouble        *colors)
-{
-  GdkPixbuf *pixbuf;
-  guint32 pixel;
+  widget_class = GTK_WIDGET_CLASS (klass);
+  widget_class->destroy = gtk_color_selection_destroy;
+  widget_class->realize = gtk_color_selection_realize;
+  widget_class->unrealize = gtk_color_selection_unrealize;
+  widget_class->show_all = gtk_color_selection_show_all;
+  widget_class->grab_broken_event = gtk_color_selection_grab_broken;
+  
+  g_object_class_install_property (gobject_class,
+                                   PROP_HAS_OPACITY_CONTROL,
+                                   g_param_spec_boolean ("has-opacity-control",
+                                                        P_("Has Opacity Control"),
+                                                        P_("Whether the color selector should allow setting opacity"),
+                                                        FALSE,
+                                                        GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                   PROP_HAS_PALETTE,
+                                   g_param_spec_boolean ("has-palette",
+                                                        P_("Has palette"),
+                                                        P_("Whether a palette should be used"),
+                                                        FALSE,
+                                                        GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                   PROP_CURRENT_COLOR,
+                                   g_param_spec_boxed ("current-color",
+                                                       P_("Current Color"),
+                                                       P_("The current color"),
+                                                       GDK_TYPE_COLOR,
+                                                       GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                   PROP_CURRENT_ALPHA,
+                                   g_param_spec_uint ("current-alpha",
+                                                     P_("Current Alpha"),
+                                                     P_("The current opacity value (0 fully transparent, 65535 fully opaque)"),
+                                                     0, 65535, 65535,
+                                                     GTK_PARAM_READWRITE));
 
-  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
-                          8, 48, 32);
+  /**
+   * GtkColorSelection:current-rgba
+   *
+   * The current RGBA color.
+   *
+   * Since: 3.0
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_CURRENT_RGBA,
+                                   g_param_spec_boxed ("current-rgba",
+                                                       P_("Current RGBA"),
+                                                       P_("The current RGBA color"),
+                                                       GDK_TYPE_RGBA,
+                                                       GTK_PARAM_READWRITE));
 
-  pixel = (((UNSCALE (colors[COLORSEL_RED])   & 0xff00) << 16) |
-          ((UNSCALE (colors[COLORSEL_GREEN]) & 0xff00) << 8) |
-          ((UNSCALE (colors[COLORSEL_BLUE])  & 0xff00)));
+  /**
+   * GtkColorSelection::color-changed:
+   * @colorselection: the object which received the signal.
+   *
+   * This signal is emitted when the color changes in the #GtkColorSelection
+   * according to its update policy.
+   */
+  color_selection_signals[COLOR_CHANGED] =
+    g_signal_new (I_("color-changed"),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_FIRST,
+                 G_STRUCT_OFFSET (GtkColorSelectionClass, color_changed),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__VOID,
+                 G_TYPE_NONE, 0);
 
-  gdk_pixbuf_fill (pixbuf, pixel);
-  
-  gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
-  g_object_unref (pixbuf);
+  g_type_class_add_private (gobject_class, sizeof (GtkColorSelectionPrivate));
 }
 
 static void
-color_sample_drag_begin (GtkWidget      *widget,
-                        GdkDragContext *context,
-                        gpointer        data)
+gtk_color_selection_init (GtkColorSelection *colorsel)
 {
-  GtkColorSelection *colorsel = data;
-  ColorSelectionPrivate *priv;
-  gdouble *colsrc;
-  
-  priv = colorsel->private_data;
+  GtkWidget *top_hbox;
+  GtkWidget *top_right_vbox;
+  GtkWidget *table, *label, *hbox, *frame, *vbox, *button;
+  GtkAdjustment *adjust;
+  GtkWidget *picker_image;
+  gint i, j;
+  GtkColorSelectionPrivate *priv;
+  AtkObject *atk_obj;
+  GList *focus_chain = NULL;
   
-  if (widget == priv->old_sample)
-    colsrc = priv->old_color;
-  else
-    colsrc = priv->color;
-
-  set_color_icon (context, colsrc);
-}
-
-static void
-color_sample_drag_end (GtkWidget      *widget,
-                      GdkDragContext *context,
-                      gpointer        data)
-{
-  g_object_set_data (G_OBJECT (widget), I_("gtk-color-selection-drag-window"), NULL);
-}
+  gtk_widget_push_composite_child ();
 
-static void
-color_sample_drop_handle (GtkWidget        *widget,
-                         GdkDragContext   *context,
-                         gint              x,
-                         gint              y,
-                         GtkSelectionData *selection_data,
-                         guint             info,
-                         guint             time,
-                         gpointer          data)
-{
-  GtkColorSelection *colorsel = data;
-  ColorSelectionPrivate *priv;
-  guint16 *vals;
-  gdouble color[4];
-  priv = colorsel->private_data;
+  priv = colorsel->private_data = G_TYPE_INSTANCE_GET_PRIVATE (colorsel, GTK_TYPE_COLOR_SELECTION, GtkColorSelectionPrivate);
+  priv->changing = FALSE;
+  priv->default_set = FALSE;
+  priv->default_alpha_set = FALSE;
   
-  /* This is currently a guint16 array of the format:
-   * R
-   * G
-   * B
-   * opacity
-   */
+  top_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+  gtk_box_pack_start (GTK_BOX (colorsel), top_hbox, FALSE, FALSE, 0);
   
-  if (selection_data->length < 0)
-    return;
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+  priv->triangle_colorsel = gtk_hsv_new ();
+  g_signal_connect (priv->triangle_colorsel, "changed",
+                    G_CALLBACK (hsv_changed), colorsel);
+  gtk_hsv_set_metrics (GTK_HSV (priv->triangle_colorsel), 174, 15);
+  gtk_box_pack_start (GTK_BOX (top_hbox), vbox, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), priv->triangle_colorsel, FALSE, FALSE, 0);
+  gtk_widget_set_tooltip_text (priv->triangle_colorsel,
+                        _("Select the color you want from the outer ring. Select the darkness or lightness of that color using the inner triangle."));
   
-  /* We accept drops with the wrong format, since the KDE color
-   * chooser incorrectly drops application/x-color with format 8.
-   */
-  if (selection_data->length != 8)
-    {
-      g_warning ("Received invalid color data\n");
-      return;
-    }
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
   
-  vals = (guint16 *)selection_data->data;
+  frame = gtk_frame_new (NULL);
+  gtk_widget_set_size_request (frame, -1, 30);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  color_sample_new (colorsel);
+  gtk_container_add (GTK_CONTAINER (frame), priv->sample_area);
+  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
   
-  if (widget == priv->cur_sample)
-    {
-      color[0] = (gdouble)vals[0] / 0xffff;
-      color[1] = (gdouble)vals[1] / 0xffff;
-      color[2] = (gdouble)vals[2] / 0xffff;
-      color[3] = (gdouble)vals[3] / 0xffff;
-      
-      set_color_internal (colorsel, color);
-    }
-}
+  button = gtk_button_new ();
 
-static void
-color_sample_drag_handle (GtkWidget        *widget,
-                         GdkDragContext   *context,
-                         GtkSelectionData *selection_data,
-                         guint             info,
-                         guint             time,
-                         gpointer          data)
-{
-  GtkColorSelection *colorsel = data;
-  ColorSelectionPrivate *priv;
-  guint16 vals[4];
-  gdouble *colsrc;
+  gtk_widget_set_events (button, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
+  g_object_set_data (G_OBJECT (button), I_("COLORSEL"), colorsel); 
+  g_signal_connect (button, "clicked",
+                    G_CALLBACK (get_screen_color), NULL);
+  picker_image = gtk_image_new_from_stock (GTK_STOCK_COLOR_PICKER, GTK_ICON_SIZE_BUTTON);
+  gtk_container_add (GTK_CONTAINER (button), picker_image);
+  gtk_widget_show (GTK_WIDGET (picker_image));
+  gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+
+  gtk_widget_set_tooltip_text (button,
+                        _("Click the eyedropper, then click a color anywhere on your screen to select that color."));
   
-  priv = colorsel->private_data;
+  top_right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+  gtk_box_pack_start (GTK_BOX (top_hbox), top_right_vbox, FALSE, FALSE, 0);
+  table = gtk_table_new (8, 6, FALSE);
+  gtk_box_pack_start (GTK_BOX (top_right_vbox), table, FALSE, FALSE, 0);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
   
-  if (widget == priv->old_sample)
-    colsrc = priv->old_color;
-  else
-    colsrc = priv->color;
-  
-  vals[0] = colsrc[COLORSEL_RED] * 0xffff;
-  vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
-  vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
-  vals[3] = priv->has_opacity ? colsrc[COLORSEL_OPACITY] * 0xffff : 0xffff;
-  
-  gtk_selection_data_set (selection_data,
-                         gdk_atom_intern_static_string ("application/x-color"),
-                         16, (guchar *)vals, 8);
-}
+  make_label_spinbutton (colorsel, &priv->hue_spinbutton, _("_Hue:"), table, 0, 0, COLORSEL_HUE,
+                         _("Position on the color wheel."));
+  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (priv->hue_spinbutton), TRUE);
+  make_label_spinbutton (colorsel, &priv->sat_spinbutton, _("_Saturation:"), table, 0, 1, COLORSEL_SATURATION,
+                         _("Intensity of the color."));
+  make_label_spinbutton (colorsel, &priv->val_spinbutton, _("_Value:"), table, 0, 2, COLORSEL_VALUE,
+                         _("Brightness of the color."));
+  make_label_spinbutton (colorsel, &priv->red_spinbutton, _("_Red:"), table, 6, 0, COLORSEL_RED,
+                         _("Amount of red light in the color."));
+  make_label_spinbutton (colorsel, &priv->green_spinbutton, _("_Green:"), table, 6, 1, COLORSEL_GREEN,
+                         _("Amount of green light in the color."));
+  make_label_spinbutton (colorsel, &priv->blue_spinbutton, _("_Blue:"), table, 6, 2, COLORSEL_BLUE,
+                         _("Amount of blue light in the color."));
+  gtk_table_attach_defaults (GTK_TABLE (table), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL), 0, 8, 3, 4); 
 
-/* which = 0 means draw old sample, which = 1 means draw new */
-static void
-color_sample_draw_sample (GtkColorSelection *colorsel, int which)
-{
-  GtkWidget *da;
-  gint x, y, wid, heig, goff;
-  ColorSelectionPrivate *priv;
-  cairo_t *cr;
-  
-  g_return_if_fail (colorsel != NULL);
-  priv = colorsel->private_data;
+  priv->opacity_label = gtk_label_new_with_mnemonic (_("Op_acity:")); 
+  gtk_misc_set_alignment (GTK_MISC (priv->opacity_label), 0.0, 0.5); 
+  gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_label, 0, 1, 4, 5); 
+  adjust = gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0);
+  g_object_set_data (G_OBJECT (adjust), I_("COLORSEL"), colorsel); 
+  priv->opacity_slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjust);
+  gtk_widget_set_tooltip_text (priv->opacity_slider,
+                        _("Transparency of the color."));
+  gtk_label_set_mnemonic_widget (GTK_LABEL (priv->opacity_label),
+                                 priv->opacity_slider);
+  gtk_scale_set_draw_value (GTK_SCALE (priv->opacity_slider), FALSE);
+  g_signal_connect (adjust, "value-changed",
+                    G_CALLBACK (adjustment_changed),
+                    GINT_TO_POINTER (COLORSEL_OPACITY));
+  gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_slider, 1, 7, 4, 5); 
+  priv->opacity_entry = gtk_entry_new (); 
+  gtk_widget_set_tooltip_text (priv->opacity_entry,
+                        _("Transparency of the color."));
+  gtk_widget_set_size_request (priv->opacity_entry, 40, -1); 
+
+  g_signal_connect (priv->opacity_entry, "activate",
+                    G_CALLBACK (opacity_entry_changed), colorsel);
+  gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_entry, 7, 8, 4, 5);
   
-  g_return_if_fail (priv->sample_area != NULL);
-  if (!GTK_WIDGET_DRAWABLE (priv->sample_area))
-    return;
+  label = gtk_label_new_with_mnemonic (_("Color _name:"));
+  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 5, 6);
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  priv->hex_entry = gtk_entry_new ();
 
-  if (which == 0)
-    {
-      da = priv->old_sample;
-      goff = 0;
-    }
-  else
-    {
-      da = priv->cur_sample;
-      goff =  priv->old_sample->allocation.width % 32;
-    }
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->hex_entry);
 
-  cr = gdk_cairo_create (da->window);
-  
-  wid = da->allocation.width;
-  heig = da->allocation.height;
+  g_signal_connect (priv->hex_entry, "activate",
+                    G_CALLBACK (hex_changed), colorsel);
 
-  /* Below needs tweaking for non-power-of-two */  
-#define CHECK_SIZE 16  
+  g_signal_connect (priv->hex_entry, "focus-out-event",
+                    G_CALLBACK (hex_focus_out), colorsel);
+
+  gtk_widget_set_tooltip_text (priv->hex_entry,
+                        _("You can enter an HTML-style hexadecimal color value, or simply a color name such as 'orange' in this entry."));
   
-  if (priv->has_opacity)
-    {
-      /* Draw checks in background */
+  gtk_entry_set_width_chars (GTK_ENTRY (priv->hex_entry), 7);
+  gtk_table_attach_defaults (GTK_TABLE (table), priv->hex_entry, 1, 5, 5, 6);
 
-      cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
-      cairo_rectangle (cr, 0, 0, wid, heig);
-      cairo_fill (cr);
+  focus_chain = g_list_append (focus_chain, priv->hue_spinbutton);
+  focus_chain = g_list_append (focus_chain, priv->sat_spinbutton);
+  focus_chain = g_list_append (focus_chain, priv->val_spinbutton);
+  focus_chain = g_list_append (focus_chain, priv->red_spinbutton);
+  focus_chain = g_list_append (focus_chain, priv->green_spinbutton);
+  focus_chain = g_list_append (focus_chain, priv->blue_spinbutton);
+  focus_chain = g_list_append (focus_chain, priv->opacity_slider);
+  focus_chain = g_list_append (focus_chain, priv->opacity_entry);
+  focus_chain = g_list_append (focus_chain, priv->hex_entry);
+  gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
+  g_list_free (focus_chain);
 
-      cairo_set_source_rgb (cr, 0.75, 0.75, 0.75);
-      for (x = goff & -CHECK_SIZE; x < goff + wid; x += CHECK_SIZE)
-       for (y = 0; y < heig; y += CHECK_SIZE)
-         if ((x / CHECK_SIZE + y / CHECK_SIZE) % 2 == 0)
-           cairo_rectangle (cr, x - goff, y, CHECK_SIZE, CHECK_SIZE);
-      cairo_fill (cr);
+  /* Set up the palette */
+  table = gtk_table_new (GTK_CUSTOM_PALETTE_HEIGHT, GTK_CUSTOM_PALETTE_WIDTH, TRUE);
+  gtk_table_set_row_spacings (GTK_TABLE (table), 1);
+  gtk_table_set_col_spacings (GTK_TABLE (table), 1);
+  for (i = 0; i < GTK_CUSTOM_PALETTE_WIDTH; i++)
+    {
+      for (j = 0; j < GTK_CUSTOM_PALETTE_HEIGHT; j++)
+       {
+         make_palette_frame (colorsel, table, i, j);
+       }
     }
+  set_selected_palette (colorsel, 0, 0);
+  priv->palette_frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+  label = gtk_label_new_with_mnemonic (_("_Palette:"));
+  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+  gtk_box_pack_start (GTK_BOX (priv->palette_frame), label, FALSE, FALSE, 0);
 
-  if (which == 0)
+  gtk_label_set_mnemonic_widget (GTK_LABEL (label),
+                                 priv->custom_palette[0][0]);
+  
+  gtk_box_pack_end (GTK_BOX (top_right_vbox), priv->palette_frame, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (priv->palette_frame), table, FALSE, FALSE, 0);
+  
+  gtk_widget_show_all (top_hbox);
+
+  /* hide unused stuff */
+  
+  if (priv->has_opacity == FALSE)
     {
-      cairo_set_source_rgba (cr,
-                            priv->old_color[COLORSEL_RED], 
-                            priv->old_color[COLORSEL_GREEN], 
-                            priv->old_color[COLORSEL_BLUE],
-                            priv->has_opacity ?
-                               priv->old_color[COLORSEL_OPACITY] : 1.0);
+      gtk_widget_hide (priv->opacity_label);
+      gtk_widget_hide (priv->opacity_slider);
+      gtk_widget_hide (priv->opacity_entry);
     }
-  else
+  
+  if (priv->has_palette == FALSE)
     {
-      cairo_set_source_rgba (cr,
-                            priv->color[COLORSEL_RED], 
-                            priv->color[COLORSEL_GREEN], 
-                            priv->color[COLORSEL_BLUE],
-                            priv->has_opacity ?
-                              priv->color[COLORSEL_OPACITY] : 1.0);
+      gtk_widget_hide (priv->palette_frame);
     }
 
-  cairo_rectangle (cr, 0, 0, wid, heig);
-  cairo_fill (cr);
+  atk_obj = gtk_widget_get_accessible (priv->triangle_colorsel);
+  if (GTK_IS_ACCESSIBLE (atk_obj))
+    {
+      atk_object_set_name (atk_obj, _("Color Wheel"));
+      atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (colorsel)), ATK_ROLE_COLOR_CHOOSER);
+      make_all_relations (atk_obj, priv);
+    } 
 
-  cairo_destroy (cr);
+  gtk_widget_pop_composite_child ();
 }
 
-
+/* GObject methods */
 static void
-color_sample_update_samples (GtkColorSelection *colorsel)
-{
-  ColorSelectionPrivate *priv = colorsel->private_data;
-  gtk_widget_queue_draw (priv->old_sample);
-  gtk_widget_queue_draw (priv->cur_sample);
-}
-
-static gboolean
-color_old_sample_expose (GtkWidget         *da,
-                        GdkEventExpose    *event,
-                        GtkColorSelection *colorsel)
+gtk_color_selection_finalize (GObject *object)
 {
-  color_sample_draw_sample (colorsel, 0);
-  return FALSE;
+  G_OBJECT_CLASS (gtk_color_selection_parent_class)->finalize (object);
 }
 
-
-static gboolean
-color_cur_sample_expose (GtkWidget         *da,
-                        GdkEventExpose    *event,
-                        GtkColorSelection *colorsel)
+static void
+gtk_color_selection_set_property (GObject         *object,
+                                 guint            prop_id,
+                                 const GValue    *value,
+                                 GParamSpec      *pspec)
 {
-  color_sample_draw_sample (colorsel, 1);
-  return FALSE;
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
+  
+  switch (prop_id)
+    {
+    case PROP_HAS_OPACITY_CONTROL:
+      gtk_color_selection_set_has_opacity_control (colorsel, 
+                                                  g_value_get_boolean (value));
+      break;
+    case PROP_HAS_PALETTE:
+      gtk_color_selection_set_has_palette (colorsel, 
+                                          g_value_get_boolean (value));
+      break;
+    case PROP_CURRENT_COLOR:
+      gtk_color_selection_set_current_color (colorsel, g_value_get_boxed (value));
+      break;
+    case PROP_CURRENT_ALPHA:
+      gtk_color_selection_set_current_alpha (colorsel, g_value_get_uint (value));
+      break;
+    case PROP_CURRENT_RGBA:
+      gtk_color_selection_set_current_rgba (colorsel, g_value_get_boxed (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+  
 }
 
 static void
-color_sample_setup_dnd (GtkColorSelection *colorsel, GtkWidget *sample)
+gtk_color_selection_get_property (GObject     *object,
+                                 guint        prop_id,
+                                 GValue      *value,
+                                 GParamSpec  *pspec)
 {
-  static const GtkTargetEntry targets[] = {
-    { "application/x-color", 0 }
-  };
-  ColorSelectionPrivate *priv;
-  priv = colorsel->private_data;
-  
-  gtk_drag_source_set (sample,
-                      GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
-                      targets, 1,
-                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
+  GdkColor color;
   
-  g_signal_connect (sample,
-                   "drag_begin",
-                   G_CALLBACK (color_sample_drag_begin),
-                   colorsel);
-  if (sample == priv->cur_sample)
+  switch (prop_id)
     {
-      
-      gtk_drag_dest_set (sample,
-                        GTK_DEST_DEFAULT_HIGHLIGHT |
-                        GTK_DEST_DEFAULT_MOTION |
-                        GTK_DEST_DEFAULT_DROP,
-                        targets, 1,
-                        GDK_ACTION_COPY);
-      
-      g_signal_connect (sample,
-                       "drag_end",
-                       G_CALLBACK (color_sample_drag_end),
-                       colorsel);
+    case PROP_HAS_OPACITY_CONTROL:
+      g_value_set_boolean (value, gtk_color_selection_get_has_opacity_control (colorsel));
+      break;
+    case PROP_HAS_PALETTE:
+      g_value_set_boolean (value, gtk_color_selection_get_has_palette (colorsel));
+      break;
+    case PROP_CURRENT_COLOR:
+      gtk_color_selection_get_current_color (colorsel, &color);
+      g_value_set_boxed (value, &color);
+      break;
+    case PROP_CURRENT_ALPHA:
+      g_value_set_uint (value, gtk_color_selection_get_current_alpha (colorsel));
+      break;
+    case PROP_CURRENT_RGBA:
+      {
+        GdkRGBA rgba;
+
+        gtk_color_selection_get_current_rgba (colorsel, &rgba);
+        g_value_set_boxed (value, &rgba);
+      }
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
     }
-  
-  g_signal_connect (sample,
-                   "drag_data_get",
-                   G_CALLBACK (color_sample_drag_handle),
-                   colorsel);
-  g_signal_connect (sample,
-                   "drag_data_received",
-                   G_CALLBACK (color_sample_drop_handle),
-                   colorsel);
-  
 }
 
+/* GtkWidget methods */
 
 static void
-color_sample_new (GtkColorSelection *colorsel)
+gtk_color_selection_destroy (GtkWidget *widget)
 {
-  ColorSelectionPrivate *priv;
-  
-  priv = colorsel->private_data;
-  
-  priv->sample_area = gtk_hbox_new (FALSE, 0);
-  priv->old_sample = gtk_drawing_area_new ();
-  priv->cur_sample = gtk_drawing_area_new ();
+  GtkColorSelection *cselection = GTK_COLOR_SELECTION (widget);
+  GtkColorSelectionPrivate *priv = cselection->private_data;
 
-  gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->old_sample,
-                     TRUE, TRUE, 0);
-  gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->cur_sample,
-                     TRUE, TRUE, 0);
-  
-  g_signal_connect (priv->old_sample, "expose_event",
-                   G_CALLBACK (color_old_sample_expose),
-                   colorsel);
-  g_signal_connect (priv->cur_sample, "expose_event",
-                   G_CALLBACK (color_cur_sample_expose),
-                   colorsel);
-  
-  color_sample_setup_dnd (colorsel, priv->old_sample);
-  color_sample_setup_dnd (colorsel, priv->cur_sample);
+  if (priv->dropper_grab_widget)
+    {
+      gtk_widget_destroy (priv->dropper_grab_widget);
+      priv->dropper_grab_widget = NULL;
+    }
 
-  gtk_widget_set_tooltip_text (priv->old_sample,
-                        _("The previously-selected color, for comparison to the color you're selecting now. You can drag this color to a palette entry, or select this color as current by dragging it to the other color swatch alongside."));
+  GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->destroy (widget);
+}
 
+static void
+gtk_color_selection_realize (GtkWidget *widget)
+{
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (widget);
+  GtkColorSelectionPrivate *priv = colorsel->private_data;
+  GtkSettings *settings = gtk_widget_get_settings (widget);
 
-  gtk_widget_set_tooltip_text (priv->cur_sample,
-                        _("The color you've chosen. You can drag this color to a palette entry to save it for use in the future."));
-  
-  gtk_widget_show_all (priv->sample_area);
+  priv->settings_connection =  g_signal_connect (settings,
+                                                "notify::gtk-color-palette",
+                                                G_CALLBACK (palette_change_notify_instance),
+                                                widget);
+  update_palette (colorsel);
+
+  GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->realize (widget);
+}
+
+static void
+gtk_color_selection_unrealize (GtkWidget *widget)
+{
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (widget);
+  GtkColorSelectionPrivate *priv = colorsel->private_data;
+  GtkSettings *settings = gtk_widget_get_settings (widget);
+
+  g_signal_handler_disconnect (settings, priv->settings_connection);
+
+  GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->unrealize (widget);
+}
+
+/* We override show-all since we have internal widgets that
+ * shouldn't be shown when you call show_all(), like the
+ * palette and opacity sliders.
+ */
+static void
+gtk_color_selection_show_all (GtkWidget *widget)
+{
+  gtk_widget_show (widget);
 }
 
+static gboolean 
+gtk_color_selection_grab_broken (GtkWidget          *widget,
+                                GdkEventGrabBroken *event)
+{
+  shutdown_eyedropper (widget);
+
+  return TRUE;
+}
 
 /*
  *
- * The palette area code
+ * The Sample Color
  *
  */
-#define CUSTOM_PALETTE_ENTRY_WIDTH   20
-#define CUSTOM_PALETTE_ENTRY_HEIGHT  20
+
+static void color_sample_draw_sample (GtkColorSelection *colorsel,
+                                      int                which,
+                                      cairo_t *          cr);
+static void color_sample_update_samples (GtkColorSelection *colorsel);
 
 static void
-palette_get_color (GtkWidget *drawing_area, gdouble *color)
+set_color_internal (GtkColorSelection *colorsel,
+                   gdouble           *color)
 {
-  gdouble *color_val;
-  
-  g_return_if_fail (color != NULL);
+  GtkColorSelectionPrivate *priv;
+  gint i;
   
-  color_val = g_object_get_data (G_OBJECT (drawing_area), "color_val");
-  if (color_val == NULL)
+  priv = colorsel->private_data;
+  priv->changing = TRUE;
+  priv->color[COLORSEL_RED] = color[0];
+  priv->color[COLORSEL_GREEN] = color[1];
+  priv->color[COLORSEL_BLUE] = color[2];
+  priv->color[COLORSEL_OPACITY] = color[3];
+  gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
+                 priv->color[COLORSEL_GREEN],
+                 priv->color[COLORSEL_BLUE],
+                 &priv->color[COLORSEL_HUE],
+                 &priv->color[COLORSEL_SATURATION],
+                 &priv->color[COLORSEL_VALUE]);
+  if (priv->default_set == FALSE)
     {
-      /* Default to white for no good reason */
-      color[0] = 1.0;
-      color[1] = 1.0;
-      color[2] = 1.0;
-      color[3] = 1.0;
-      return;
+      for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
+       priv->old_color[i] = priv->color[i];
     }
-  
-  color[0] = color_val[0];
-  color[1] = color_val[1];
-  color[2] = color_val[2];
-  color[3] = 1.0;
+  priv->default_set = TRUE;
+  priv->default_alpha_set = TRUE;
+  update_color (colorsel);
 }
 
-#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
 static void
-palette_paint (GtkWidget    *drawing_area,
-              GdkRectangle *area,
-              gpointer      data)
+set_color_icon (GdkDragContext *context,
+               gdouble        *colors)
 {
-  cairo_t *cr;
-  gint focus_width;
-    
-  if (drawing_area->window == NULL)
-    return;
+  GdkPixbuf *pixbuf;
+  guint32 pixel;
+
+  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
+                          8, 48, 32);
 
-  cr = gdk_cairo_create (drawing_area->window);
+  pixel = (((UNSCALE (colors[COLORSEL_RED])   & 0xff00) << 16) |
+          ((UNSCALE (colors[COLORSEL_GREEN]) & 0xff00) << 8) |
+          ((UNSCALE (colors[COLORSEL_BLUE])  & 0xff00)));
 
-  gdk_cairo_set_source_color (cr, &drawing_area->style->bg[GTK_STATE_NORMAL]);
-  gdk_cairo_rectangle (cr, area);
-  cairo_fill (cr);
+  gdk_pixbuf_fill (pixbuf, pixel);
   
-  if (GTK_WIDGET_HAS_FOCUS (drawing_area))
-    {
-      set_focus_line_attributes (drawing_area, cr, &focus_width);
+  gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
+  g_object_unref (pixbuf);
+}
 
-      cairo_rectangle (cr,
-                      focus_width / 2., focus_width / 2.,
-                      drawing_area->allocation.width - focus_width,
-                      drawing_area->allocation.height - focus_width);
-      cairo_stroke (cr);
-    }
+static void
+color_sample_drag_begin (GtkWidget      *widget,
+                        GdkDragContext *context,
+                        gpointer        data)
+{
+  GtkColorSelection *colorsel = data;
+  GtkColorSelectionPrivate *priv;
+  gdouble *colsrc;
+  
+  priv = colorsel->private_data;
+  
+  if (widget == priv->old_sample)
+    colsrc = priv->old_color;
+  else
+    colsrc = priv->color;
 
-  cairo_destroy (cr);
+  set_color_icon (context, colsrc);
 }
 
 static void
-set_focus_line_attributes (GtkWidget *drawing_area,
-                          cairo_t   *cr,
-                          gint      *focus_width)
+color_sample_drag_end (GtkWidget      *widget,
+                      GdkDragContext *context,
+                      gpointer        data)
+{
+  g_object_set_data (G_OBJECT (widget), I_("gtk-color-selection-drag-window"), NULL);
+}
+
+static void
+color_sample_drop_handle (GtkWidget        *widget,
+                         GdkDragContext   *context,
+                         gint              x,
+                         gint              y,
+                         GtkSelectionData *selection_data,
+                         guint             info,
+                         guint             time,
+                         gpointer          data)
 {
+  GtkColorSelection *colorsel = data;
+  GtkColorSelectionPrivate *priv;
+  gint length;
+  guint16 *vals;
   gdouble color[4];
-  gint8 *dash_list;
+  priv = colorsel->private_data;
   
-  gtk_widget_style_get (drawing_area,
-                       "focus-line-width", focus_width,
-                       "focus-line-pattern", (gchar *)&dash_list,
-                       NULL);
-      
-  palette_get_color (drawing_area, color);
-
-  if (INTENSITY (color[0], color[1], color[2]) > 0.5)
-    cairo_set_source_rgb (cr, 0., 0., 0.);
-  else
-    cairo_set_source_rgb (cr, 1., 1., 1.);
+  /* This is currently a guint16 array of the format:
+   * R
+   * G
+   * B
+   * opacity
+   */
 
-  cairo_set_line_width (cr, *focus_width);
+  length = gtk_selection_data_get_length (selection_data);
 
-  if (dash_list[0])
+  if (length < 0)
+    return;
+  
+  /* We accept drops with the wrong format, since the KDE color
+   * chooser incorrectly drops application/x-color with format 8.
+   */
+  if (length != 8)
     {
-      gint n_dashes = strlen (dash_list);
-      gdouble *dashes = g_new (gdouble, n_dashes);
-      gdouble total_length = 0;
-      gdouble dash_offset;
-      gint i;
+      g_warning ("Received invalid color data\n");
+      return;
+    }
 
-      for (i = 0; i < n_dashes; i++)
-       {
-         dashes[i] = dash_list[i];
-         total_length += dash_list[i];
-       }
+  vals = (guint16 *) gtk_selection_data_get_data (selection_data);
 
-      /* The dash offset here aligns the pattern to integer pixels
-       * by starting the dash at the right side of the left border
-       * Negative dash offsets in cairo don't work
-       * (https://bugs.freedesktop.org/show_bug.cgi?id=2729)
-       */
-      dash_offset = - *focus_width / 2.;
-      while (dash_offset < 0)
-       dash_offset += total_length;
+  if (widget == priv->cur_sample)
+    {
+      color[0] = (gdouble)vals[0] / 0xffff;
+      color[1] = (gdouble)vals[1] / 0xffff;
+      color[2] = (gdouble)vals[2] / 0xffff;
+      color[3] = (gdouble)vals[3] / 0xffff;
       
-      cairo_set_dash (cr, dashes, n_dashes, dash_offset);
-      g_free (dashes);
+      set_color_internal (colorsel, color);
     }
-
-  g_free (dash_list);
-}
-
-static void
-palette_drag_begin (GtkWidget      *widget,
-                   GdkDragContext *context,
-                   gpointer        data)
-{
-  gdouble colors[4];
-  
-  palette_get_color (widget, colors);
-  set_color_icon (context, colors);
 }
 
 static void
-palette_drag_handle (GtkWidget        *widget,
-                    GdkDragContext   *context,
-                    GtkSelectionData *selection_data,
-                    guint             info,
-                    guint             time,
-                    gpointer          data)
+color_sample_drag_handle (GtkWidget        *widget,
+                         GdkDragContext   *context,
+                         GtkSelectionData *selection_data,
+                         guint             info,
+                         guint             time,
+                         gpointer          data)
 {
+  GtkColorSelection *colorsel = data;
+  GtkColorSelectionPrivate *priv;
   guint16 vals[4];
-  gdouble colsrc[4];
+  gdouble *colsrc;
   
-  palette_get_color (widget, colsrc);
+  priv = colorsel->private_data;
+  
+  if (widget == priv->old_sample)
+    colsrc = priv->old_color;
+  else
+    colsrc = priv->color;
   
   vals[0] = colsrc[COLORSEL_RED] * 0xffff;
   vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
   vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
-  vals[3] = 0xffff;
+  vals[3] = priv->has_opacity ? colsrc[COLORSEL_OPACITY] * 0xffff : 0xffff;
   
   gtk_selection_data_set (selection_data,
                          gdk_atom_intern_static_string ("application/x-color"),
                          16, (guchar *)vals, 8);
 }
 
+/* which = 0 means draw old sample, which = 1 means draw new */
 static void
-palette_drag_end (GtkWidget      *widget,
-                 GdkDragContext *context,
-                 gpointer        data)
-{
-  g_object_set_data (G_OBJECT (widget), I_("gtk-color-selection-drag-window"), NULL);
-}
-
-static GdkColor *
-get_current_colors (GtkColorSelection *colorsel)
+color_sample_draw_sample (GtkColorSelection *colorsel,
+                          int                which,
+                          cairo_t           *cr)
 {
-  GtkSettings *settings;
-  GdkColor *colors = NULL;
-  gint n_colors = 0;
-  gchar *palette;
-
-  settings = gtk_widget_get_settings (GTK_WIDGET (colorsel));
-  g_object_get (settings,
-               "gtk-color-palette", &palette,
-               NULL);
+  GtkWidget *da;
+  gint x, y, goff;
+  GtkColorSelectionPrivate *priv;
+  int width, height;
   
-  if (!gtk_color_selection_palette_from_string (palette, &colors, &n_colors))
+  g_return_if_fail (colorsel != NULL);
+  priv = colorsel->private_data;
+  
+  g_return_if_fail (priv->sample_area != NULL);
+  if (!gtk_widget_is_drawable (priv->sample_area))
+    return;
+
+  if (which == 0)
     {
-      gtk_color_selection_palette_from_string (default_colors, &colors, &n_colors);
+      da = priv->old_sample;
+      goff = 0;
     }
   else
     {
-      /* If there are less colors provided than the number of slots in the
-       * color selection, we fill in the rest from the defaults.
-       */
-      if (n_colors < (GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT))
-       {
-         GdkColor *tmp_colors = colors;
-         gint tmp_n_colors = n_colors;
-         
-         gtk_color_selection_palette_from_string (default_colors, &colors, &n_colors);
-         memcpy (colors, tmp_colors, sizeof (GdkColor) * tmp_n_colors);
+      GtkAllocation old_sample_allocation;
 
-         g_free (tmp_colors);
-       }
+      da = priv->cur_sample;
+      gtk_widget_get_allocation (priv->old_sample, &old_sample_allocation);
+      goff =  old_sample_allocation.width % 32;
     }
 
-  g_assert (n_colors >= GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
-  g_free (palette);
-  
-  return colors;
-}
-
-/* Changes the model color */
-static void
-palette_change_color (GtkWidget         *drawing_area,
-                      GtkColorSelection *colorsel,
-                      gdouble           *color)
-{
-  gint x, y;
-  ColorSelectionPrivate *priv;
-  GdkColor gdk_color;
-  GdkColor *current_colors;
-  GdkScreen *screen;
-
-  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
-  g_return_if_fail (GTK_IS_DRAWING_AREA (drawing_area));
-  
-  priv = colorsel->private_data;
+  /* Below needs tweaking for non-power-of-two */  
+  width = gtk_widget_get_allocated_width (da);
+  height = gtk_widget_get_allocated_height (da);
   
-  gdk_color.red = UNSCALE (color[0]);
-  gdk_color.green = UNSCALE (color[1]);
-  gdk_color.blue = UNSCALE (color[2]);
-  gdk_color.pixel = 0;
-
-  x = 0;
-  y = 0;                       /* Quiet GCC */
-  while (x < GTK_CUSTOM_PALETTE_WIDTH)
+  if (priv->has_opacity)
     {
-      y = 0;
-      while (y < GTK_CUSTOM_PALETTE_HEIGHT)
-        {
-          if (priv->custom_palette[x][y] == drawing_area)
-            goto out;
-          
-          ++y;
-        }
-
-      ++x;
-    }
+      /* Draw checks in background */
 
- out:
-  
-  g_assert (x < GTK_CUSTOM_PALETTE_WIDTH || y < GTK_CUSTOM_PALETTE_HEIGHT);
+      cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
+      cairo_rectangle (cr, 0, 0, width, height);
+      cairo_fill (cr);
 
-  current_colors = get_current_colors (colorsel);
-  current_colors[y * GTK_CUSTOM_PALETTE_WIDTH + x] = gdk_color;
+      cairo_set_source_rgb (cr, 0.75, 0.75, 0.75);
+      for (x = goff & -CHECK_SIZE; x < goff + width; x += CHECK_SIZE)
+       for (y = 0; y < height; y += CHECK_SIZE)
+         if ((x / CHECK_SIZE + y / CHECK_SIZE) % 2 == 0)
+           cairo_rectangle (cr, x - goff, y, CHECK_SIZE, CHECK_SIZE);
+      cairo_fill (cr);
+    }
 
-  screen = gtk_widget_get_screen (GTK_WIDGET (colorsel));
-  if (change_palette_hook != default_change_palette_func)
-    (* change_palette_hook) (screen, current_colors, 
-                            GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
-  else if (noscreen_change_palette_hook != default_noscreen_change_palette_func)
+  if (which == 0)
     {
-      if (screen != gdk_screen_get_default ())
-       g_warning ("gtk_color_selection_set_change_palette_hook used by widget is not on the default screen.");
-      (* noscreen_change_palette_hook) (current_colors, 
-                                       GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
+      cairo_set_source_rgba (cr,
+                            priv->old_color[COLORSEL_RED], 
+                            priv->old_color[COLORSEL_GREEN], 
+                            priv->old_color[COLORSEL_BLUE],
+                            priv->has_opacity ?
+                               priv->old_color[COLORSEL_OPACITY] : 1.0);
     }
   else
-    (* change_palette_hook) (screen, current_colors, 
-                            GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
+    {
+      cairo_set_source_rgba (cr,
+                            priv->color[COLORSEL_RED], 
+                            priv->color[COLORSEL_GREEN], 
+                            priv->color[COLORSEL_BLUE],
+                            priv->has_opacity ?
+                              priv->color[COLORSEL_OPACITY] : 1.0);
+    }
 
-  g_free (current_colors);
+  cairo_rectangle (cr, 0, 0, width, height);
+  cairo_fill (cr);
 }
 
-/* Changes the view color */
+
 static void
-palette_set_color (GtkWidget         *drawing_area,
-                  GtkColorSelection *colorsel,
-                  gdouble           *color)
+color_sample_update_samples (GtkColorSelection *colorsel)
 {
-  gdouble *new_color = g_new (double, 4);
-  GdkColor gdk_color;
-  
-  gdk_color.red = UNSCALE (color[0]);
-  gdk_color.green = UNSCALE (color[1]);
-  gdk_color.blue = UNSCALE (color[2]);
-
-  gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &gdk_color);
-  
-  if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) == 0)
-    {
-      static const GtkTargetEntry targets[] = {
-       { "application/x-color", 0 }
-      };
-      gtk_drag_source_set (drawing_area,
-                          GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
-                          targets, 1,
-                          GDK_ACTION_COPY | GDK_ACTION_MOVE);
-      
-      g_signal_connect (drawing_area,
-                       "drag_begin",
-                       G_CALLBACK (palette_drag_begin),
-                       colorsel);
-      g_signal_connect (drawing_area,
-                       "drag_data_get",
-                       G_CALLBACK (palette_drag_handle),
-                       colorsel);
-      
-      g_object_set_data (G_OBJECT (drawing_area), I_("color_set"),
-                        GINT_TO_POINTER (1));
-    }
+  GtkColorSelectionPrivate *priv = colorsel->private_data;
+  gtk_widget_queue_draw (priv->old_sample);
+  gtk_widget_queue_draw (priv->cur_sample);
+}
 
-  new_color[0] = color[0];
-  new_color[1] = color[1];
-  new_color[2] = color[2];
-  new_color[3] = 1.0;
-  
-  g_object_set_data_full (G_OBJECT (drawing_area), I_("color_val"), new_color, (GDestroyNotify)g_free);
+static gboolean
+color_old_sample_draw (GtkWidget         *da,
+                       cairo_t           *cr,
+                       GtkColorSelection *colorsel)
+{
+  color_sample_draw_sample (colorsel, 0, cr);
+  return FALSE;
 }
 
+
 static gboolean
-palette_expose (GtkWidget      *drawing_area,
-               GdkEventExpose *event,
-               gpointer        data)
+color_cur_sample_draw (GtkWidget         *da,
+                       cairo_t           *cr,
+                       GtkColorSelection *colorsel)
 {
-  if (drawing_area->window == NULL)
-    return FALSE;
-  
-  palette_paint (drawing_area, &(event->area), data);
-  
+  color_sample_draw_sample (colorsel, 1, cr);
   return FALSE;
 }
 
 static void
-popup_position_func (GtkMenu   *menu,
-                     gint      *x,
-                     gint      *y,
-                     gboolean  *push_in,
-                     gpointer  user_data)
+color_sample_setup_dnd (GtkColorSelection *colorsel, GtkWidget *sample)
 {
-  GtkWidget *widget;
-  GtkRequisition req;      
-  gint root_x, root_y;
-  GdkScreen *screen;
+  static const GtkTargetEntry targets[] = {
+    { "application/x-color", 0 }
+  };
+  GtkColorSelectionPrivate *priv;
+  priv = colorsel->private_data;
   
-  widget = GTK_WIDGET (user_data);
+  gtk_drag_source_set (sample,
+                      GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
+                      targets, 1,
+                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
   
-  g_return_if_fail (GTK_WIDGET_REALIZED (widget));
-
-  gdk_window_get_origin (widget->window, &root_x, &root_y);
+  g_signal_connect (sample, "drag-begin",
+                   G_CALLBACK (color_sample_drag_begin),
+                   colorsel);
+  if (sample == priv->cur_sample)
+    {
+      
+      gtk_drag_dest_set (sample,
+                        GTK_DEST_DEFAULT_HIGHLIGHT |
+                        GTK_DEST_DEFAULT_MOTION |
+                        GTK_DEST_DEFAULT_DROP,
+                        targets, 1,
+                        GDK_ACTION_COPY);
+      
+      g_signal_connect (sample, "drag-end",
+                       G_CALLBACK (color_sample_drag_end),
+                       colorsel);
+    }
+  
+  g_signal_connect (sample, "drag-data-get",
+                   G_CALLBACK (color_sample_drag_handle),
+                   colorsel);
+  g_signal_connect (sample, "drag-data-received",
+                   G_CALLBACK (color_sample_drop_handle),
+                   colorsel);
   
-  gtk_widget_size_request (GTK_WIDGET (menu), &req);
-
-  /* Put corner of menu centered on color cell */
-  *x = root_x + widget->allocation.width / 2;
-  *y = root_y + widget->allocation.height / 2;
-
-  /* Ensure sanity */
-  screen = gtk_widget_get_screen (widget);
-  *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
-  *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
 }
 
 static void
-save_color_selected (GtkWidget *menuitem,
-                     gpointer   data)
+update_tooltips (GtkColorSelection *colorsel)
 {
-  GtkColorSelection *colorsel;
-  GtkWidget *drawing_area;
-  ColorSelectionPrivate *priv;
-
-  drawing_area = GTK_WIDGET (data);
-  
-  colorsel = GTK_COLOR_SELECTION (g_object_get_data (G_OBJECT (drawing_area),
-                                                     "gtk-color-sel"));
+  GtkColorSelectionPrivate *priv;
 
   priv = colorsel->private_data;
-  
-  palette_change_color (drawing_area, colorsel, priv->color);  
+
+  if (priv->has_palette == TRUE)
+    {
+      gtk_widget_set_tooltip_text (priv->old_sample,
+                            _("The previously-selected color, for comparison to the color you're selecting now. You can drag this color to a palette entry, or select this color as current by dragging it to the other color swatch alongside."));
+
+      gtk_widget_set_tooltip_text (priv->cur_sample,
+                            _("The color you've chosen. You can drag this color to a palette entry to save it for use in the future."));
+    }
+  else
+    {
+      gtk_widget_set_tooltip_text (priv->old_sample,
+                            _("The previously-selected color, for comparison to the color you're selecting now."));
+
+      gtk_widget_set_tooltip_text (priv->cur_sample,
+                            _("The color you've chosen."));
+    }
 }
 
 static void
-do_popup (GtkColorSelection *colorsel,
-          GtkWidget         *drawing_area,
-          guint32            timestamp)
+color_sample_new (GtkColorSelection *colorsel)
 {
-  GtkWidget *menu;
-  GtkWidget *mi;
-  
-  g_object_set_data (G_OBJECT (drawing_area),
-                     I_("gtk-color-sel"),
-                     colorsel);
+  GtkColorSelectionPrivate *priv;
   
-  menu = gtk_menu_new ();
-
-  mi = gtk_menu_item_new_with_mnemonic (_("_Save color here"));
-
-  g_signal_connect (mi, "activate",
-                    G_CALLBACK (save_color_selected),
-                    drawing_area);
+  priv = colorsel->private_data;
   
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+  priv->sample_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  priv->old_sample = gtk_drawing_area_new ();
+  priv->cur_sample = gtk_drawing_area_new ();
 
-  gtk_widget_show_all (mi);
+  gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->old_sample,
+                     TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->cur_sample,
+                     TRUE, TRUE, 0);
+  
+  g_signal_connect (priv->old_sample, "draw",
+                   G_CALLBACK (color_old_sample_draw),
+                   colorsel);
+  g_signal_connect (priv->cur_sample, "draw",
+                   G_CALLBACK (color_cur_sample_draw),
+                   colorsel);
+  
+  color_sample_setup_dnd (colorsel, priv->old_sample);
+  color_sample_setup_dnd (colorsel, priv->cur_sample);
 
-  gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
-                  popup_position_func, drawing_area,
-                  3, timestamp);
-}
+  update_tooltips (colorsel);
 
+  gtk_widget_show_all (priv->sample_area);
+}
 
-static gboolean
-palette_enter (GtkWidget        *drawing_area,
-              GdkEventCrossing *event,
-              gpointer        data)
-{
-  g_object_set_data (G_OBJECT (drawing_area),
-                    I_("gtk-colorsel-have-pointer"),
-                    GUINT_TO_POINTER (TRUE));
 
-  return FALSE;
-}
+/*
+ *
+ * The palette area code
+ *
+ */
 
-static gboolean
-palette_leave (GtkWidget        *drawing_area,
-              GdkEventCrossing *event,
-              gpointer        data)
+static void
+palette_get_color (GtkWidget *drawing_area, gdouble *color)
 {
-  g_object_set_data (G_OBJECT (drawing_area),
-                    I_("gtk-colorsel-have-pointer"),
-                    NULL);
-
-  return FALSE;
+  gdouble *color_val;
+  
+  g_return_if_fail (color != NULL);
+  
+  color_val = g_object_get_data (G_OBJECT (drawing_area), "color_val");
+  if (color_val == NULL)
+    {
+      /* Default to white for no good reason */
+      color[0] = 1.0;
+      color[1] = 1.0;
+      color[2] = 1.0;
+      color[3] = 1.0;
+      return;
+    }
+  
+  color[0] = color_val[0];
+  color[1] = color_val[1];
+  color[2] = color_val[2];
+  color[3] = 1.0;
 }
 
 static gboolean
-palette_press (GtkWidget      *drawing_area,
-              GdkEventButton *event,
-              gpointer        data)
+palette_draw (GtkWidget *drawing_area,
+               cairo_t   *cr,
+              gpointer   data)
 {
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
+  gint focus_width;
 
-  gtk_widget_grab_focus (drawing_area);
+  gdk_cairo_set_source_color (cr, &gtk_widget_get_style (drawing_area)->bg[GTK_STATE_NORMAL]);
+  cairo_paint (cr);
   
-  if (event->button == 3 &&
-      event->type == GDK_BUTTON_PRESS)
+  if (gtk_widget_has_focus (drawing_area))
     {
-      do_popup (colorsel, drawing_area, event->time);
-      return TRUE;
+      set_focus_line_attributes (drawing_area, cr, &focus_width);
+
+      cairo_rectangle (cr,
+                       focus_width / 2., focus_width / 2.,
+                       gtk_widget_get_allocated_width (drawing_area) - focus_width,
+                       gtk_widget_get_allocated_height (drawing_area) - focus_width);
+      cairo_stroke (cr);
     }
 
   return FALSE;
 }
 
-static gboolean
-palette_release (GtkWidget      *drawing_area,
-                GdkEventButton *event,
-                gpointer        data)
+static void
+set_focus_line_attributes (GtkWidget *drawing_area,
+                          cairo_t   *cr,
+                          gint      *focus_width)
 {
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
+  gdouble color[4];
+  gint8 *dash_list;
+  
+  gtk_widget_style_get (drawing_area,
+                       "focus-line-width", focus_width,
+                       "focus-line-pattern", (gchar *)&dash_list,
+                       NULL);
+      
+  palette_get_color (drawing_area, color);
 
-  gtk_widget_grab_focus (drawing_area);
+  if (INTENSITY (color[0], color[1], color[2]) > 0.5)
+    cairo_set_source_rgb (cr, 0., 0., 0.);
+  else
+    cairo_set_source_rgb (cr, 1., 1., 1.);
 
-  if (event->button == 1 &&
-      g_object_get_data (G_OBJECT (drawing_area),
-                        "gtk-colorsel-have-pointer") != NULL)
+  cairo_set_line_width (cr, *focus_width);
+
+  if (dash_list[0])
     {
-      if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) != 0)
-        {
-          gdouble color[4];
-          palette_get_color (drawing_area, color);
-          set_color_internal (colorsel, color);
-        }
+      gint n_dashes = strlen ((gchar *)dash_list);
+      gdouble *dashes = g_new (gdouble, n_dashes);
+      gdouble total_length = 0;
+      gdouble dash_offset;
+      gint i;
+
+      for (i = 0; i < n_dashes; i++)
+       {
+         dashes[i] = dash_list[i];
+         total_length += dash_list[i];
+       }
+
+      /* The dash offset here aligns the pattern to integer pixels
+       * by starting the dash at the right side of the left border
+       * Negative dash offsets in cairo don't work
+       * (https://bugs.freedesktop.org/show_bug.cgi?id=2729)
+       */
+      dash_offset = - *focus_width / 2.;
+      while (dash_offset < 0)
+       dash_offset += total_length;
+      
+      cairo_set_dash (cr, dashes, n_dashes, dash_offset);
+      g_free (dashes);
     }
 
-  return FALSE;
+  g_free (dash_list);
 }
 
 static void
-palette_drop_handle (GtkWidget        *widget,
+palette_drag_begin (GtkWidget      *widget,
+                   GdkDragContext *context,
+                   gpointer        data)
+{
+  gdouble colors[4];
+  
+  palette_get_color (widget, colors);
+  set_color_icon (context, colors);
+}
+
+static void
+palette_drag_handle (GtkWidget        *widget,
                     GdkDragContext   *context,
-                    gint              x,
-                    gint              y,
                     GtkSelectionData *selection_data,
                     guint             info,
                     guint             time,
                     gpointer          data)
 {
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
-  guint16 *vals;
-  gdouble color[4];
-  
-  if (selection_data->length < 0)
-    return;
+  guint16 vals[4];
+  gdouble colsrc[4];
   
-  /* We accept drops with the wrong format, since the KDE color
-   * chooser incorrectly drops application/x-color with format 8.
-   */
-  if (selection_data->length != 8)
-    {
-      g_warning ("Received invalid color data\n");
-      return;
-    }
+  palette_get_color (widget, colsrc);
   
-  vals = (guint16 *)selection_data->data;
+  vals[0] = colsrc[COLORSEL_RED] * 0xffff;
+  vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
+  vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
+  vals[3] = 0xffff;
   
-  color[0] = (gdouble)vals[0] / 0xffff;
-  color[1] = (gdouble)vals[1] / 0xffff;
-  color[2] = (gdouble)vals[2] / 0xffff;
-  color[3] = (gdouble)vals[3] / 0xffff;
-  palette_change_color (widget, colorsel, color);
-  set_color_internal (colorsel, color);
+  gtk_selection_data_set (selection_data,
+                         gdk_atom_intern_static_string ("application/x-color"),
+                         16, (guchar *)vals, 8);
 }
 
-static gint
-palette_activate (GtkWidget   *widget,
-                 GdkEventKey *event,
-                 gpointer     data)
+static void
+palette_drag_end (GtkWidget      *widget,
+                 GdkDragContext *context,
+                 gpointer        data)
 {
-  /* should have a drawing area subclass with an activate signal */
-  if ((event->keyval == GDK_space) ||
-      (event->keyval == GDK_Return) ||
-      (event->keyval == GDK_KP_Enter) ||
-      (event->keyval == GDK_KP_Space))
-    {
-      if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "color_set")) != 0)
-        {
-          gdouble color[4];
-          palette_get_color (widget, color);
-          set_color_internal (GTK_COLOR_SELECTION (data), color);
-        }
-      return TRUE;
-    }
-  
-  return FALSE;
+  g_object_set_data (G_OBJECT (widget), I_("gtk-color-selection-drag-window"), NULL);
 }
 
-static gboolean
-palette_popup (GtkWidget *widget,
-               gpointer   data)
+static GdkColor *
+get_current_colors (GtkColorSelection *colorsel)
 {
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
+  GtkSettings *settings;
+  GdkColor *colors = NULL;
+  gint n_colors = 0;
+  gchar *palette;
 
-  do_popup (colorsel, widget, GDK_CURRENT_TIME);
-  return TRUE;
+  settings = gtk_widget_get_settings (GTK_WIDGET (colorsel));
+  g_object_get (settings, "gtk-color-palette", &palette, NULL);
+  
+  if (!gtk_color_selection_palette_from_string (palette, &colors, &n_colors))
+    {
+      gtk_color_selection_palette_from_string (DEFAULT_COLOR_PALETTE,
+                                               &colors,
+                                               &n_colors);
+    }
+  else
+    {
+      /* If there are less colors provided than the number of slots in the
+       * color selection, we fill in the rest from the defaults.
+       */
+      if (n_colors < (GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT))
+       {
+         GdkColor *tmp_colors = colors;
+         gint tmp_n_colors = n_colors;
+         
+         gtk_color_selection_palette_from_string (DEFAULT_COLOR_PALETTE,
+                                                   &colors,
+                                                   &n_colors);
+         memcpy (colors, tmp_colors, sizeof (GdkColor) * tmp_n_colors);
+
+         g_free (tmp_colors);
+       }
+    }
+
+  /* make sure that we fill every slot */
+  g_assert (n_colors == GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
+  g_free (palette);
+  
+  return colors;
 }
-               
 
-static GtkWidget*
-palette_new (GtkColorSelection *colorsel)
+/* Changes the model color */
+static void
+palette_change_color (GtkWidget         *drawing_area,
+                      GtkColorSelection *colorsel,
+                      gdouble           *color)
 {
-  GtkWidget *retval;
-  ColorSelectionPrivate *priv;
-  
-  static const GtkTargetEntry targets[] = {
-    { "application/x-color", 0 }
-  };
+  gint x, y;
+  GtkColorSelectionPrivate *priv;
+  GdkColor gdk_color;
+  GdkColor *current_colors;
+  GdkScreen *screen;
 
+  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
+  g_return_if_fail (GTK_IS_DRAWING_AREA (drawing_area));
+  
   priv = colorsel->private_data;
   
-  retval = gtk_drawing_area_new ();
+  gdk_color.red = UNSCALE (color[0]);
+  gdk_color.green = UNSCALE (color[1]);
+  gdk_color.blue = UNSCALE (color[2]);
+  gdk_color.pixel = 0;
 
-  GTK_WIDGET_SET_FLAGS (retval, GTK_CAN_FOCUS);
-  
-  g_object_set_data (G_OBJECT (retval), I_("color_set"), GINT_TO_POINTER (0)); 
-  gtk_widget_set_events (retval, GDK_BUTTON_PRESS_MASK
-                         | GDK_BUTTON_RELEASE_MASK
-                         | GDK_EXPOSURE_MASK
-                         | GDK_ENTER_NOTIFY_MASK
-                         | GDK_LEAVE_NOTIFY_MASK);
-  
-  g_signal_connect (retval, "expose_event",
-                   G_CALLBACK (palette_expose), colorsel);
-  g_signal_connect (retval, "button_press_event",
-                   G_CALLBACK (palette_press), colorsel);
-  g_signal_connect (retval, "button_release_event",
-                   G_CALLBACK (palette_release), colorsel);
-  g_signal_connect (retval, "enter_notify_event",
-                   G_CALLBACK (palette_enter), colorsel);
-  g_signal_connect (retval, "leave_notify_event",
-                   G_CALLBACK (palette_leave), colorsel);
-  g_signal_connect (retval, "key_press_event",
-                   G_CALLBACK (palette_activate), colorsel);
-  g_signal_connect (retval, "popup_menu",
-                   G_CALLBACK (palette_popup), colorsel);
-  
-  gtk_drag_dest_set (retval,
-                    GTK_DEST_DEFAULT_HIGHLIGHT |
-                    GTK_DEST_DEFAULT_MOTION |
-                    GTK_DEST_DEFAULT_DROP,
-                    targets, 1,
-                    GDK_ACTION_COPY);
+  x = 0;
+  y = 0;                       /* Quiet GCC */
+  while (x < GTK_CUSTOM_PALETTE_WIDTH)
+    {
+      y = 0;
+      while (y < GTK_CUSTOM_PALETTE_HEIGHT)
+        {
+          if (priv->custom_palette[x][y] == drawing_area)
+            goto out;
+          
+          ++y;
+        }
+
+      ++x;
+    }
+
+ out:
   
-  g_signal_connect (retval, "drag_end",
-                    G_CALLBACK (palette_drag_end), NULL);
-  g_signal_connect (retval, "drag_data_received",
-                    G_CALLBACK (palette_drop_handle), colorsel);
+  g_assert (x < GTK_CUSTOM_PALETTE_WIDTH || y < GTK_CUSTOM_PALETTE_HEIGHT);
 
-  gtk_widget_set_tooltip_text (retval,
-                        _("Click this palette entry to make it the current color. To change this entry, drag a color swatch here or right-click it and select \"Save color here.\""));
-  return retval;
-}
+  current_colors = get_current_colors (colorsel);
+  current_colors[y * GTK_CUSTOM_PALETTE_WIDTH + x] = gdk_color;
 
+  screen = gtk_widget_get_screen (GTK_WIDGET (colorsel));
+  if (change_palette_hook != default_change_palette_func)
+    (* change_palette_hook) (screen, current_colors, 
+                            GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
+  else if (noscreen_change_palette_hook != default_noscreen_change_palette_func)
+    {
+      if (screen != gdk_screen_get_default ())
+       g_warning ("gtk_color_selection_set_change_palette_hook used by widget is not on the default screen.");
+      (* noscreen_change_palette_hook) (current_colors, 
+                                       GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
+    }
+  else
+    (* change_palette_hook) (screen, current_colors, 
+                            GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
 
-/*
- *
- * The actual GtkColorSelection widget
- *
- */
+  g_free (current_colors);
+}
 
-static GdkCursor *
-make_picker_cursor (GdkScreen *screen)
+/* Changes the view color */
+static void
+palette_set_color (GtkWidget         *drawing_area,
+                  GtkColorSelection *colorsel,
+                  gdouble           *color)
 {
-  GdkCursor *cursor;
-
-  cursor = gdk_cursor_new_from_name (gdk_screen_get_display (screen),
-                                    "color-picker");
+  gdouble *new_color = g_new (double, 4);
+  GdkColor gdk_color;
+  
+  gdk_color.red = UNSCALE (color[0]);
+  gdk_color.green = UNSCALE (color[1]);
+  gdk_color.blue = UNSCALE (color[2]);
 
-  if (!cursor)
+  gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &gdk_color);
+  
+  if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) == 0)
     {
-      GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
-      GdkColor fg = { 0, 0x0000, 0x0000, 0x0000 };
-      GdkWindow *window;
-      GdkPixmap *pixmap, *mask;
-
-      window = gdk_screen_get_root_window (screen);
-      
-      pixmap =
-       gdk_bitmap_create_from_data (window, (gchar *) dropper_bits,
-                                    DROPPER_WIDTH, DROPPER_HEIGHT);
-      
-      mask =
-       gdk_bitmap_create_from_data (window, (gchar *) dropper_mask,
-                                    DROPPER_WIDTH, DROPPER_HEIGHT);
+      static const GtkTargetEntry targets[] = {
+       { "application/x-color", 0 }
+      };
+      gtk_drag_source_set (drawing_area,
+                          GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
+                          targets, 1,
+                          GDK_ACTION_COPY | GDK_ACTION_MOVE);
       
-      cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg,
-                                          DROPPER_X_HOT, DROPPER_Y_HOT);
+      g_signal_connect (drawing_area, "drag-begin",
+                       G_CALLBACK (palette_drag_begin),
+                       colorsel);
+      g_signal_connect (drawing_area, "drag-data-get",
+                       G_CALLBACK (palette_drag_handle),
+                       colorsel);
       
-      g_object_unref (pixmap);
-      g_object_unref (mask);
+      g_object_set_data (G_OBJECT (drawing_area), I_("color_set"),
+                        GINT_TO_POINTER (1));
     }
-      
-  return cursor;
+
+  new_color[0] = color[0];
+  new_color[1] = color[1];
+  new_color[2] = color[2];
+  new_color[3] = 1.0;
+  
+  g_object_set_data_full (G_OBJECT (drawing_area), I_("color_val"), new_color, (GDestroyNotify)g_free);
 }
 
 static void
-grab_color_at_mouse (GdkScreen *screen,
-                    gint       x_root,
-                    gint       y_root,
-                    gpointer   data)
+popup_position_func (GtkMenu   *menu,
+                     gint      *x,
+                     gint      *y,
+                     gboolean  *push_in,
+                     gpointer  user_data)
 {
-  GdkImage *image;
-  guint32 pixel;
-  GtkColorSelection *colorsel = data;
-  ColorSelectionPrivate *priv;
-  GdkColor color;
-  GdkColormap *colormap = gdk_screen_get_system_colormap (screen);
-  GdkWindow *root_window = gdk_screen_get_root_window (screen);
+  GtkAllocation allocation;
+  GtkWidget *widget;
+  GtkRequisition req;      
+  gint root_x, root_y;
+  GdkScreen *screen;
   
-  priv = colorsel->private_data;
+  widget = GTK_WIDGET (user_data);
   
-  image = gdk_drawable_get_image (root_window, x_root, y_root, 1, 1);
-  if (!image)
-    {
-      gint x, y;
-      GdkDisplay *display = gdk_screen_get_display (screen);
-      GdkWindow *window = gdk_display_get_window_at_pointer (display, &x, &y);
-      if (!window)
-       return;
-      image = gdk_drawable_get_image (window, x, y, 1, 1);
-      if (!image)
-       return;
-    }
-  pixel = gdk_image_get_pixel (image, 0, 0);
-  g_object_unref (image);
+  g_return_if_fail (gtk_widget_get_realized (widget));
 
-  gdk_colormap_query_color (colormap, pixel, &color);
-  
-  priv->color[COLORSEL_RED] = SCALE (color.red);
-  priv->color[COLORSEL_GREEN] = SCALE (color.green);
-  priv->color[COLORSEL_BLUE] = SCALE (color.blue);
-  
-  gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
-                 priv->color[COLORSEL_GREEN],
-                 priv->color[COLORSEL_BLUE],
-                 &priv->color[COLORSEL_HUE],
-                 &priv->color[COLORSEL_SATURATION],
-                 &priv->color[COLORSEL_VALUE]);
+  gdk_window_get_origin (gtk_widget_get_window (widget),
+                         &root_x, &root_y);
 
-  update_color (colorsel);
+  gtk_widget_get_preferred_size (GTK_WIDGET (menu),
+                                 &req, NULL);
+  gtk_widget_get_allocation (widget, &allocation);
+
+  /* Put corner of menu centered on color cell */
+  *x = root_x + allocation.width / 2;
+  *y = root_y + allocation.height / 2;
+
+  /* Ensure sanity */
+  screen = gtk_widget_get_screen (widget);
+  *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
+  *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
 }
 
 static void
-shutdown_eyedropper (GtkWidget *widget)
+save_color_selected (GtkWidget *menuitem,
+                     gpointer   data)
 {
   GtkColorSelection *colorsel;
-  ColorSelectionPrivate *priv;
-  GdkDisplay *display = gtk_widget_get_display (widget);
-
-  colorsel = GTK_COLOR_SELECTION (widget);
-  priv = colorsel->private_data;    
+  GtkWidget *drawing_area;
+  GtkColorSelectionPrivate *priv;
 
-  if (priv->has_grab)
-    {
-      gdk_display_keyboard_ungrab (display, priv->grab_time);
-      gdk_display_pointer_ungrab (display, priv->grab_time);
-      gtk_grab_remove (priv->dropper_grab_widget);
+  drawing_area = GTK_WIDGET (data);
+  
+  colorsel = GTK_COLOR_SELECTION (g_object_get_data (G_OBJECT (drawing_area),
+                                                     "gtk-color-sel"));
 
-      priv->has_grab = FALSE;
-    }
+  priv = colorsel->private_data;
+  
+  palette_change_color (drawing_area, colorsel, priv->color);  
 }
 
-static gboolean 
-gtk_color_selection_grab_broken (GtkWidget          *widget,
-                                GdkEventGrabBroken *event)
+static void
+do_popup (GtkColorSelection *colorsel,
+          GtkWidget         *drawing_area,
+          guint32            timestamp)
 {
-  shutdown_eyedropper (widget);
+  GtkWidget *menu;
+  GtkWidget *mi;
+  
+  g_object_set_data (G_OBJECT (drawing_area),
+                     I_("gtk-color-sel"),
+                     colorsel);
+  
+  menu = gtk_menu_new ();
 
-  return TRUE;
+  mi = gtk_menu_item_new_with_mnemonic (_("_Save color here"));
+
+  g_signal_connect (mi, "activate",
+                    G_CALLBACK (save_color_selected),
+                    drawing_area);
+  
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+
+  gtk_widget_show_all (mi);
+
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+                  popup_position_func, drawing_area,
+                  3, timestamp);
 }
 
-static void
-mouse_motion (GtkWidget      *invisible,
-             GdkEventMotion *event,
-             gpointer        data)
+
+static gboolean
+palette_enter (GtkWidget        *drawing_area,
+              GdkEventCrossing *event,
+              gpointer        data)
 {
-  grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
-                      event->x_root, event->y_root, data); 
+  g_object_set_data (G_OBJECT (drawing_area),
+                    I_("gtk-colorsel-have-pointer"),
+                    GUINT_TO_POINTER (TRUE));
+
+  return FALSE;
 }
 
 static gboolean
-mouse_release (GtkWidget      *invisible,
-              GdkEventButton *event,
+palette_leave (GtkWidget        *drawing_area,
+              GdkEventCrossing *event,
               gpointer        data)
 {
-  /* GtkColorSelection *colorsel = data; */
+  g_object_set_data (G_OBJECT (drawing_area),
+                    I_("gtk-colorsel-have-pointer"),
+                    NULL);
 
-  if (event->button != 1)
-    return FALSE;
+  return FALSE;
+}
 
-  grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
-                      event->x_root, event->y_root, data);
+static gboolean
+palette_press (GtkWidget      *drawing_area,
+              GdkEventButton *event,
+              gpointer        data)
+{
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
 
-  shutdown_eyedropper (GTK_WIDGET (data));
+  gtk_widget_grab_focus (drawing_area);
   
-  g_signal_handlers_disconnect_by_func (invisible,
-                                       mouse_motion,
-                                       data);
-  g_signal_handlers_disconnect_by_func (invisible,
-                                       mouse_release,
-                                       data);
+  if (event->button == 3 &&
+      event->type == GDK_BUTTON_PRESS)
+    {
+      do_popup (colorsel, drawing_area, event->time);
+      return TRUE;
+    }
 
-  return TRUE;
+  return FALSE;
 }
 
-/* Helper Functions */
+static gboolean
+palette_release (GtkWidget      *drawing_area,
+                GdkEventButton *event,
+                gpointer        data)
+{
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
 
-static gboolean mouse_press (GtkWidget      *invisible,
-                             GdkEventButton *event,
-                             gpointer        data);
+  gtk_widget_grab_focus (drawing_area);
 
-#define BIG_STEP 20
+  if (event->button == 1 &&
+      g_object_get_data (G_OBJECT (drawing_area),
+                        "gtk-colorsel-have-pointer") != NULL)
+    {
+      if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) != 0)
+        {
+          gdouble color[4];
+          palette_get_color (drawing_area, color);
+          set_color_internal (colorsel, color);
+        }
+    }
+
+  return FALSE;
+}
+
+static void
+palette_drop_handle (GtkWidget        *widget,
+                    GdkDragContext   *context,
+                    gint              x,
+                    gint              y,
+                    GtkSelectionData *selection_data,
+                    guint             info,
+                    guint             time,
+                    gpointer          data)
+{
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
+  gint length;
+  guint16 *vals;
+  gdouble color[4];
+
+  length = gtk_selection_data_get_length (selection_data);
+
+  if (length < 0)
+    return;
+  
+  /* We accept drops with the wrong format, since the KDE color
+   * chooser incorrectly drops application/x-color with format 8.
+   */
+  if (length != 8)
+    {
+      g_warning ("Received invalid color data\n");
+      return;
+    }
+
+  vals = (guint16 *) gtk_selection_data_get_data (selection_data);
+
+  color[0] = (gdouble)vals[0] / 0xffff;
+  color[1] = (gdouble)vals[1] / 0xffff;
+  color[2] = (gdouble)vals[2] / 0xffff;
+  color[3] = (gdouble)vals[3] / 0xffff;
+  palette_change_color (widget, colorsel, color);
+  set_color_internal (colorsel, color);
+}
+
+static gint
+palette_activate (GtkWidget   *widget,
+                 GdkEventKey *event,
+                 gpointer     data)
+{
+  /* should have a drawing area subclass with an activate signal */
+  if ((event->keyval == GDK_KEY_space) ||
+      (event->keyval == GDK_KEY_Return) ||
+      (event->keyval == GDK_KEY_ISO_Enter) ||
+      (event->keyval == GDK_KEY_KP_Enter) ||
+      (event->keyval == GDK_KEY_KP_Space))
+    {
+      if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "color_set")) != 0)
+        {
+          gdouble color[4];
+          palette_get_color (widget, color);
+          set_color_internal (GTK_COLOR_SELECTION (data), color);
+        }
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static gboolean
+palette_popup (GtkWidget *widget,
+               gpointer   data)
+{
+  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
+
+  do_popup (colorsel, widget, GDK_CURRENT_TIME);
+  return TRUE;
+}
+               
+
+static GtkWidget*
+palette_new (GtkColorSelection *colorsel)
+{
+  GtkWidget *retval;
+  GtkColorSelectionPrivate *priv;
+  
+  static const GtkTargetEntry targets[] = {
+    { "application/x-color", 0 }
+  };
+
+  priv = colorsel->private_data;
+  
+  retval = gtk_drawing_area_new ();
+
+  gtk_widget_set_can_focus (retval, TRUE);
+  
+  g_object_set_data (G_OBJECT (retval), I_("color_set"), GINT_TO_POINTER (0)); 
+  gtk_widget_set_events (retval, GDK_BUTTON_PRESS_MASK
+                         | GDK_BUTTON_RELEASE_MASK
+                         | GDK_EXPOSURE_MASK
+                         | GDK_ENTER_NOTIFY_MASK
+                         | GDK_LEAVE_NOTIFY_MASK);
+  
+  g_signal_connect (retval, "draw",
+                   G_CALLBACK (palette_draw), colorsel);
+  g_signal_connect (retval, "button-press-event",
+                   G_CALLBACK (palette_press), colorsel);
+  g_signal_connect (retval, "button-release-event",
+                   G_CALLBACK (palette_release), colorsel);
+  g_signal_connect (retval, "enter-notify-event",
+                   G_CALLBACK (palette_enter), colorsel);
+  g_signal_connect (retval, "leave-notify-event",
+                   G_CALLBACK (palette_leave), colorsel);
+  g_signal_connect (retval, "key-press-event",
+                   G_CALLBACK (palette_activate), colorsel);
+  g_signal_connect (retval, "popup-menu",
+                   G_CALLBACK (palette_popup), colorsel);
+  
+  gtk_drag_dest_set (retval,
+                    GTK_DEST_DEFAULT_HIGHLIGHT |
+                    GTK_DEST_DEFAULT_MOTION |
+                    GTK_DEST_DEFAULT_DROP,
+                    targets, 1,
+                    GDK_ACTION_COPY);
+  
+  g_signal_connect (retval, "drag-end",
+                    G_CALLBACK (palette_drag_end), NULL);
+  g_signal_connect (retval, "drag-data-received",
+                    G_CALLBACK (palette_drop_handle), colorsel);
+
+  gtk_widget_set_tooltip_text (retval,
+                        _("Click this palette entry to make it the current color. To change this entry, drag a color swatch here or right-click it and select \"Save color here.\""));
+  return retval;
+}
+
+
+/*
+ *
+ * The actual GtkColorSelection widget
+ *
+ */
+
+static GdkCursor *
+make_picker_cursor (GdkScreen *screen)
+{
+  GdkCursor *cursor;
+
+  cursor = gdk_cursor_new_from_name (gdk_screen_get_display (screen),
+                                    "color-picker");
+
+  if (!cursor)
+    {
+      GdkPixbuf *pixbuf;
+
+      pixbuf = gdk_pixbuf_new_from_data (dropper_bits,
+                                         GDK_COLORSPACE_RGB, TRUE, 8,
+                                         DROPPER_WIDTH, DROPPER_HEIGHT,
+                                         DROPPER_STRIDE,
+                                         NULL, NULL);
+
+      cursor = gdk_cursor_new_from_pixbuf (gdk_screen_get_display (screen),
+                                           pixbuf,
+                                          DROPPER_X_HOT, DROPPER_Y_HOT);
+      
+      g_object_unref (pixbuf);
+    }
+      
+  return cursor;
+}
+
+static void
+grab_color_at_pointer (GdkScreen *screen,
+                       GdkDevice *device,
+                       gint       x_root,
+                       gint       y_root,
+                       gpointer   data)
+{
+  GdkPixbuf *pixbuf;
+  guchar *pixels;
+  GtkColorSelection *colorsel = data;
+  GtkColorSelectionPrivate *priv;
+  GdkColor color;
+  GdkWindow *root_window = gdk_screen_get_root_window (screen);
+  
+  priv = colorsel->private_data;
+  
+  pixbuf = gdk_pixbuf_get_from_window (root_window,
+                                       x_root, y_root,
+                                       1, 1);
+  if (!pixbuf)
+    {
+      gint x, y;
+      GdkDisplay *display = gdk_screen_get_display (screen);
+      GdkWindow *window = gdk_display_get_window_at_device_position (display, device, &x, &y);
+      if (!window)
+       return;
+      pixbuf = gdk_pixbuf_get_from_window (window,
+                                           x, y,
+                                           1, 1);
+      if (!pixbuf)
+       return;
+    }
+  pixels = gdk_pixbuf_get_pixels (pixbuf);
+  color.red = pixels[0] * 0x101;
+  color.green = pixels[1] * 0x101;
+  color.blue = pixels[2] * 0x101;
+  g_object_unref (pixbuf);
+
+  priv->color[COLORSEL_RED] = SCALE (color.red);
+  priv->color[COLORSEL_GREEN] = SCALE (color.green);
+  priv->color[COLORSEL_BLUE] = SCALE (color.blue);
+  
+  gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
+                 priv->color[COLORSEL_GREEN],
+                 priv->color[COLORSEL_BLUE],
+                 &priv->color[COLORSEL_HUE],
+                 &priv->color[COLORSEL_SATURATION],
+                 &priv->color[COLORSEL_VALUE]);
+
+  update_color (colorsel);
+}
+
+static void
+shutdown_eyedropper (GtkWidget *widget)
+{
+  GtkColorSelection *colorsel;
+  GtkColorSelectionPrivate *priv;
+
+  colorsel = GTK_COLOR_SELECTION (widget);
+  priv = colorsel->private_data;
+
+  if (priv->has_grab)
+    {
+      gdk_device_ungrab (priv->keyboard_device, priv->grab_time);
+      gdk_device_ungrab (priv->pointer_device, priv->grab_time);
+      gtk_device_grab_remove (priv->dropper_grab_widget, priv->pointer_device);
+
+      priv->has_grab = FALSE;
+      priv->keyboard_device = NULL;
+      priv->pointer_device = NULL;
+    }
+}
+
+static void
+mouse_motion (GtkWidget      *invisible,
+             GdkEventMotion *event,
+             gpointer        data)
+{
+  grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event),
+                         gdk_event_get_device ((GdkEvent *) event),
+                         event->x_root, event->y_root, data);
+}
+
+static gboolean
+mouse_release (GtkWidget      *invisible,
+              GdkEventButton *event,
+              gpointer        data)
+{
+  /* GtkColorSelection *colorsel = data; */
+
+  if (event->button != 1)
+    return FALSE;
+
+  grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event),
+                         gdk_event_get_device ((GdkEvent *) event),
+                         event->x_root, event->y_root, data);
+
+  shutdown_eyedropper (GTK_WIDGET (data));
+  
+  g_signal_handlers_disconnect_by_func (invisible,
+                                       mouse_motion,
+                                       data);
+  g_signal_handlers_disconnect_by_func (invisible,
+                                       mouse_release,
+                                       data);
+
+  return TRUE;
+}
+
+/* Helper Functions */
 
 static gboolean
 key_press (GtkWidget   *invisible,
@@ -1313,26 +1805,30 @@ key_press (GtkWidget   *invisible,
            gpointer     data)
 {  
   GdkDisplay *display = gtk_widget_get_display (invisible);
-  GdkScreen *screen = gdk_event_get_screen ((GdkEvent *)event);
+  GdkScreen *screen = gdk_event_get_screen ((GdkEvent *) event);
+  GdkDevice *device, *pointer_device;
   guint state = event->state & gtk_accelerator_get_default_mod_mask ();
   gint x, y;
   gint dx, dy;
 
-  gdk_display_get_pointer (display, NULL, &x, &y, NULL);
+  device = gdk_event_get_device ((GdkEvent * ) event);
+  pointer_device = gdk_device_get_associated_device (device);
+  gdk_display_get_device_state (display, pointer_device, NULL, &x, &y, NULL);
 
   dx = 0;
   dy = 0;
 
   switch (event->keyval) 
     {
-    case GDK_space:
-    case GDK_Return:
-    case GDK_KP_Enter:
-    case GDK_KP_Space:
-      grab_color_at_mouse (screen, x, y, data);
+    case GDK_KEY_space:
+    case GDK_KEY_Return:
+    case GDK_KEY_ISO_Enter:
+    case GDK_KEY_KP_Enter:
+    case GDK_KEY_KP_Space:
+      grab_color_at_pointer (screen, pointer_device, x, y, data);
       /* fall through */
 
-    case GDK_Escape:
+    case GDK_KEY_Escape:
       shutdown_eyedropper (data);
       
       g_signal_handlers_disconnect_by_func (invisible,
@@ -1345,23 +1841,23 @@ key_press (GtkWidget   *invisible,
       return TRUE;
 
 #if defined GDK_WINDOWING_X11 || defined GDK_WINDOWING_WIN32
-    case GDK_Up:
-    case GDK_KP_Up:
+    case GDK_KEY_Up:
+    case GDK_KEY_KP_Up:
       dy = state == GDK_MOD1_MASK ? -BIG_STEP : -1;
       break;
 
-    case GDK_Down:
-    case GDK_KP_Down:
+    case GDK_KEY_Down:
+    case GDK_KEY_KP_Down:
       dy = state == GDK_MOD1_MASK ? BIG_STEP : 1;
       break;
 
-    case GDK_Left:
-    case GDK_KP_Left:
+    case GDK_KEY_Left:
+    case GDK_KEY_KP_Left:
       dx = state == GDK_MOD1_MASK ? -BIG_STEP : -1;
       break;
 
-    case GDK_Right:
-    case GDK_KP_Right:
+    case GDK_KEY_Right:
+    case GDK_KEY_KP_Right:
       dx = state == GDK_MOD1_MASK ? BIG_STEP : 1;
       break;
 #endif
@@ -1370,8 +1866,8 @@ key_press (GtkWidget   *invisible,
       return FALSE;
     }
 
-  gdk_display_warp_pointer (display, screen, x + dx, y + dy);
-  
+  gdk_display_warp_device (display, pointer_device, screen, x + dx, y + dy);
+
   return TRUE;
 
 }
@@ -1386,10 +1882,10 @@ mouse_press (GtkWidget      *invisible,
   if (event->type == GDK_BUTTON_PRESS &&
       event->button == 1)
     {
-      g_signal_connect (invisible, "motion_notify_event",
+      g_signal_connect (invisible, "motion-notify-event",
                         G_CALLBACK (mouse_motion),
                         data);
-      g_signal_connect (invisible, "button_release_event",
+      g_signal_connect (invisible, "button-release-event",
                         G_CALLBACK (mouse_release),
                         data);
       g_signal_handlers_disconnect_by_func (invisible,
@@ -1409,14 +1905,29 @@ static void
 get_screen_color (GtkWidget *button)
 {
   GtkColorSelection *colorsel = g_object_get_data (G_OBJECT (button), "COLORSEL");
-  ColorSelectionPrivate *priv = colorsel->private_data;
+  GtkColorSelectionPrivate *priv = colorsel->private_data;
   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
+  GdkDevice *device, *keyb_device, *pointer_device;
   GdkCursor *picker_cursor;
   GdkGrabStatus grab_status;
+  GdkWindow *window;
   GtkWidget *grab_widget, *toplevel;
 
   guint32 time = gtk_get_current_event_time ();
-  
+
+  device = gtk_get_current_event_device ();
+
+  if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
+    {
+      keyb_device = device;
+      pointer_device = gdk_device_get_associated_device (device);
+    }
+  else
+    {
+      pointer_device = device;
+      keyb_device = gdk_device_get_associated_device (device);
+    }
+
   if (priv->dropper_grab_widget == NULL)
     {
       grab_widget = gtk_window_new (GTK_WINDOW_POPUP);
@@ -1432,40 +1943,51 @@ get_screen_color (GtkWidget *button)
   
       if (GTK_IS_WINDOW (toplevel))
        {
-         if (GTK_WINDOW (toplevel)->group)
-           gtk_window_group_add_window (GTK_WINDOW (toplevel)->group, 
+          if (gtk_window_has_group (GTK_WINDOW (toplevel)))
+           gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
                                         GTK_WINDOW (grab_widget));
        }
 
       priv->dropper_grab_widget = grab_widget;
     }
 
-  if (gdk_keyboard_grab (priv->dropper_grab_widget->window,
-                         FALSE, time) != GDK_GRAB_SUCCESS)
+  window = gtk_widget_get_window (priv->dropper_grab_widget);
+
+  if (gdk_device_grab (keyb_device,
+                       window,
+                       GDK_OWNERSHIP_APPLICATION, FALSE,
+                       GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+                       NULL, time) != GDK_GRAB_SUCCESS)
     return;
-  
+
   picker_cursor = make_picker_cursor (screen);
-  grab_status = gdk_pointer_grab (priv->dropper_grab_widget->window,
-                                 FALSE,
-                                 GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
-                                 NULL,
-                                 picker_cursor,
-                                 time);
+  grab_status = gdk_device_grab (pointer_device,
+                                 window,
+                                 GDK_OWNERSHIP_APPLICATION,
+                                 FALSE,
+                                 GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
+                                 picker_cursor,
+                                 time);
   gdk_cursor_unref (picker_cursor);
-  
+
   if (grab_status != GDK_GRAB_SUCCESS)
     {
-      gdk_display_keyboard_ungrab (gtk_widget_get_display (button), time);
+      gdk_device_ungrab (keyb_device, time);
       return;
     }
 
-  gtk_grab_add (priv->dropper_grab_widget);
+  gtk_device_grab_add (priv->dropper_grab_widget,
+                       pointer_device,
+                       TRUE);
+
   priv->grab_time = time;
   priv->has_grab = TRUE;
-  
-  g_signal_connect (priv->dropper_grab_widget, "button_press_event",
+  priv->keyboard_device = keyb_device;
+  priv->pointer_device = pointer_device;
+
+  g_signal_connect (priv->dropper_grab_widget, "button-press-event",
                     G_CALLBACK (mouse_press), colorsel);
-  g_signal_connect (priv->dropper_grab_widget, "key_press_event",
+  g_signal_connect (priv->dropper_grab_widget, "key-press-event",
                     G_CALLBACK (key_press), colorsel);
 }
 
@@ -1474,7 +1996,7 @@ hex_changed (GtkWidget *hex_entry,
             gpointer   data)
 {
   GtkColorSelection *colorsel;
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   GdkColor color;
   gchar *text;
   
@@ -1516,7 +2038,7 @@ hsv_changed (GtkWidget *hsv,
             gpointer   data)
 {
   GtkColorSelection *colorsel;
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   colorsel = GTK_COLOR_SELECTION (data);
   priv = colorsel->private_data;
@@ -1542,7 +2064,7 @@ adjustment_changed (GtkAdjustment *adjustment,
                    gpointer       data)
 {
   GtkColorSelection *colorsel;
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   colorsel = GTK_COLOR_SELECTION (g_object_get_data (G_OBJECT (adjustment), "COLORSEL"));
   priv = colorsel->private_data;
@@ -1595,7 +2117,7 @@ opacity_entry_changed (GtkWidget *opacity_entry,
                       gpointer   data)
 {
   GtkColorSelection *colorsel;
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   GtkAdjustment *adj;
   gchar *text;
   
@@ -1629,23 +2151,23 @@ make_label_spinbutton (GtkColorSelection *colorsel,
 
   if (channel_type == COLORSEL_HUE)
     {
-      adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 1.0, 1.0));
+      adjust = gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 1.0, 0.0);
     }
   else if (channel_type == COLORSEL_SATURATION ||
           channel_type == COLORSEL_VALUE)
     {
-      adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 1.0, 1.0));
+      adjust = gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 1.0, 0.0);
     }
   else
     {
-      adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 1.0));
+      adjust = gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0);
     }
   g_object_set_data (G_OBJECT (adjust), I_("COLORSEL"), colorsel);
   *spinbutton = gtk_spin_button_new (adjust, 10.0, 0);
 
   gtk_widget_set_tooltip_text (*spinbutton, tooltip);  
 
-  g_signal_connect (adjust, "value_changed",
+  g_signal_connect (adjust, "value-changed",
                     G_CALLBACK (adjustment_changed),
                     GINT_TO_POINTER (channel_type));
   label = gtk_label_new_with_mnemonic (text);
@@ -1663,7 +2185,7 @@ make_palette_frame (GtkColorSelection *colorsel,
                    gint               j)
 {
   GtkWidget *frame;
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   priv = colorsel->private_data;
   frame = gtk_frame_new (NULL);
@@ -1678,7 +2200,7 @@ make_palette_frame (GtkColorSelection *colorsel,
 static void 
 set_selected_palette (GtkColorSelection *colorsel, int x, int y)
 {
-  ColorSelectionPrivate *priv = colorsel->private_data; 
+  GtkColorSelectionPrivate *priv = colorsel->private_data; 
 
   gtk_widget_grab_focus (priv->custom_palette[x][y]);
 }
@@ -1695,7 +2217,7 @@ scale_round (double val, double factor)
 static void
 update_color (GtkColorSelection *colorsel)
 {
-  ColorSelectionPrivate *priv = colorsel->private_data;
+  GtkColorSelectionPrivate *priv = colorsel->private_data;
   gchar entryval[12];
   gchar opacity_text[32];
   gchar *ptr;
@@ -1771,361 +2293,45 @@ update_palette (GtkColorSelection *colorsel)
 
           index = i * GTK_CUSTOM_PALETTE_WIDTH + j;
           
-          gtk_color_selection_set_palette_color (colorsel,
-                                                 index,
-                                                 &current_colors[index]);
-       }
-    }
-
-  g_free (current_colors);
-}
-
-static void
-palette_change_notify_instance (GObject    *object,
-                                GParamSpec *pspec,
-                                gpointer    data)
-{
-  update_palette (GTK_COLOR_SELECTION (data));
-}
-
-static void
-default_noscreen_change_palette_func (const GdkColor *colors,
-                                     gint            n_colors)
-{
-  default_change_palette_func (gdk_screen_get_default (), colors, n_colors);
-}
-
-static void
-default_change_palette_func (GdkScreen     *screen,
-                            const GdkColor *colors,
-                             gint            n_colors)
-{
-  gchar *str;
-  
-  str = gtk_color_selection_palette_to_string (colors, n_colors);
-
-  gtk_settings_set_string_property (gtk_settings_get_for_screen (screen),
-                                    "gtk-color-palette",
-                                    str,
-                                    "gtk_color_selection_palette_to_string");
-
-  g_free (str);
-}
-
-G_DEFINE_TYPE (GtkColorSelection, gtk_color_selection, GTK_TYPE_VBOX)
-
-static void
-gtk_color_selection_class_init (GtkColorSelectionClass *klass)
-{
-  GObjectClass *gobject_class;
-  GtkObjectClass *object_class;
-  GtkWidgetClass *widget_class;
-  
-  gobject_class = G_OBJECT_CLASS (klass);
-  object_class = GTK_OBJECT_CLASS (klass);
-  widget_class = GTK_WIDGET_CLASS (klass);
-  
-  object_class->destroy = gtk_color_selection_destroy;
-  gobject_class->finalize = gtk_color_selection_finalize;
-  
-  gobject_class->set_property = gtk_color_selection_set_property;
-  gobject_class->get_property = gtk_color_selection_get_property;
-
-  widget_class->realize = gtk_color_selection_realize;
-  widget_class->unrealize = gtk_color_selection_unrealize;
-  widget_class->show_all = gtk_color_selection_show_all;
-  widget_class->grab_broken_event = gtk_color_selection_grab_broken;
-  
-  g_object_class_install_property (gobject_class,
-                                   PROP_HAS_OPACITY_CONTROL,
-                                   g_param_spec_boolean ("has-opacity-control",
-                                                        P_("Has Opacity Control"),
-                                                        P_("Whether the color selector should allow setting opacity"),
-                                                        FALSE,
-                                                        GTK_PARAM_READWRITE));
-  g_object_class_install_property (gobject_class,
-                                   PROP_HAS_PALETTE,
-                                   g_param_spec_boolean ("has-palette",
-                                                        P_("Has palette"),
-                                                        P_("Whether a palette should be used"),
-                                                        FALSE,
-                                                        GTK_PARAM_READWRITE));
-  g_object_class_install_property (gobject_class,
-                                   PROP_CURRENT_COLOR,
-                                   g_param_spec_boxed ("current-color",
-                                                       P_("Current Color"),
-                                                       P_("The current color"),
-                                                       GDK_TYPE_COLOR,
-                                                       GTK_PARAM_READWRITE));
-  g_object_class_install_property (gobject_class,
-                                   PROP_CURRENT_ALPHA,
-                                   g_param_spec_uint ("current-alpha",
-                                                     P_("Current Alpha"),
-                                                     P_("The current opacity value (0 fully transparent, 65535 fully opaque)"),
-                                                     0, 65535, 65535,
-                                                     GTK_PARAM_READWRITE));
-  
-  color_selection_signals[COLOR_CHANGED] =
-    g_signal_new (I_("color_changed"),
-                 G_OBJECT_CLASS_TYPE (object_class),
-                 G_SIGNAL_RUN_FIRST,
-                 G_STRUCT_OFFSET (GtkColorSelectionClass, color_changed),
-                 NULL, NULL,
-                 _gtk_marshal_VOID__VOID,
-                 G_TYPE_NONE, 0);
-
-  gtk_settings_install_property (g_param_spec_string ("gtk-color-palette",
-                                                      P_("Custom palette"),
-                                                      P_("Palette to use in the color selector"),
-                                                      default_colors,
-                                                      GTK_PARAM_READWRITE));
-
-   g_type_class_add_private (gobject_class, sizeof (ColorSelectionPrivate));
-}
-
-/* widget functions */
-
-static void
-gtk_color_selection_init (GtkColorSelection *colorsel)
-{
-  GtkWidget *top_hbox;
-  GtkWidget *top_right_vbox;
-  GtkWidget *table, *label, *hbox, *frame, *vbox, *button;
-  GtkAdjustment *adjust;
-  GtkWidget *picker_image;
-  gint i, j;
-  ColorSelectionPrivate *priv;
-  AtkObject *atk_obj;
-  GList *focus_chain = NULL;
-  
-  gtk_widget_push_composite_child ();
-
-  priv = colorsel->private_data = G_TYPE_INSTANCE_GET_PRIVATE (colorsel, GTK_TYPE_COLOR_SELECTION, ColorSelectionPrivate);
-  priv->changing = FALSE;
-  priv->default_set = FALSE;
-  priv->default_alpha_set = FALSE;
-  
-  top_hbox = gtk_hbox_new (FALSE, 12);
-  gtk_box_pack_start (GTK_BOX (colorsel), top_hbox, FALSE, FALSE, 0);
-  
-  vbox = gtk_vbox_new (FALSE, 6);
-  priv->triangle_colorsel = gtk_hsv_new ();
-  g_signal_connect (priv->triangle_colorsel, "changed",
-                    G_CALLBACK (hsv_changed), colorsel);
-  gtk_hsv_set_metrics (GTK_HSV (priv->triangle_colorsel), 174, 15);
-  gtk_box_pack_start (GTK_BOX (top_hbox), vbox, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (vbox), priv->triangle_colorsel, FALSE, FALSE, 0);
-  gtk_widget_set_tooltip_text (priv->triangle_colorsel,
-                        _("Select the color you want from the outer ring. Select the darkness or lightness of that color using the inner triangle."));
-  
-  hbox = gtk_hbox_new (FALSE, 6);
-  gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-  
-  frame = gtk_frame_new (NULL);
-  gtk_widget_set_size_request (frame, -1, 30);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
-  color_sample_new (colorsel);
-  gtk_container_add (GTK_CONTAINER (frame), priv->sample_area);
-  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
-  
-  button = gtk_button_new ();
-
-  gtk_widget_set_events (button, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
-  g_object_set_data (G_OBJECT (button), I_("COLORSEL"), colorsel); 
-  g_signal_connect (button, "clicked",
-                    G_CALLBACK (get_screen_color), NULL);
-  picker_image = gtk_image_new_from_stock (GTK_STOCK_COLOR_PICKER, GTK_ICON_SIZE_BUTTON);
-  gtk_container_add (GTK_CONTAINER (button), picker_image);
-  gtk_widget_show (GTK_WIDGET (picker_image));
-  gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
-
-  gtk_widget_set_tooltip_text (button,
-                        _("Click the eyedropper, then click a color anywhere on your screen to select that color."));
-  
-  top_right_vbox = gtk_vbox_new (FALSE, 6);
-  gtk_box_pack_start (GTK_BOX (top_hbox), top_right_vbox, FALSE, FALSE, 0);
-  table = gtk_table_new (8, 6, FALSE);
-  gtk_box_pack_start (GTK_BOX (top_right_vbox), table, FALSE, FALSE, 0);
-  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
-  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
-  
-  make_label_spinbutton (colorsel, &priv->hue_spinbutton, _("_Hue:"), table, 0, 0, COLORSEL_HUE,
-                         _("Position on the color wheel."));
-  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (priv->hue_spinbutton), TRUE);
-  make_label_spinbutton (colorsel, &priv->sat_spinbutton, _("_Saturation:"), table, 0, 1, COLORSEL_SATURATION,
-                         _("\"Deepness\" of the color."));
-  make_label_spinbutton (colorsel, &priv->val_spinbutton, _("_Value:"), table, 0, 2, COLORSEL_VALUE,
-                         _("Brightness of the color."));
-  make_label_spinbutton (colorsel, &priv->red_spinbutton, _("_Red:"), table, 6, 0, COLORSEL_RED,
-                         _("Amount of red light in the color."));
-  make_label_spinbutton (colorsel, &priv->green_spinbutton, _("_Green:"), table, 6, 1, COLORSEL_GREEN,
-                         _("Amount of green light in the color."));
-  make_label_spinbutton (colorsel, &priv->blue_spinbutton, _("_Blue:"), table, 6, 2, COLORSEL_BLUE,
-                         _("Amount of blue light in the color."));
-  gtk_table_attach_defaults (GTK_TABLE (table), gtk_hseparator_new (), 0, 8, 3, 4); 
-
-  priv->opacity_label = gtk_label_new_with_mnemonic (_("Op_acity:")); 
-  gtk_misc_set_alignment (GTK_MISC (priv->opacity_label), 0.0, 0.5); 
-  gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_label, 0, 1, 4, 5); 
-  adjust = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0)); 
-  g_object_set_data (G_OBJECT (adjust), I_("COLORSEL"), colorsel); 
-  priv->opacity_slider = gtk_hscale_new (adjust);
-  gtk_widget_set_tooltip_text (priv->opacity_slider,
-                        _("Transparency of the color."));
-  gtk_label_set_mnemonic_widget (GTK_LABEL (priv->opacity_label),
-                                 priv->opacity_slider);
-  gtk_scale_set_draw_value (GTK_SCALE (priv->opacity_slider), FALSE);
-  g_signal_connect (adjust, "value_changed",
-                    G_CALLBACK (adjustment_changed),
-                    GINT_TO_POINTER (COLORSEL_OPACITY));
-  gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_slider, 1, 7, 4, 5); 
-  priv->opacity_entry = gtk_entry_new (); 
-  gtk_widget_set_tooltip_text (priv->opacity_entry,
-                        _("Transparency of the color."));
-  gtk_widget_set_size_request (priv->opacity_entry, 40, -1); 
-
-  g_signal_connect (priv->opacity_entry, "activate",
-                    G_CALLBACK (opacity_entry_changed), colorsel);
-  gtk_table_attach_defaults (GTK_TABLE (table), priv->opacity_entry, 7, 8, 4, 5);
-  
-  label = gtk_label_new_with_mnemonic (_("Color _name:"));
-  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 5, 6);
-  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  priv->hex_entry = gtk_entry_new ();
-
-  gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->hex_entry);
-
-  g_signal_connect (priv->hex_entry, "activate",
-                    G_CALLBACK (hex_changed), colorsel);
-
-  g_signal_connect (priv->hex_entry, "focus_out_event",
-                    G_CALLBACK (hex_focus_out), colorsel);
-
-  gtk_widget_set_tooltip_text (priv->hex_entry,
-                        _("You can enter an HTML-style hexadecimal color value, or simply a color name such as 'orange' in this entry."));
-  
-  gtk_entry_set_width_chars (GTK_ENTRY (priv->hex_entry), 7);
-  gtk_table_attach_defaults (GTK_TABLE (table), priv->hex_entry, 1, 5, 5, 6);
-
-  focus_chain = g_list_append (focus_chain, priv->hue_spinbutton);
-  focus_chain = g_list_append (focus_chain, priv->sat_spinbutton);
-  focus_chain = g_list_append (focus_chain, priv->val_spinbutton);
-  focus_chain = g_list_append (focus_chain, priv->red_spinbutton);
-  focus_chain = g_list_append (focus_chain, priv->green_spinbutton);
-  focus_chain = g_list_append (focus_chain, priv->blue_spinbutton);
-  focus_chain = g_list_append (focus_chain, priv->opacity_slider);
-  focus_chain = g_list_append (focus_chain, priv->opacity_entry);
-  focus_chain = g_list_append (focus_chain, priv->hex_entry);
-  gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
-  g_list_free (focus_chain);
-
-  /* Set up the palette */
-  table = gtk_table_new (GTK_CUSTOM_PALETTE_HEIGHT, GTK_CUSTOM_PALETTE_WIDTH, TRUE);
-  gtk_table_set_row_spacings (GTK_TABLE (table), 1);
-  gtk_table_set_col_spacings (GTK_TABLE (table), 1);
-  for (i = 0; i < GTK_CUSTOM_PALETTE_WIDTH; i++)
-    {
-      for (j = 0; j < GTK_CUSTOM_PALETTE_HEIGHT; j++)
-       {
-         make_palette_frame (colorsel, table, i, j);
-       }
-    }
-  set_selected_palette (colorsel, 0, 0);
-  priv->palette_frame = gtk_vbox_new (FALSE, 6);
-  label = gtk_label_new_with_mnemonic (_("_Palette:"));
-  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  gtk_box_pack_start (GTK_BOX (priv->palette_frame), label, FALSE, FALSE, 0);
-
-  gtk_label_set_mnemonic_widget (GTK_LABEL (label),
-                                 priv->custom_palette[0][0]);
-  
-  gtk_box_pack_end (GTK_BOX (top_right_vbox), priv->palette_frame, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (priv->palette_frame), table, FALSE, FALSE, 0);
-  
-  gtk_widget_show_all (top_hbox);
-
-  /* hide unused stuff */
-  
-  if (priv->has_opacity == FALSE)
-    {
-      gtk_widget_hide (priv->opacity_label);
-      gtk_widget_hide (priv->opacity_slider);
-      gtk_widget_hide (priv->opacity_entry);
-    }
-  
-  if (priv->has_palette == FALSE)
-    {
-      gtk_widget_hide (priv->palette_frame);
-    }
-
-  atk_obj = gtk_widget_get_accessible (priv->triangle_colorsel);
-  if (GTK_IS_ACCESSIBLE (atk_obj))
-    {
-      atk_object_set_name (atk_obj, _("Color Wheel"));
-      atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (colorsel)), ATK_ROLE_COLOR_CHOOSER);
-      make_all_relations (atk_obj, priv);
-    } 
-
-  gtk_widget_pop_composite_child ();
-}
-
-static void
-gtk_color_selection_destroy (GtkObject *object)
-{
-  GtkColorSelection *cselection = GTK_COLOR_SELECTION (object);
-  ColorSelectionPrivate *priv = cselection->private_data;
-
-  if (priv->dropper_grab_widget)
-    {
-      gtk_widget_destroy (priv->dropper_grab_widget);
-      priv->dropper_grab_widget = NULL;
+          gtk_color_selection_set_palette_color (colorsel,
+                                                 index,
+                                                 &current_colors[index]);
+       }
     }
 
-  GTK_OBJECT_CLASS (gtk_color_selection_parent_class)->destroy (object);
+  g_free (current_colors);
 }
 
 static void
-gtk_color_selection_finalize (GObject *object)
+palette_change_notify_instance (GObject    *object,
+                                GParamSpec *pspec,
+                                gpointer    data)
 {
-  G_OBJECT_CLASS (gtk_color_selection_parent_class)->finalize (object);
+  update_palette (GTK_COLOR_SELECTION (data));
 }
 
 static void
-gtk_color_selection_realize (GtkWidget *widget)
+default_noscreen_change_palette_func (const GdkColor *colors,
+                                     gint            n_colors)
 {
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (widget);
-  ColorSelectionPrivate *priv = colorsel->private_data;
-  GtkSettings *settings = gtk_widget_get_settings (widget);
-
-  priv->settings_connection =  g_signal_connect (settings,
-                                                "notify::gtk-color-palette",
-                                                G_CALLBACK (palette_change_notify_instance),
-                                                widget);
-  update_palette (colorsel);
-
-  GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->realize (widget);
+  default_change_palette_func (gdk_screen_get_default (), colors, n_colors);
 }
 
 static void
-gtk_color_selection_unrealize (GtkWidget *widget)
+default_change_palette_func (GdkScreen     *screen,
+                            const GdkColor *colors,
+                             gint            n_colors)
 {
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (widget);
-  ColorSelectionPrivate *priv = colorsel->private_data;
-  GtkSettings *settings = gtk_widget_get_settings (widget);
-
-  g_signal_handler_disconnect (settings, priv->settings_connection);
+  gchar *str;
+  
+  str = gtk_color_selection_palette_to_string (colors, n_colors);
 
-  GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->unrealize (widget);
-}
+  gtk_settings_set_string_property (gtk_settings_get_for_screen (screen),
+                                    "gtk-color-palette",
+                                    str,
+                                    "gtk_color_selection_palette_to_string");
 
-/* We override show-all since we have internal widgets that
- * shouldn't be shown when you call show_all(), like the
- * palette and opacity sliders.
- */
-static void
-gtk_color_selection_show_all (GtkWidget *widget)
-{
-  gtk_widget_show (widget);
+  g_free (str);
 }
 
 /**
@@ -2139,7 +2345,7 @@ GtkWidget *
 gtk_color_selection_new (void)
 {
   GtkColorSelection *colorsel;
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   gdouble color[4];
   color[0] = 1.0;
   color[1] = 1.0;
@@ -2159,14 +2365,6 @@ gtk_color_selection_new (void)
   return GTK_WIDGET (colorsel);
 }
 
-
-void
-gtk_color_selection_set_update_policy (GtkColorSelection *colorsel,
-                                      GtkUpdateType      policy)
-{
-  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
-}
-
 /**
  * gtk_color_selection_get_has_opacity_control:
  * @colorsel: a #GtkColorSelection.
@@ -2178,7 +2376,7 @@ gtk_color_selection_set_update_policy (GtkColorSelection *colorsel,
 gboolean
 gtk_color_selection_get_has_opacity_control (GtkColorSelection *colorsel)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
   
@@ -2199,7 +2397,7 @@ void
 gtk_color_selection_set_has_opacity_control (GtkColorSelection *colorsel,
                                             gboolean           has_opacity)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
   
@@ -2238,7 +2436,7 @@ gtk_color_selection_set_has_opacity_control (GtkColorSelection *colorsel,
 gboolean
 gtk_color_selection_get_has_palette (GtkColorSelection *colorsel)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
   
@@ -2259,7 +2457,7 @@ void
 gtk_color_selection_set_has_palette (GtkColorSelection *colorsel,
                                     gboolean           has_palette)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
   
   priv = colorsel->private_data;
@@ -2272,7 +2470,9 @@ gtk_color_selection_set_has_palette (GtkColorSelection *colorsel,
        gtk_widget_show (priv->palette_frame);
       else
        gtk_widget_hide (priv->palette_frame);
-      
+
+      update_tooltips (colorsel);
+
       g_object_notify (G_OBJECT (colorsel), "has-palette");
     }
 }
@@ -2289,7 +2489,7 @@ void
 gtk_color_selection_set_current_color (GtkColorSelection *colorsel,
                                       const GdkColor    *color)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   gint i;
   
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
@@ -2327,7 +2527,7 @@ void
 gtk_color_selection_set_current_alpha (GtkColorSelection *colorsel,
                                       guint16            alpha)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   gint i;
   
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
@@ -2344,30 +2544,10 @@ gtk_color_selection_set_current_alpha (GtkColorSelection *colorsel,
   update_color (colorsel);
 }
 
-/**
- * gtk_color_selection_set_color:
- * @colorsel: a #GtkColorSelection.
- * @color: an array of 4 doubles specifying the red, green, blue and opacity 
- *   to set the current color to.
- *
- * Sets the current color to be @color.  The first time this is called, it will
- * also set the original color to be @color too.
- *
- * Deprecated: Use gtk_color_selection_set_current_color() instead.
- **/
-void
-gtk_color_selection_set_color (GtkColorSelection    *colorsel,
-                              gdouble              *color)
-{
-  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
-
-  set_color_internal (colorsel, color);
-}
-
 /**
  * gtk_color_selection_get_current_color:
  * @colorsel: a #GtkColorSelection.
- * @color: a #GdkColor to fill in with the current color.
+ * @color: (out): a #GdkColor to fill in with the current color.
  *
  * Sets @color to be the current color in the GtkColorSelection widget.
  **/
@@ -2375,7 +2555,7 @@ void
 gtk_color_selection_get_current_color (GtkColorSelection *colorsel,
                                       GdkColor          *color)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
   g_return_if_fail (color != NULL);
@@ -2397,7 +2577,7 @@ gtk_color_selection_get_current_color (GtkColorSelection *colorsel,
 guint16
 gtk_color_selection_get_current_alpha (GtkColorSelection *colorsel)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), 0);
   
@@ -2405,30 +2585,6 @@ gtk_color_selection_get_current_alpha (GtkColorSelection *colorsel)
   return priv->has_opacity ? UNSCALE (priv->color[COLORSEL_OPACITY]) : 65535;
 }
 
-/**
- * gtk_color_selection_get_color:
- * @colorsel: a #GtkColorSelection.
- * @color: an array of 4 #gdouble to fill in with the current color.
- *
- * Sets @color to be the current color in the GtkColorSelection widget.
- * 
- * This function is deprecated, use gtk_color_selection_get_current_color() instead.
- **/
-void
-gtk_color_selection_get_color (GtkColorSelection *colorsel,
-                              gdouble           *color)
-{
-  ColorSelectionPrivate *priv;
-  
-  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
-  
-  priv = colorsel->private_data;
-  color[0] = priv->color[COLORSEL_RED];
-  color[1] = priv->color[COLORSEL_GREEN];
-  color[2] = priv->color[COLORSEL_BLUE];
-  color[3] = priv->has_opacity ? priv->color[COLORSEL_OPACITY] : 65535;
-}
-
 /**
  * gtk_color_selection_set_previous_color:
  * @colorsel: a #GtkColorSelection.
@@ -2443,7 +2599,7 @@ void
 gtk_color_selection_set_previous_color (GtkColorSelection *colorsel,
                                        const GdkColor    *color)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
   g_return_if_fail (color != NULL);
@@ -2476,7 +2632,7 @@ void
 gtk_color_selection_set_previous_alpha (GtkColorSelection *colorsel,
                                        guint16            alpha)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
   
@@ -2500,7 +2656,7 @@ void
 gtk_color_selection_get_previous_color (GtkColorSelection *colorsel,
                                        GdkColor           *color)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
   g_return_if_fail (color != NULL);
@@ -2522,7 +2678,7 @@ gtk_color_selection_get_previous_color (GtkColorSelection *colorsel,
 guint16
 gtk_color_selection_get_previous_alpha (GtkColorSelection *colorsel)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), 0);
   
@@ -2530,6 +2686,142 @@ gtk_color_selection_get_previous_alpha (GtkColorSelection *colorsel)
   return priv->has_opacity ? UNSCALE (priv->old_color[COLORSEL_OPACITY]) : 65535;
 }
 
+/**
+ * gtk_color_selection_set_current_rgba:
+ * @colorsel: a #GtkColorSelection.
+ * @rgba: A #GdkRGBA to set the current color with
+ *
+ * Sets the current color to be @rgba.  The first time this is called, it will
+ * also set the original color to be @rgba too.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_color_selection_set_current_rgba (GtkColorSelection *colorsel,
+                                      const GdkRGBA     *rgba)
+{
+  GtkColorSelectionPrivate *priv;
+  gint i;
+
+  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
+  g_return_if_fail (rgba != NULL);
+
+  priv = colorsel->private_data;
+  priv->changing = TRUE;
+
+  priv->color[COLORSEL_RED] = CLAMP (rgba->red, 0, 1);
+  priv->color[COLORSEL_GREEN] = CLAMP (rgba->green, 0, 1);
+  priv->color[COLORSEL_BLUE] = CLAMP (rgba->blue, 0, 1);
+  priv->color[COLORSEL_OPACITY] = CLAMP (rgba->alpha, 0, 1);
+
+  gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
+                 priv->color[COLORSEL_GREEN],
+                 priv->color[COLORSEL_BLUE],
+                 &priv->color[COLORSEL_HUE],
+                 &priv->color[COLORSEL_SATURATION],
+                 &priv->color[COLORSEL_VALUE]);
+
+  if (priv->default_set == FALSE)
+    {
+      for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
+       priv->old_color[i] = priv->color[i];
+    }
+
+  priv->default_set = TRUE;
+  update_color (colorsel);
+}
+
+/**
+ * gtk_color_selection_get_current_rgba:
+ * @colorsel: a #GtkColorSelection.
+ * @rgba: (out): a #GdkRGBA to fill in with the current color.
+ *
+ * Sets @rgba to be the current color in the GtkColorSelection widget.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_color_selection_get_current_rgba (GtkColorSelection *colorsel,
+                                      GdkRGBA           *rgba)
+{
+  GtkColorSelectionPrivate *priv;
+
+  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
+  g_return_if_fail (rgba != NULL);
+
+  priv = colorsel->private_data;
+  rgba->red = priv->color[COLORSEL_RED];
+  rgba->green = priv->color[COLORSEL_GREEN];
+  rgba->blue = priv->color[COLORSEL_BLUE];
+  rgba->alpha = (priv->has_opacity) ? priv->color[COLORSEL_OPACITY] : 1;
+}
+
+/**
+ * gtk_color_selection_set_previous_rgba:
+ * @colorsel: a #GtkColorSelection.
+ * @rgba: a #GdkRGBA to set the previous color with
+ *
+ * Sets the 'previous' color to be @rgba.  This function should be called with
+ * some hesitations, as it might seem confusing to have that color change.
+ * Calling gtk_color_selection_set_current_rgba() will also set this color the first
+ * time it is called.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_color_selection_set_previous_rgba (GtkColorSelection *colorsel,
+                                       const GdkRGBA     *rgba)
+{
+  GtkColorSelectionPrivate *priv;
+
+  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
+  g_return_if_fail (rgba != NULL);
+
+  priv = colorsel->private_data;
+  priv->changing = TRUE;
+
+  priv->old_color[COLORSEL_RED] = CLAMP (rgba->red, 0, 1);
+  priv->old_color[COLORSEL_GREEN] = CLAMP (rgba->green, 0, 1);
+  priv->old_color[COLORSEL_BLUE] = CLAMP (rgba->blue, 0, 1);
+  priv->old_color[COLORSEL_OPACITY] = CLAMP (rgba->alpha, 0, 1);
+
+  gtk_rgb_to_hsv (priv->old_color[COLORSEL_RED],
+                 priv->old_color[COLORSEL_GREEN],
+                 priv->old_color[COLORSEL_BLUE],
+                 &priv->old_color[COLORSEL_HUE],
+                 &priv->old_color[COLORSEL_SATURATION],
+                 &priv->old_color[COLORSEL_VALUE]);
+
+  color_sample_update_samples (colorsel);
+  priv->default_set = TRUE;
+  priv->changing = FALSE;
+}
+
+/**
+ * gtk_color_selection_get_previous_rgba:
+ * @colorsel: a #GtkColorSelection.
+ * @rgba: a #GdkRGBA to fill in with the original color value.
+ *
+ * Fills @rgba in with the original color value.
+ *
+ * Since: 3.0
+ **/
+void
+gtk_color_selection_get_previous_rgba (GtkColorSelection *colorsel,
+                                       GdkRGBA           *rgba)
+{
+  GtkColorSelectionPrivate *priv;
+
+  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
+  g_return_if_fail (rgba != NULL);
+
+  priv = colorsel->private_data;
+  rgba->red = priv->old_color[COLORSEL_RED];
+  rgba->green = priv->old_color[COLORSEL_GREEN];
+  rgba->blue = priv->old_color[COLORSEL_BLUE];
+  rgba->alpha = (priv->has_opacity) ? priv->old_color[COLORSEL_OPACITY] : 1;
+}
+
 /**
  * gtk_color_selection_set_palette_color:
  * @colorsel: a #GtkColorSelection.
@@ -2544,7 +2836,7 @@ gtk_color_selection_set_palette_color (GtkColorSelection   *colorsel,
                                       gint                 index,
                                       GdkColor            *color)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   gint x, y;
   gdouble col[3];
   
@@ -2574,7 +2866,7 @@ gtk_color_selection_set_palette_color (GtkColorSelection   *colorsel,
 gboolean
 gtk_color_selection_is_adjusting (GtkColorSelection *colorsel)
 {
-  ColorSelectionPrivate *priv;
+  GtkColorSelectionPrivate *priv;
   
   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
   
@@ -2583,67 +2875,6 @@ gtk_color_selection_is_adjusting (GtkColorSelection *colorsel)
   return (gtk_hsv_is_adjusting (GTK_HSV (priv->triangle_colorsel)));
 }
 
-static void
-gtk_color_selection_set_property (GObject         *object,
-                                 guint            prop_id,
-                                 const GValue    *value,
-                                 GParamSpec      *pspec)
-{
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
-  
-  switch (prop_id)
-    {
-    case PROP_HAS_OPACITY_CONTROL:
-      gtk_color_selection_set_has_opacity_control (colorsel, 
-                                                  g_value_get_boolean (value));
-      break;
-    case PROP_HAS_PALETTE:
-      gtk_color_selection_set_has_palette (colorsel, 
-                                          g_value_get_boolean (value));
-      break;
-    case PROP_CURRENT_COLOR:
-      gtk_color_selection_set_current_color (colorsel, g_value_get_boxed (value));
-      break;
-    case PROP_CURRENT_ALPHA:
-      gtk_color_selection_set_current_alpha (colorsel, g_value_get_uint (value));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-  
-}
-
-static void
-gtk_color_selection_get_property (GObject     *object,
-                                 guint        prop_id,
-                                 GValue      *value,
-                                 GParamSpec  *pspec)
-{
-  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
-  GdkColor color;
-  
-  switch (prop_id)
-    {
-    case PROP_HAS_OPACITY_CONTROL:
-      g_value_set_boolean (value, gtk_color_selection_get_has_opacity_control (colorsel));
-      break;
-    case PROP_HAS_PALETTE:
-      g_value_set_boolean (value, gtk_color_selection_get_has_palette (colorsel));
-      break;
-    case PROP_CURRENT_COLOR:
-      gtk_color_selection_get_current_color (colorsel, &color);
-      g_value_set_boxed (value, &color);
-      break;
-    case PROP_CURRENT_ALPHA:
-      g_value_set_uint (value, gtk_color_selection_get_current_alpha (colorsel));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
 
 /**
  * gtk_color_selection_palette_from_string:
@@ -2778,34 +3009,6 @@ gtk_color_selection_palette_to_string (const GdkColor *colors,
   return retval;
 }
 
-/**
- * gtk_color_selection_set_change_palette_hook:
- * @func: a function to call when the custom palette needs saving.
- * 
- * Installs a global function to be called whenever the user tries to
- * modify the palette in a color selection. This function should save
- * the new palette contents, and update the GtkSettings property
- * "gtk-color-palette" so all GtkColorSelection widgets will be modified.
- *
- * Return value: the previous change palette hook (that was replaced).
- *
- * Deprecated: This function is deprecated in favor of 
- * gtk_color_selection_set_change_palette_with_screen_hook(), and does
- * not work in multihead environments.
- * 
- **/
-GtkColorSelectionChangePaletteFunc
-gtk_color_selection_set_change_palette_hook (GtkColorSelectionChangePaletteFunc func)
-{
-  GtkColorSelectionChangePaletteFunc old;
-
-  old = noscreen_change_palette_hook;
-
-  noscreen_change_palette_hook = func;
-
-  return old;
-}
-
 /**
  * gtk_color_selection_set_change_palette_with_screen_hook:
  * @func: a function to call when the custom palette needs saving.
@@ -2844,7 +3047,7 @@ make_control_relations (AtkObject *atk_obj,
 
 static void
 make_all_relations (AtkObject *atk_obj,
-                    ColorSelectionPrivate *priv)
+                    GtkColorSelectionPrivate *priv)
 {
   make_control_relations (atk_obj, priv->hue_spinbutton);
   make_control_relations (atk_obj, priv->sat_spinbutton);
@@ -2853,7 +3056,3 @@ make_all_relations (AtkObject *atk_obj,
   make_control_relations (atk_obj, priv->green_spinbutton);
   make_control_relations (atk_obj, priv->blue_spinbutton);
 }
-
-#define __GTK_COLOR_SELECTION_C__
-#include "gtkaliasdef.c"
-