]> Pileus Git - ~andy/gtk/blob - gtk/deprecated/gtkcolorsel.c
GtkBubbleWindow: use OSD style class
[~andy/gtk] / gtk / deprecated / gtkcolorsel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2000 Red Hat, Inc.
3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 /*
20  * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
21  * file for a list of people on the GTK+ Team.  See the ChangeLog
22  * files for a list of changes.  These files are distributed with
23  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
24  */
25
26 #include "config.h"
27
28 #define GDK_DISABLE_DEPRECATION_WARNINGS
29
30 #include "gtkcolorsel.h"
31
32 #include <math.h>
33 #include <string.h>
34
35 #include "gdk/gdk.h"
36 #include "gtkadjustment.h"
37 #include "gtkorientable.h"
38 #include "gtkhsv.h"
39 #include "gtkwindow.h"
40 #include "gtkselection.h"
41 #include "gtkcolorutils.h"
42 #include "gtkdnd.h"
43 #include "gtkdrawingarea.h"
44 #include "gtkframe.h"
45 #include "gtkgrid.h"
46 #include "gtklabel.h"
47 #include "gtkmarshalers.h"
48 #include "gtkimage.h"
49 #include "gtkspinbutton.h"
50 #include "gtkrange.h"
51 #include "gtkscale.h"
52 #include "gtkentry.h"
53 #include "gtkbutton.h"
54 #include "gtkmenuitem.h"
55 #include "gtkmain.h"
56 #include "gtksettings.h"
57 #include "gtkstock.h"
58 #include "gtkaccessible.h"
59 #include "gtksizerequest.h"
60 #include "gtkseparator.h"
61 #include "gtkprivate.h"
62 #include "gtkintl.h"
63
64
65 /**
66  * SECTION:gtkcolorsel
67  * @Short_description: Deprecated widget used to select a color
68  * @Title: GtkColorSelection
69  *
70  * The #GtkColorSelection is a widget that is used to select
71  * a color.  It consists of a color wheel and number of sliders
72  * and entry boxes for color parameters such as hue, saturation,
73  * value, red, green, blue, and opacity.  It is found on the standard
74  * color selection dialog box #GtkColorSelectionDialog.
75  */
76
77
78 /* Keep it in sync with gtksettings.c:default_color_palette */
79 #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"
80
81 /* Number of elements in the custom palatte */
82 #define GTK_CUSTOM_PALETTE_WIDTH 10
83 #define GTK_CUSTOM_PALETTE_HEIGHT 2
84
85 #define CUSTOM_PALETTE_ENTRY_WIDTH   20
86 #define CUSTOM_PALETTE_ENTRY_HEIGHT  20
87
88 /* The cursor for the dropper */
89 #define DROPPER_WIDTH 17
90 #define DROPPER_HEIGHT 17
91 #define DROPPER_STRIDE (DROPPER_WIDTH * 4)
92 #define DROPPER_X_HOT 2
93 #define DROPPER_Y_HOT 16
94
95 #define SAMPLE_WIDTH  64
96 #define SAMPLE_HEIGHT 28
97 #define CHECK_SIZE 16
98 #define BIG_STEP 20
99
100 /* Conversion between 0->1 double and and guint16. See
101  * scale_round() below for more general conversions
102  */
103 #define SCALE(i) (i / 65535.)
104 #define UNSCALE(d) ((guint16)(d * 65535 + 0.5))
105 #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
106
107 enum {
108   COLOR_CHANGED,
109   LAST_SIGNAL
110 };
111
112 enum {
113   PROP_0,
114   PROP_HAS_PALETTE,
115   PROP_HAS_OPACITY_CONTROL,
116   PROP_CURRENT_COLOR,
117   PROP_CURRENT_ALPHA,
118   PROP_CURRENT_RGBA
119 };
120
121 enum {
122   COLORSEL_RED = 0,
123   COLORSEL_GREEN = 1,
124   COLORSEL_BLUE = 2,
125   COLORSEL_OPACITY = 3,
126   COLORSEL_HUE,
127   COLORSEL_SATURATION,
128   COLORSEL_VALUE,
129   COLORSEL_NUM_CHANNELS
130 };
131
132
133 struct _GtkColorSelectionPrivate
134 {
135   guint has_opacity       : 1;
136   guint has_palette       : 1;
137   guint changing          : 1;
138   guint default_set       : 1;
139   guint default_alpha_set : 1;
140   guint has_grab          : 1;
141
142   gdouble color[COLORSEL_NUM_CHANNELS];
143   gdouble old_color[COLORSEL_NUM_CHANNELS];
144
145   GtkWidget *triangle_colorsel;
146   GtkWidget *hue_spinbutton;
147   GtkWidget *sat_spinbutton;
148   GtkWidget *val_spinbutton;
149   GtkWidget *red_spinbutton;
150   GtkWidget *green_spinbutton;
151   GtkWidget *blue_spinbutton;
152   GtkWidget *opacity_slider;
153   GtkWidget *opacity_label;
154   GtkWidget *opacity_entry;
155   GtkWidget *palette_frame;
156   GtkWidget *hex_entry;
157
158   /* The Palette code */
159   GtkWidget *custom_palette [GTK_CUSTOM_PALETTE_WIDTH][GTK_CUSTOM_PALETTE_HEIGHT];
160
161   /* The color_sample stuff */
162   GtkWidget *sample_area;
163   GtkWidget *old_sample;
164   GtkWidget *cur_sample;
165   GtkWidget *colorsel;
166
167   /* Window for grabbing on */
168   GtkWidget *dropper_grab_widget;
169   guint32    grab_time;
170   GdkDevice *keyboard_device;
171   GdkDevice *pointer_device;
172
173   /* Connection to settings */
174   gulong settings_connection;
175 };
176
177
178 static void gtk_color_selection_destroy         (GtkWidget               *widget);
179 static void gtk_color_selection_finalize        (GObject                 *object);
180 static void update_color                        (GtkColorSelection       *colorsel);
181 static void gtk_color_selection_set_property    (GObject                 *object,
182                                                  guint                    prop_id,
183                                                  const GValue            *value,
184                                                  GParamSpec              *pspec);
185 static void gtk_color_selection_get_property    (GObject                 *object,
186                                                  guint                    prop_id,
187                                                  GValue                  *value,
188                                                  GParamSpec              *pspec);
189
190 static void gtk_color_selection_realize         (GtkWidget               *widget);
191 static void gtk_color_selection_unrealize       (GtkWidget               *widget);
192 static void gtk_color_selection_show_all        (GtkWidget               *widget);
193 static gboolean gtk_color_selection_grab_broken (GtkWidget               *widget,
194                                                  GdkEventGrabBroken      *event);
195
196 static void     gtk_color_selection_set_palette_color   (GtkColorSelection *colorsel,
197                                                          gint               index,
198                                                          GdkColor          *color);
199 static void     set_focus_line_attributes               (GtkWidget         *drawing_area,
200                                                          cairo_t           *cr,
201                                                          gint              *focus_width);
202 static void     default_noscreen_change_palette_func    (const GdkColor    *colors,
203                                                          gint               n_colors);
204 static void     default_change_palette_func             (GdkScreen         *screen,
205                                                          const GdkColor    *colors,
206                                                          gint               n_colors);
207 static void     make_control_relations                  (AtkObject         *atk_obj,
208                                                          GtkWidget         *widget);
209 static void     make_all_relations                      (AtkObject         *atk_obj,
210                                                          GtkColorSelectionPrivate *priv);
211
212 static void     hsv_changed                             (GtkWidget         *hsv,
213                                                          gpointer           data);
214 static void     get_screen_color                        (GtkWidget         *button);
215 static void     adjustment_changed                      (GtkAdjustment     *adjustment,
216                                                          gpointer           data);
217 static void     opacity_entry_changed                   (GtkWidget         *opacity_entry,
218                                                          gpointer           data);
219 static void     hex_changed                             (GtkWidget         *hex_entry,
220                                                          gpointer           data);
221 static gboolean hex_focus_out                           (GtkWidget         *hex_entry,
222                                                          GdkEventFocus     *event,
223                                                          gpointer           data);
224 static void     color_sample_new                        (GtkColorSelection *colorsel);
225 static void     make_label_spinbutton                   (GtkColorSelection *colorsel,
226                                                          GtkWidget        **spinbutton,
227                                                          gchar             *text,
228                                                          GtkWidget         *table,
229                                                          gint               i,
230                                                          gint               j,
231                                                          gint               channel_type,
232                                                          const gchar       *tooltip);
233 static void     make_palette_frame                      (GtkColorSelection *colorsel,
234                                                          GtkWidget         *table,
235                                                          gint               i,
236                                                          gint               j);
237 static void     set_selected_palette                    (GtkColorSelection *colorsel,
238                                                          int                x,
239                                                          int                y);
240 static void     set_focus_line_attributes               (GtkWidget         *drawing_area,
241                                                          cairo_t           *cr,
242                                                          gint              *focus_width);
243 static gboolean mouse_press                             (GtkWidget         *invisible,
244                                                          GdkEventButton    *event,
245                                                          gpointer           data);
246 static void  palette_change_notify_instance (GObject    *object,
247                                              GParamSpec *pspec,
248                                              gpointer    data);
249 static void update_palette (GtkColorSelection *colorsel);
250 static void shutdown_eyedropper (GtkWidget *widget);
251
252 static guint color_selection_signals[LAST_SIGNAL] = { 0 };
253
254 static GtkColorSelectionChangePaletteFunc noscreen_change_palette_hook = default_noscreen_change_palette_func;
255 static GtkColorSelectionChangePaletteWithScreenFunc change_palette_hook = default_change_palette_func;
256
257 static const guchar dropper_bits[] = {
258   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
259   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377"
260   "\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"
261   "\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"
262   "\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"
263   "\0\0\0\0\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"
264   "\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"
265   "\0\0\0\0\0\0\0\0\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"
266   "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0"
267   "\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"
268   "\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"
269   "\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"
270   "\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"
271   "\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"
272   "\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"
273   "\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"
274   "\0\377\0\0\0\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0"
275   "\0\0\0\0\0\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"
276   "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\377\377"
277   "\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"
278   "\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
279   "\0\0\0\377\377\377\377\377\0\0\0\377\377\377\377\377\0\0\0\0\0\0\0\0"
280   "\0\0\0\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"
281   "\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\0\0\0\0\0\377\377"
282   "\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"
283   "\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0"
284   "\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"
285   "\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"
286   "\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"
287   "\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"
288   "\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"
289   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
290   "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0"
291   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
292   "\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"
293   "\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"
294   "\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"
295   "\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"
296   "\0\0\0\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"
297   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
298   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"};
299
300 G_DEFINE_TYPE (GtkColorSelection, gtk_color_selection, GTK_TYPE_BOX)
301
302 static void
303 gtk_color_selection_class_init (GtkColorSelectionClass *klass)
304 {
305   GObjectClass *gobject_class;
306   GtkWidgetClass *widget_class;
307
308   gobject_class = G_OBJECT_CLASS (klass);
309   gobject_class->finalize = gtk_color_selection_finalize;
310   gobject_class->set_property = gtk_color_selection_set_property;
311   gobject_class->get_property = gtk_color_selection_get_property;
312
313   widget_class = GTK_WIDGET_CLASS (klass);
314   widget_class->destroy = gtk_color_selection_destroy;
315   widget_class->realize = gtk_color_selection_realize;
316   widget_class->unrealize = gtk_color_selection_unrealize;
317   widget_class->show_all = gtk_color_selection_show_all;
318   widget_class->grab_broken_event = gtk_color_selection_grab_broken;
319
320   g_object_class_install_property (gobject_class,
321                                    PROP_HAS_OPACITY_CONTROL,
322                                    g_param_spec_boolean ("has-opacity-control",
323                                                          P_("Has Opacity Control"),
324                                                          P_("Whether the color selector should allow setting opacity"),
325                                                          FALSE,
326                                                          GTK_PARAM_READWRITE));
327   g_object_class_install_property (gobject_class,
328                                    PROP_HAS_PALETTE,
329                                    g_param_spec_boolean ("has-palette",
330                                                          P_("Has palette"),
331                                                          P_("Whether a palette should be used"),
332                                                          FALSE,
333                                                          GTK_PARAM_READWRITE));
334
335   /**
336    * GtkColorSelection:current-color:
337    *
338    * The current GdkColor color.
339    *
340    * Deprecated: 3.4: Use #GtkColorSelection:current-rgba instead.
341    */
342   g_object_class_install_property (gobject_class,
343                                    PROP_CURRENT_COLOR,
344                                    g_param_spec_boxed ("current-color",
345                                                        P_("Current Color"),
346                                                        P_("The current color"),
347                                                        GDK_TYPE_COLOR,
348                                                        GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
349   g_object_class_install_property (gobject_class,
350                                    PROP_CURRENT_ALPHA,
351                                    g_param_spec_uint ("current-alpha",
352                                                       P_("Current Alpha"),
353                                                       P_("The current opacity value (0 fully transparent, 65535 fully opaque)"),
354                                                       0, 65535, 65535,
355                                                       GTK_PARAM_READWRITE));
356
357   /**
358    * GtkColorSelection:current-rgba:
359    *
360    * The current RGBA color.
361    *
362    * Since: 3.0
363    */
364   g_object_class_install_property (gobject_class,
365                                    PROP_CURRENT_RGBA,
366                                    g_param_spec_boxed ("current-rgba",
367                                                        P_("Current RGBA"),
368                                                        P_("The current RGBA color"),
369                                                        GDK_TYPE_RGBA,
370                                                        GTK_PARAM_READWRITE));
371
372   /**
373    * GtkColorSelection::color-changed:
374    * @colorselection: the object which received the signal.
375    *
376    * This signal is emitted when the color changes in the #GtkColorSelection
377    * according to its update policy.
378    */
379   color_selection_signals[COLOR_CHANGED] =
380     g_signal_new (I_("color-changed"),
381                   G_OBJECT_CLASS_TYPE (gobject_class),
382                   G_SIGNAL_RUN_FIRST,
383                   G_STRUCT_OFFSET (GtkColorSelectionClass, color_changed),
384                   NULL, NULL,
385                   _gtk_marshal_VOID__VOID,
386                   G_TYPE_NONE, 0);
387
388   g_type_class_add_private (gobject_class, sizeof (GtkColorSelectionPrivate));
389 }
390
391 static void
392 gtk_color_selection_init (GtkColorSelection *colorsel)
393 {
394   GtkWidget *top_hbox;
395   GtkWidget *top_right_vbox;
396   GtkWidget *table, *label, *hbox, *frame, *vbox, *button;
397   GtkAdjustment *adjust;
398   GtkWidget *picker_image;
399   gint i, j;
400   GtkColorSelectionPrivate *priv;
401   AtkObject *atk_obj;
402   GList *focus_chain = NULL;
403
404   gtk_orientable_set_orientation (GTK_ORIENTABLE (colorsel),
405                                   GTK_ORIENTATION_VERTICAL);
406
407   gtk_widget_push_composite_child ();
408
409   priv = colorsel->private_data = G_TYPE_INSTANCE_GET_PRIVATE (colorsel, GTK_TYPE_COLOR_SELECTION, GtkColorSelectionPrivate);
410   priv->changing = FALSE;
411   priv->default_set = FALSE;
412   priv->default_alpha_set = FALSE;
413
414   top_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
415   gtk_box_pack_start (GTK_BOX (colorsel), top_hbox, FALSE, FALSE, 0);
416
417   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
418   priv->triangle_colorsel = gtk_hsv_new ();
419   g_signal_connect (priv->triangle_colorsel, "changed",
420                     G_CALLBACK (hsv_changed), colorsel);
421   gtk_hsv_set_metrics (GTK_HSV (priv->triangle_colorsel), 174, 15);
422   gtk_box_pack_start (GTK_BOX (top_hbox), vbox, FALSE, FALSE, 0);
423   gtk_box_pack_start (GTK_BOX (vbox), priv->triangle_colorsel, FALSE, FALSE, 0);
424   gtk_widget_set_tooltip_text (priv->triangle_colorsel,
425                         _("Select the color you want from the outer ring. "
426                           "Select the darkness or lightness of that color "
427                           "using the inner triangle."));
428
429   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
430   gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
431
432   frame = gtk_frame_new (NULL);
433   gtk_widget_set_size_request (frame, -1, 30);
434   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
435   color_sample_new (colorsel);
436   gtk_container_add (GTK_CONTAINER (frame), priv->sample_area);
437   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
438
439   button = gtk_button_new ();
440
441   gtk_widget_set_events (button, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);
442   g_object_set_data (G_OBJECT (button), I_("COLORSEL"), colorsel);
443   g_signal_connect (button, "clicked",
444                     G_CALLBACK (get_screen_color), NULL);
445   picker_image = gtk_image_new_from_stock (GTK_STOCK_COLOR_PICKER, GTK_ICON_SIZE_BUTTON);
446   gtk_container_add (GTK_CONTAINER (button), picker_image);
447   gtk_widget_show (GTK_WIDGET (picker_image));
448   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
449
450   gtk_widget_set_tooltip_text (button,
451                         _("Click the eyedropper, then click a color "
452                           "anywhere on your screen to select that color."));
453
454   top_right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
455   gtk_box_pack_start (GTK_BOX (top_hbox), top_right_vbox, FALSE, FALSE, 0);
456   table = gtk_grid_new ();
457   gtk_box_pack_start (GTK_BOX (top_right_vbox), table, FALSE, FALSE, 0);
458   gtk_grid_set_row_spacing (GTK_GRID (table), 6);
459   gtk_grid_set_column_spacing (GTK_GRID (table), 12);
460
461   make_label_spinbutton (colorsel, &priv->hue_spinbutton, _("_Hue:"), table, 0, 0, COLORSEL_HUE,
462                          _("Position on the color wheel."));
463   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (priv->hue_spinbutton), TRUE);
464   make_label_spinbutton (colorsel, &priv->sat_spinbutton, _("S_aturation:"), table, 0, 1, COLORSEL_SATURATION,
465                          _("Intensity of the color."));
466   make_label_spinbutton (colorsel, &priv->val_spinbutton, _("_Value:"), table, 0, 2, COLORSEL_VALUE,
467                          _("Brightness of the color."));
468   make_label_spinbutton (colorsel, &priv->red_spinbutton, _("_Red:"), table, 6, 0, COLORSEL_RED,
469                          _("Amount of red light in the color."));
470   make_label_spinbutton (colorsel, &priv->green_spinbutton, _("_Green:"), table, 6, 1, COLORSEL_GREEN,
471                          _("Amount of green light in the color."));
472   make_label_spinbutton (colorsel, &priv->blue_spinbutton, _("_Blue:"), table, 6, 2, COLORSEL_BLUE,
473                          _("Amount of blue light in the color."));
474   gtk_grid_attach (GTK_GRID (table), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL), 0, 3, 8, 1);
475
476   priv->opacity_label = gtk_label_new_with_mnemonic (_("Op_acity:"));
477   gtk_widget_set_halign (priv->opacity_label, GTK_ALIGN_START);
478   gtk_widget_set_valign (priv->opacity_label, GTK_ALIGN_CENTER);
479   gtk_grid_attach (GTK_GRID (table), priv->opacity_label, 0, 4, 1, 1);
480   adjust = gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0);
481   g_object_set_data (G_OBJECT (adjust), I_("COLORSEL"), colorsel);
482   priv->opacity_slider = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, adjust);
483   gtk_widget_set_tooltip_text (priv->opacity_slider,
484                         _("Transparency of the color."));
485   gtk_label_set_mnemonic_widget (GTK_LABEL (priv->opacity_label),
486                                  priv->opacity_slider);
487   gtk_scale_set_draw_value (GTK_SCALE (priv->opacity_slider), FALSE);
488   g_signal_connect (adjust, "value-changed",
489                     G_CALLBACK (adjustment_changed),
490                     GINT_TO_POINTER (COLORSEL_OPACITY));
491   gtk_grid_attach (GTK_GRID (table), priv->opacity_slider, 1, 4, 6, 1);
492   priv->opacity_entry = gtk_entry_new ();
493   gtk_widget_set_tooltip_text (priv->opacity_entry,
494                         _("Transparency of the color."));
495   gtk_widget_set_size_request (priv->opacity_entry, 40, -1);
496
497   g_signal_connect (priv->opacity_entry, "activate",
498                     G_CALLBACK (opacity_entry_changed), colorsel);
499   gtk_grid_attach (GTK_GRID (table), priv->opacity_entry, 7, 4, 1, 1);
500
501   label = gtk_label_new_with_mnemonic (_("Color _name:"));
502   gtk_grid_attach (GTK_GRID (table), label, 0, 5, 1, 1);
503   gtk_widget_set_halign (label, GTK_ALIGN_START);
504   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
505   priv->hex_entry = gtk_entry_new ();
506
507   gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->hex_entry);
508
509   g_signal_connect (priv->hex_entry, "activate",
510                     G_CALLBACK (hex_changed), colorsel);
511
512   g_signal_connect (priv->hex_entry, "focus-out-event",
513                     G_CALLBACK (hex_focus_out), colorsel);
514
515   gtk_widget_set_tooltip_text (priv->hex_entry,
516                         _("You can enter an HTML-style hexadecimal color "
517                           "value, or simply a color name such as 'orange' "
518                           "in this entry."));
519
520   gtk_entry_set_width_chars (GTK_ENTRY (priv->hex_entry), 7);
521   gtk_grid_attach (GTK_GRID (table), priv->hex_entry, 1, 5, 4, 1);
522
523   focus_chain = g_list_append (focus_chain, priv->hue_spinbutton);
524   focus_chain = g_list_append (focus_chain, priv->sat_spinbutton);
525   focus_chain = g_list_append (focus_chain, priv->val_spinbutton);
526   focus_chain = g_list_append (focus_chain, priv->red_spinbutton);
527   focus_chain = g_list_append (focus_chain, priv->green_spinbutton);
528   focus_chain = g_list_append (focus_chain, priv->blue_spinbutton);
529   focus_chain = g_list_append (focus_chain, priv->opacity_slider);
530   focus_chain = g_list_append (focus_chain, priv->opacity_entry);
531   focus_chain = g_list_append (focus_chain, priv->hex_entry);
532   gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
533   g_list_free (focus_chain);
534
535   /* Set up the palette */
536   table = gtk_grid_new ();
537   gtk_grid_set_row_spacing (GTK_GRID (table), 1);
538   gtk_grid_set_column_spacing (GTK_GRID (table), 1);
539   for (i = 0; i < GTK_CUSTOM_PALETTE_WIDTH; i++)
540     {
541       for (j = 0; j < GTK_CUSTOM_PALETTE_HEIGHT; j++)
542         {
543           make_palette_frame (colorsel, table, i, j);
544         }
545     }
546   set_selected_palette (colorsel, 0, 0);
547   priv->palette_frame = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
548   label = gtk_label_new_with_mnemonic (_("_Palette:"));
549   gtk_widget_set_halign (label, GTK_ALIGN_START);
550   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
551   gtk_box_pack_start (GTK_BOX (priv->palette_frame), label, FALSE, FALSE, 0);
552
553   gtk_label_set_mnemonic_widget (GTK_LABEL (label),
554                                  priv->custom_palette[0][0]);
555
556   gtk_box_pack_end (GTK_BOX (top_right_vbox), priv->palette_frame, FALSE, FALSE, 0);
557   gtk_box_pack_start (GTK_BOX (priv->palette_frame), table, FALSE, FALSE, 0);
558
559   gtk_widget_show_all (top_hbox);
560
561   /* hide unused stuff */
562
563   if (priv->has_opacity == FALSE)
564     {
565       gtk_widget_hide (priv->opacity_label);
566       gtk_widget_hide (priv->opacity_slider);
567       gtk_widget_hide (priv->opacity_entry);
568     }
569
570   if (priv->has_palette == FALSE)
571     {
572       gtk_widget_hide (priv->palette_frame);
573     }
574
575   atk_obj = gtk_widget_get_accessible (priv->triangle_colorsel);
576   if (GTK_IS_ACCESSIBLE (atk_obj))
577     {
578       atk_object_set_name (atk_obj, _("Color Wheel"));
579       atk_object_set_role (gtk_widget_get_accessible (GTK_WIDGET (colorsel)), ATK_ROLE_COLOR_CHOOSER);
580       make_all_relations (atk_obj, priv);
581     }
582
583   gtk_widget_pop_composite_child ();
584 }
585
586 /* GObject methods */
587 static void
588 gtk_color_selection_finalize (GObject *object)
589 {
590   G_OBJECT_CLASS (gtk_color_selection_parent_class)->finalize (object);
591 }
592
593 static void
594 gtk_color_selection_set_property (GObject         *object,
595                                   guint            prop_id,
596                                   const GValue    *value,
597                                   GParamSpec      *pspec)
598 {
599   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
600
601   switch (prop_id)
602     {
603     case PROP_HAS_OPACITY_CONTROL:
604       gtk_color_selection_set_has_opacity_control (colorsel,
605                                                    g_value_get_boolean (value));
606       break;
607     case PROP_HAS_PALETTE:
608       gtk_color_selection_set_has_palette (colorsel,
609                                            g_value_get_boolean (value));
610       break;
611     case PROP_CURRENT_COLOR:
612       {
613         GdkColor *color;
614         GdkRGBA rgba;
615
616         color = g_value_get_boxed (value);
617
618         rgba.red = SCALE (color->red);
619         rgba.green = SCALE (color->green);;
620         rgba.blue = SCALE (color->blue);
621         rgba.alpha = 1.0;
622
623         gtk_color_selection_set_current_rgba (colorsel, &rgba);
624       }
625       break;
626     case PROP_CURRENT_ALPHA:
627       gtk_color_selection_set_current_alpha (colorsel, g_value_get_uint (value));
628       break;
629     case PROP_CURRENT_RGBA:
630       gtk_color_selection_set_current_rgba (colorsel, g_value_get_boxed (value));
631       break;
632     default:
633       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
634       break;
635     }
636
637 }
638
639 static void
640 gtk_color_selection_get_property (GObject     *object,
641                                   guint        prop_id,
642                                   GValue      *value,
643                                   GParamSpec  *pspec)
644 {
645   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (object);
646
647   switch (prop_id)
648     {
649     case PROP_HAS_OPACITY_CONTROL:
650       g_value_set_boolean (value, gtk_color_selection_get_has_opacity_control (colorsel));
651       break;
652     case PROP_HAS_PALETTE:
653       g_value_set_boolean (value, gtk_color_selection_get_has_palette (colorsel));
654       break;
655     case PROP_CURRENT_COLOR:
656       {
657         GdkColor color;
658         GdkRGBA rgba;
659
660         gtk_color_selection_get_current_rgba (colorsel, &rgba);
661
662         color.red = UNSCALE (rgba.red);
663         color.green = UNSCALE (rgba.green);
664         color.blue = UNSCALE (rgba.blue);
665
666         g_value_set_boxed (value, &color);
667       }
668       break;
669     case PROP_CURRENT_ALPHA:
670       g_value_set_uint (value, gtk_color_selection_get_current_alpha (colorsel));
671       break;
672     case PROP_CURRENT_RGBA:
673       {
674         GdkRGBA rgba;
675
676         gtk_color_selection_get_current_rgba (colorsel, &rgba);
677         g_value_set_boxed (value, &rgba);
678       }
679       break;
680     default:
681       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
682       break;
683     }
684 }
685
686 /* GtkWidget methods */
687
688 static void
689 gtk_color_selection_destroy (GtkWidget *widget)
690 {
691   GtkColorSelection *cselection = GTK_COLOR_SELECTION (widget);
692   GtkColorSelectionPrivate *priv = cselection->private_data;
693
694   if (priv->dropper_grab_widget)
695     {
696       gtk_widget_destroy (priv->dropper_grab_widget);
697       priv->dropper_grab_widget = NULL;
698     }
699
700   GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->destroy (widget);
701 }
702
703 static void
704 gtk_color_selection_realize (GtkWidget *widget)
705 {
706   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (widget);
707   GtkColorSelectionPrivate *priv = colorsel->private_data;
708   GtkSettings *settings = gtk_widget_get_settings (widget);
709
710   priv->settings_connection =  g_signal_connect (settings,
711                                                  "notify::gtk-color-palette",
712                                                  G_CALLBACK (palette_change_notify_instance),
713                                                  widget);
714   update_palette (colorsel);
715
716   GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->realize (widget);
717 }
718
719 static void
720 gtk_color_selection_unrealize (GtkWidget *widget)
721 {
722   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (widget);
723   GtkColorSelectionPrivate *priv = colorsel->private_data;
724   GtkSettings *settings = gtk_widget_get_settings (widget);
725
726   g_signal_handler_disconnect (settings, priv->settings_connection);
727
728   GTK_WIDGET_CLASS (gtk_color_selection_parent_class)->unrealize (widget);
729 }
730
731 /* We override show-all since we have internal widgets that
732  * shouldn't be shown when you call show_all(), like the
733  * palette and opacity sliders.
734  */
735 static void
736 gtk_color_selection_show_all (GtkWidget *widget)
737 {
738   gtk_widget_show (widget);
739 }
740
741 static gboolean
742 gtk_color_selection_grab_broken (GtkWidget          *widget,
743                                  GdkEventGrabBroken *event)
744 {
745   shutdown_eyedropper (widget);
746
747   return TRUE;
748 }
749
750 /*
751  *
752  * The Sample Color
753  *
754  */
755
756 static void color_sample_draw_sample (GtkColorSelection *colorsel,
757                                       int                which,
758                                       cairo_t *          cr);
759 static void color_sample_update_samples (GtkColorSelection *colorsel);
760
761 static void
762 set_color_internal (GtkColorSelection *colorsel,
763                     gdouble           *color)
764 {
765   GtkColorSelectionPrivate *priv;
766   gint i;
767
768   priv = colorsel->private_data;
769   priv->changing = TRUE;
770   priv->color[COLORSEL_RED] = color[0];
771   priv->color[COLORSEL_GREEN] = color[1];
772   priv->color[COLORSEL_BLUE] = color[2];
773   priv->color[COLORSEL_OPACITY] = color[3];
774   gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
775                   priv->color[COLORSEL_GREEN],
776                   priv->color[COLORSEL_BLUE],
777                   &priv->color[COLORSEL_HUE],
778                   &priv->color[COLORSEL_SATURATION],
779                   &priv->color[COLORSEL_VALUE]);
780   if (priv->default_set == FALSE)
781     {
782       for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
783         priv->old_color[i] = priv->color[i];
784     }
785   priv->default_set = TRUE;
786   priv->default_alpha_set = TRUE;
787   update_color (colorsel);
788 }
789
790 static void
791 set_color_icon (GdkDragContext *context,
792                 gdouble        *colors)
793 {
794   GdkPixbuf *pixbuf;
795   guint32 pixel;
796
797   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
798                            8, 48, 32);
799
800   pixel = (((UNSCALE (colors[COLORSEL_RED])   & 0xff00) << 16) |
801            ((UNSCALE (colors[COLORSEL_GREEN]) & 0xff00) << 8) |
802            ((UNSCALE (colors[COLORSEL_BLUE])  & 0xff00)));
803
804   gdk_pixbuf_fill (pixbuf, pixel);
805
806   gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
807   g_object_unref (pixbuf);
808 }
809
810 static void
811 color_sample_drag_begin (GtkWidget      *widget,
812                          GdkDragContext *context,
813                          gpointer        data)
814 {
815   GtkColorSelection *colorsel = data;
816   GtkColorSelectionPrivate *priv;
817   gdouble *colsrc;
818
819   priv = colorsel->private_data;
820
821   if (widget == priv->old_sample)
822     colsrc = priv->old_color;
823   else
824     colsrc = priv->color;
825
826   set_color_icon (context, colsrc);
827 }
828
829 static void
830 color_sample_drag_end (GtkWidget      *widget,
831                        GdkDragContext *context,
832                        gpointer        data)
833 {
834   g_object_set_data (G_OBJECT (widget), I_("gtk-color-selection-drag-window"), NULL);
835 }
836
837 static void
838 color_sample_drop_handle (GtkWidget        *widget,
839                           GdkDragContext   *context,
840                           gint              x,
841                           gint              y,
842                           GtkSelectionData *selection_data,
843                           guint             info,
844                           guint             time,
845                           gpointer          data)
846 {
847   GtkColorSelection *colorsel = data;
848   GtkColorSelectionPrivate *priv;
849   gint length;
850   guint16 *vals;
851   gdouble color[4];
852   priv = colorsel->private_data;
853
854   /* This is currently a guint16 array of the format:
855    * R
856    * G
857    * B
858    * opacity
859    */
860
861   length = gtk_selection_data_get_length (selection_data);
862
863   if (length < 0)
864     return;
865
866   /* We accept drops with the wrong format, since the KDE color
867    * chooser incorrectly drops application/x-color with format 8.
868    */
869   if (length != 8)
870     {
871       g_warning ("Received invalid color data\n");
872       return;
873     }
874
875   vals = (guint16 *) gtk_selection_data_get_data (selection_data);
876
877   if (widget == priv->cur_sample)
878     {
879       color[0] = (gdouble)vals[0] / 0xffff;
880       color[1] = (gdouble)vals[1] / 0xffff;
881       color[2] = (gdouble)vals[2] / 0xffff;
882       color[3] = (gdouble)vals[3] / 0xffff;
883
884       set_color_internal (colorsel, color);
885     }
886 }
887
888 static void
889 color_sample_drag_handle (GtkWidget        *widget,
890                           GdkDragContext   *context,
891                           GtkSelectionData *selection_data,
892                           guint             info,
893                           guint             time,
894                           gpointer          data)
895 {
896   GtkColorSelection *colorsel = data;
897   GtkColorSelectionPrivate *priv;
898   guint16 vals[4];
899   gdouble *colsrc;
900
901   priv = colorsel->private_data;
902
903   if (widget == priv->old_sample)
904     colsrc = priv->old_color;
905   else
906     colsrc = priv->color;
907
908   vals[0] = colsrc[COLORSEL_RED] * 0xffff;
909   vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
910   vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
911   vals[3] = priv->has_opacity ? colsrc[COLORSEL_OPACITY] * 0xffff : 0xffff;
912
913   gtk_selection_data_set (selection_data,
914                           gdk_atom_intern_static_string ("application/x-color"),
915                           16, (guchar *)vals, 8);
916 }
917
918 /* which = 0 means draw old sample, which = 1 means draw new */
919 static void
920 color_sample_draw_sample (GtkColorSelection *colorsel,
921                           int                which,
922                           cairo_t           *cr)
923 {
924   GtkWidget *da;
925   gint x, y, goff;
926   GtkColorSelectionPrivate *priv;
927   int width, height;
928
929   g_return_if_fail (colorsel != NULL);
930   priv = colorsel->private_data;
931
932   g_return_if_fail (priv->sample_area != NULL);
933   if (!gtk_widget_is_drawable (priv->sample_area))
934     return;
935
936   if (which == 0)
937     {
938       da = priv->old_sample;
939       goff = 0;
940     }
941   else
942     {
943       GtkAllocation old_sample_allocation;
944
945       da = priv->cur_sample;
946       gtk_widget_get_allocation (priv->old_sample, &old_sample_allocation);
947       goff =  old_sample_allocation.width % 32;
948     }
949
950   /* Below needs tweaking for non-power-of-two */
951   width = gtk_widget_get_allocated_width (da);
952   height = gtk_widget_get_allocated_height (da);
953
954   if (priv->has_opacity)
955     {
956       /* Draw checks in background */
957
958       cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
959       cairo_rectangle (cr, 0, 0, width, height);
960       cairo_fill (cr);
961
962       cairo_set_source_rgb (cr, 0.75, 0.75, 0.75);
963       for (x = goff & -CHECK_SIZE; x < goff + width; x += CHECK_SIZE)
964         for (y = 0; y < height; y += CHECK_SIZE)
965           if ((x / CHECK_SIZE + y / CHECK_SIZE) % 2 == 0)
966             cairo_rectangle (cr, x - goff, y, CHECK_SIZE, CHECK_SIZE);
967       cairo_fill (cr);
968     }
969
970   if (which == 0)
971     {
972       cairo_set_source_rgba (cr,
973                              priv->old_color[COLORSEL_RED],
974                              priv->old_color[COLORSEL_GREEN],
975                              priv->old_color[COLORSEL_BLUE],
976                              priv->has_opacity ?
977                                 priv->old_color[COLORSEL_OPACITY] : 1.0);
978     }
979   else
980     {
981       cairo_set_source_rgba (cr,
982                              priv->color[COLORSEL_RED],
983                              priv->color[COLORSEL_GREEN],
984                              priv->color[COLORSEL_BLUE],
985                              priv->has_opacity ?
986                                priv->color[COLORSEL_OPACITY] : 1.0);
987     }
988
989   cairo_rectangle (cr, 0, 0, width, height);
990   cairo_fill (cr);
991 }
992
993
994 static void
995 color_sample_update_samples (GtkColorSelection *colorsel)
996 {
997   GtkColorSelectionPrivate *priv = colorsel->private_data;
998   gtk_widget_queue_draw (priv->old_sample);
999   gtk_widget_queue_draw (priv->cur_sample);
1000 }
1001
1002 static gboolean
1003 color_old_sample_draw (GtkWidget         *da,
1004                        cairo_t           *cr,
1005                        GtkColorSelection *colorsel)
1006 {
1007   color_sample_draw_sample (colorsel, 0, cr);
1008   return FALSE;
1009 }
1010
1011
1012 static gboolean
1013 color_cur_sample_draw (GtkWidget         *da,
1014                        cairo_t           *cr,
1015                        GtkColorSelection *colorsel)
1016 {
1017   color_sample_draw_sample (colorsel, 1, cr);
1018   return FALSE;
1019 }
1020
1021 static void
1022 color_sample_setup_dnd (GtkColorSelection *colorsel, GtkWidget *sample)
1023 {
1024   static const GtkTargetEntry targets[] = {
1025     { "application/x-color", 0 }
1026   };
1027   GtkColorSelectionPrivate *priv;
1028   priv = colorsel->private_data;
1029
1030   gtk_drag_source_set (sample,
1031                        GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
1032                        targets, 1,
1033                        GDK_ACTION_COPY | GDK_ACTION_MOVE);
1034
1035   g_signal_connect (sample, "drag-begin",
1036                     G_CALLBACK (color_sample_drag_begin),
1037                     colorsel);
1038   if (sample == priv->cur_sample)
1039     {
1040
1041       gtk_drag_dest_set (sample,
1042                          GTK_DEST_DEFAULT_HIGHLIGHT |
1043                          GTK_DEST_DEFAULT_MOTION |
1044                          GTK_DEST_DEFAULT_DROP,
1045                          targets, 1,
1046                          GDK_ACTION_COPY);
1047
1048       g_signal_connect (sample, "drag-end",
1049                         G_CALLBACK (color_sample_drag_end),
1050                         colorsel);
1051     }
1052
1053   g_signal_connect (sample, "drag-data-get",
1054                     G_CALLBACK (color_sample_drag_handle),
1055                     colorsel);
1056   g_signal_connect (sample, "drag-data-received",
1057                     G_CALLBACK (color_sample_drop_handle),
1058                     colorsel);
1059
1060 }
1061
1062 static void
1063 update_tooltips (GtkColorSelection *colorsel)
1064 {
1065   GtkColorSelectionPrivate *priv;
1066
1067   priv = colorsel->private_data;
1068
1069   if (priv->has_palette == TRUE)
1070     {
1071       gtk_widget_set_tooltip_text (priv->old_sample,
1072         _("The previously-selected color, for comparison to the color "
1073           "you're selecting now. You can drag this color to a palette "
1074           "entry, or select this color as current by dragging it to the "
1075           "other color swatch alongside."));
1076
1077       gtk_widget_set_tooltip_text (priv->cur_sample,
1078         _("The color you've chosen. You can drag this color to a palette "
1079           "entry to save it for use in the future."));
1080     }
1081   else
1082     {
1083       gtk_widget_set_tooltip_text (priv->old_sample,
1084         _("The previously-selected color, for comparison to the color "
1085           "you're selecting now."));
1086
1087       gtk_widget_set_tooltip_text (priv->cur_sample,
1088         _("The color you've chosen."));
1089     }
1090 }
1091
1092 static void
1093 color_sample_new (GtkColorSelection *colorsel)
1094 {
1095   GtkColorSelectionPrivate *priv;
1096
1097   priv = colorsel->private_data;
1098
1099   priv->sample_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1100   priv->old_sample = gtk_drawing_area_new ();
1101   priv->cur_sample = gtk_drawing_area_new ();
1102
1103   gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->old_sample,
1104                       TRUE, TRUE, 0);
1105   gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->cur_sample,
1106                       TRUE, TRUE, 0);
1107
1108   g_signal_connect (priv->old_sample, "draw",
1109                     G_CALLBACK (color_old_sample_draw),
1110                     colorsel);
1111   g_signal_connect (priv->cur_sample, "draw",
1112                     G_CALLBACK (color_cur_sample_draw),
1113                     colorsel);
1114
1115   color_sample_setup_dnd (colorsel, priv->old_sample);
1116   color_sample_setup_dnd (colorsel, priv->cur_sample);
1117
1118   update_tooltips (colorsel);
1119
1120   gtk_widget_show_all (priv->sample_area);
1121 }
1122
1123
1124 /* The palette area code */
1125
1126 static void
1127 palette_get_color (GtkWidget *drawing_area, gdouble *color)
1128 {
1129   gdouble *color_val;
1130
1131   g_return_if_fail (color != NULL);
1132
1133   color_val = g_object_get_data (G_OBJECT (drawing_area), "color_val");
1134   if (color_val == NULL)
1135     {
1136       /* Default to white for no good reason */
1137       color[0] = 1.0;
1138       color[1] = 1.0;
1139       color[2] = 1.0;
1140       color[3] = 1.0;
1141       return;
1142     }
1143
1144   color[0] = color_val[0];
1145   color[1] = color_val[1];
1146   color[2] = color_val[2];
1147   color[3] = 1.0;
1148 }
1149
1150 static gboolean
1151 palette_draw (GtkWidget *drawing_area,
1152                cairo_t   *cr,
1153                gpointer   data)
1154 {
1155   GtkStyleContext *context;
1156   gint focus_width;
1157   GdkRGBA color;
1158
1159   context = gtk_widget_get_style_context (drawing_area);
1160   gtk_style_context_get_background_color (context, 0, &color);
1161   gdk_cairo_set_source_rgba (cr, &color);
1162   cairo_paint (cr);
1163
1164   if (gtk_widget_has_visible_focus (drawing_area))
1165     {
1166       set_focus_line_attributes (drawing_area, cr, &focus_width);
1167
1168       cairo_rectangle (cr,
1169                        focus_width / 2., focus_width / 2.,
1170                        gtk_widget_get_allocated_width (drawing_area) - focus_width,
1171                        gtk_widget_get_allocated_height (drawing_area) - focus_width);
1172       cairo_stroke (cr);
1173     }
1174
1175   return FALSE;
1176 }
1177
1178 static void
1179 set_focus_line_attributes (GtkWidget *drawing_area,
1180                            cairo_t   *cr,
1181                            gint      *focus_width)
1182 {
1183   gdouble color[4];
1184   gint8 *dash_list;
1185
1186   gtk_widget_style_get (drawing_area,
1187                         "focus-line-width", focus_width,
1188                         "focus-line-pattern", (gchar *)&dash_list,
1189                         NULL);
1190
1191   palette_get_color (drawing_area, color);
1192
1193   if (INTENSITY (color[0], color[1], color[2]) > 0.5)
1194     cairo_set_source_rgb (cr, 0., 0., 0.);
1195   else
1196     cairo_set_source_rgb (cr, 1., 1., 1.);
1197
1198   cairo_set_line_width (cr, *focus_width);
1199
1200   if (dash_list[0])
1201     {
1202       gint n_dashes = strlen ((gchar *)dash_list);
1203       gdouble *dashes = g_new (gdouble, n_dashes);
1204       gdouble total_length = 0;
1205       gdouble dash_offset;
1206       gint i;
1207
1208       for (i = 0; i < n_dashes; i++)
1209         {
1210           dashes[i] = dash_list[i];
1211           total_length += dash_list[i];
1212         }
1213
1214       /* The dash offset here aligns the pattern to integer pixels
1215        * by starting the dash at the right side of the left border
1216        * Negative dash offsets in cairo don't work
1217        * (https://bugs.freedesktop.org/show_bug.cgi?id=2729)
1218        */
1219       dash_offset = - *focus_width / 2.;
1220       while (dash_offset < 0)
1221         dash_offset += total_length;
1222
1223       cairo_set_dash (cr, dashes, n_dashes, dash_offset);
1224       g_free (dashes);
1225     }
1226
1227   g_free (dash_list);
1228 }
1229
1230 static void
1231 palette_drag_begin (GtkWidget      *widget,
1232                     GdkDragContext *context,
1233                     gpointer        data)
1234 {
1235   gdouble colors[4];
1236
1237   palette_get_color (widget, colors);
1238   set_color_icon (context, colors);
1239 }
1240
1241 static void
1242 palette_drag_handle (GtkWidget        *widget,
1243                      GdkDragContext   *context,
1244                      GtkSelectionData *selection_data,
1245                      guint             info,
1246                      guint             time,
1247                      gpointer          data)
1248 {
1249   guint16 vals[4];
1250   gdouble colsrc[4];
1251
1252   palette_get_color (widget, colsrc);
1253
1254   vals[0] = colsrc[COLORSEL_RED] * 0xffff;
1255   vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
1256   vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
1257   vals[3] = 0xffff;
1258
1259   gtk_selection_data_set (selection_data,
1260                           gdk_atom_intern_static_string ("application/x-color"),
1261                           16, (guchar *)vals, 8);
1262 }
1263
1264 static void
1265 palette_drag_end (GtkWidget      *widget,
1266                   GdkDragContext *context,
1267                   gpointer        data)
1268 {
1269   g_object_set_data (G_OBJECT (widget), I_("gtk-color-selection-drag-window"), NULL);
1270 }
1271
1272 static GdkColor *
1273 get_current_colors (GtkColorSelection *colorsel)
1274 {
1275   GtkSettings *settings;
1276   GdkColor *colors = NULL;
1277   gint n_colors = 0;
1278   gchar *palette;
1279
1280   settings = gtk_widget_get_settings (GTK_WIDGET (colorsel));
1281   g_object_get (settings, "gtk-color-palette", &palette, NULL);
1282
1283   if (!gtk_color_selection_palette_from_string (palette, &colors, &n_colors))
1284     {
1285       gtk_color_selection_palette_from_string (DEFAULT_COLOR_PALETTE,
1286                                                &colors,
1287                                                &n_colors);
1288     }
1289   else
1290     {
1291       /* If there are less colors provided than the number of slots in the
1292        * color selection, we fill in the rest from the defaults.
1293        */
1294       if (n_colors < (GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT))
1295         {
1296           GdkColor *tmp_colors = colors;
1297           gint tmp_n_colors = n_colors;
1298
1299           gtk_color_selection_palette_from_string (DEFAULT_COLOR_PALETTE,
1300                                                    &colors,
1301                                                    &n_colors);
1302           memcpy (colors, tmp_colors, sizeof (GdkColor) * tmp_n_colors);
1303
1304           g_free (tmp_colors);
1305         }
1306     }
1307
1308   /* make sure that we fill every slot */
1309   g_assert (n_colors == GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
1310   g_free (palette);
1311
1312   return colors;
1313 }
1314
1315 /* Changes the model color */
1316 static void
1317 palette_change_color (GtkWidget         *drawing_area,
1318                       GtkColorSelection *colorsel,
1319                       gdouble           *color)
1320 {
1321   gint x, y;
1322   GtkColorSelectionPrivate *priv;
1323   GdkColor gdk_color;
1324   GdkColor *current_colors;
1325   GdkScreen *screen;
1326
1327   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
1328   g_return_if_fail (GTK_IS_DRAWING_AREA (drawing_area));
1329
1330   priv = colorsel->private_data;
1331
1332   gdk_color.red = UNSCALE (color[0]);
1333   gdk_color.green = UNSCALE (color[1]);
1334   gdk_color.blue = UNSCALE (color[2]);
1335   gdk_color.pixel = 0;
1336
1337   x = 0;
1338   y = 0;                        /* Quiet GCC */
1339   while (x < GTK_CUSTOM_PALETTE_WIDTH)
1340     {
1341       y = 0;
1342       while (y < GTK_CUSTOM_PALETTE_HEIGHT)
1343         {
1344           if (priv->custom_palette[x][y] == drawing_area)
1345             goto out;
1346
1347           ++y;
1348         }
1349
1350       ++x;
1351     }
1352
1353  out:
1354
1355   g_assert (x < GTK_CUSTOM_PALETTE_WIDTH || y < GTK_CUSTOM_PALETTE_HEIGHT);
1356
1357   current_colors = get_current_colors (colorsel);
1358   current_colors[y * GTK_CUSTOM_PALETTE_WIDTH + x] = gdk_color;
1359
1360   screen = gtk_widget_get_screen (GTK_WIDGET (colorsel));
1361   if (change_palette_hook != default_change_palette_func)
1362     (* change_palette_hook) (screen, current_colors,
1363                              GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
1364   else if (noscreen_change_palette_hook != default_noscreen_change_palette_func)
1365     {
1366       if (screen != gdk_screen_get_default ())
1367         g_warning ("gtk_color_selection_set_change_palette_hook used by "
1368                    "widget is not on the default screen.");
1369       (* noscreen_change_palette_hook) (current_colors,
1370                                         GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
1371     }
1372   else
1373     (* change_palette_hook) (screen, current_colors,
1374                              GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
1375
1376   g_free (current_colors);
1377 }
1378
1379 /* Changes the view color */
1380 static void
1381 palette_set_color (GtkWidget         *drawing_area,
1382                    GtkColorSelection *colorsel,
1383                    gdouble           *color)
1384 {
1385   gdouble *new_color = g_new (double, 4);
1386   GdkRGBA rgba;
1387
1388   rgba.red = color[0];
1389   rgba.green = color[1];
1390   rgba.blue = color[2];
1391   rgba.alpha = 1;
1392
1393   gtk_widget_override_background_color (drawing_area, GTK_STATE_FLAG_NORMAL, &rgba);
1394
1395   if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) == 0)
1396     {
1397       static const GtkTargetEntry targets[] = {
1398         { "application/x-color", 0 }
1399       };
1400       gtk_drag_source_set (drawing_area,
1401                            GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
1402                            targets, 1,
1403                            GDK_ACTION_COPY | GDK_ACTION_MOVE);
1404
1405       g_signal_connect (drawing_area, "drag-begin",
1406                         G_CALLBACK (palette_drag_begin),
1407                         colorsel);
1408       g_signal_connect (drawing_area, "drag-data-get",
1409                         G_CALLBACK (palette_drag_handle),
1410                         colorsel);
1411
1412       g_object_set_data (G_OBJECT (drawing_area), I_("color_set"),
1413                          GINT_TO_POINTER (1));
1414     }
1415
1416   new_color[0] = color[0];
1417   new_color[1] = color[1];
1418   new_color[2] = color[2];
1419   new_color[3] = 1.0;
1420
1421   g_object_set_data_full (G_OBJECT (drawing_area),
1422                           I_("color_val"), new_color, (GDestroyNotify)g_free);
1423 }
1424
1425 static void
1426 popup_position_func (GtkMenu   *menu,
1427                      gint      *x,
1428                      gint      *y,
1429                      gboolean  *push_in,
1430                      gpointer   user_data)
1431 {
1432   GtkAllocation allocation;
1433   GtkWidget *widget;
1434   GtkRequisition req;
1435   gint root_x, root_y;
1436   GdkScreen *screen;
1437
1438   widget = GTK_WIDGET (user_data);
1439
1440   g_return_if_fail (gtk_widget_get_realized (widget));
1441
1442   gdk_window_get_origin (gtk_widget_get_window (widget),
1443                          &root_x, &root_y);
1444
1445   gtk_widget_get_preferred_size (GTK_WIDGET (menu),
1446                                  &req, NULL);
1447   gtk_widget_get_allocation (widget, &allocation);
1448
1449   /* Put corner of menu centered on color cell */
1450   *x = root_x + allocation.width / 2;
1451   *y = root_y + allocation.height / 2;
1452
1453   /* Ensure sanity */
1454   screen = gtk_widget_get_screen (widget);
1455   *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
1456   *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
1457 }
1458
1459 static void
1460 save_color_selected (GtkWidget *menuitem,
1461                      gpointer   data)
1462 {
1463   GtkColorSelection *colorsel;
1464   GtkWidget *drawing_area;
1465   GtkColorSelectionPrivate *priv;
1466
1467   drawing_area = GTK_WIDGET (data);
1468
1469   colorsel = GTK_COLOR_SELECTION (g_object_get_data (G_OBJECT (drawing_area),
1470                                                      "gtk-color-sel"));
1471
1472   priv = colorsel->private_data;
1473
1474   palette_change_color (drawing_area, colorsel, priv->color);
1475 }
1476
1477 static void
1478 do_popup (GtkColorSelection *colorsel,
1479           GtkWidget         *drawing_area,
1480           guint32            timestamp)
1481 {
1482   GtkWidget *menu;
1483   GtkWidget *mi;
1484
1485   g_object_set_data (G_OBJECT (drawing_area),
1486                      I_("gtk-color-sel"),
1487                      colorsel);
1488
1489   menu = gtk_menu_new ();
1490
1491   mi = gtk_menu_item_new_with_mnemonic (_("_Save color here"));
1492
1493   g_signal_connect (mi, "activate",
1494                     G_CALLBACK (save_color_selected),
1495                     drawing_area);
1496
1497   gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
1498
1499   gtk_widget_show_all (mi);
1500
1501   gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
1502                   popup_position_func, drawing_area,
1503                   3, timestamp);
1504 }
1505
1506
1507 static gboolean
1508 palette_enter (GtkWidget        *drawing_area,
1509                GdkEventCrossing *event,
1510                gpointer        data)
1511 {
1512   g_object_set_data (G_OBJECT (drawing_area),
1513                      I_("gtk-colorsel-have-pointer"),
1514                      GUINT_TO_POINTER (TRUE));
1515
1516   return FALSE;
1517 }
1518
1519 static gboolean
1520 palette_leave (GtkWidget        *drawing_area,
1521                GdkEventCrossing *event,
1522                gpointer        data)
1523 {
1524   g_object_set_data (G_OBJECT (drawing_area),
1525                      I_("gtk-colorsel-have-pointer"),
1526                      NULL);
1527
1528   return FALSE;
1529 }
1530
1531 static gboolean
1532 palette_press (GtkWidget      *drawing_area,
1533                GdkEventButton *event,
1534                gpointer        data)
1535 {
1536   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
1537
1538   gtk_widget_grab_focus (drawing_area);
1539
1540   if (gdk_event_triggers_context_menu ((GdkEvent *) event))
1541     {
1542       do_popup (colorsel, drawing_area, event->time);
1543       return TRUE;
1544     }
1545
1546   return FALSE;
1547 }
1548
1549 static gboolean
1550 palette_release (GtkWidget      *drawing_area,
1551                  GdkEventButton *event,
1552                  gpointer        data)
1553 {
1554   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
1555
1556   gtk_widget_grab_focus (drawing_area);
1557
1558   if (event->button == GDK_BUTTON_PRIMARY &&
1559       g_object_get_data (G_OBJECT (drawing_area),
1560                          "gtk-colorsel-have-pointer") != NULL)
1561     {
1562       if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) != 0)
1563         {
1564           gdouble color[4];
1565           palette_get_color (drawing_area, color);
1566           set_color_internal (colorsel, color);
1567         }
1568     }
1569
1570   return FALSE;
1571 }
1572
1573 static void
1574 palette_drop_handle (GtkWidget        *widget,
1575                      GdkDragContext   *context,
1576                      gint              x,
1577                      gint              y,
1578                      GtkSelectionData *selection_data,
1579                      guint             info,
1580                      guint             time,
1581                      gpointer          data)
1582 {
1583   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
1584   gint length;
1585   guint16 *vals;
1586   gdouble color[4];
1587
1588   length = gtk_selection_data_get_length (selection_data);
1589
1590   if (length < 0)
1591     return;
1592
1593   /* We accept drops with the wrong format, since the KDE color
1594    * chooser incorrectly drops application/x-color with format 8.
1595    */
1596   if (length != 8)
1597     {
1598       g_warning ("Received invalid color data\n");
1599       return;
1600     }
1601
1602   vals = (guint16 *) gtk_selection_data_get_data (selection_data);
1603
1604   color[0] = (gdouble)vals[0] / 0xffff;
1605   color[1] = (gdouble)vals[1] / 0xffff;
1606   color[2] = (gdouble)vals[2] / 0xffff;
1607   color[3] = (gdouble)vals[3] / 0xffff;
1608   palette_change_color (widget, colorsel, color);
1609   set_color_internal (colorsel, color);
1610 }
1611
1612 static gint
1613 palette_activate (GtkWidget   *widget,
1614                   GdkEventKey *event,
1615                   gpointer     data)
1616 {
1617   /* should have a drawing area subclass with an activate signal */
1618   if ((event->keyval == GDK_KEY_space) ||
1619       (event->keyval == GDK_KEY_Return) ||
1620       (event->keyval == GDK_KEY_ISO_Enter) ||
1621       (event->keyval == GDK_KEY_KP_Enter) ||
1622       (event->keyval == GDK_KEY_KP_Space))
1623     {
1624       if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "color_set")) != 0)
1625         {
1626           gdouble color[4];
1627           palette_get_color (widget, color);
1628           set_color_internal (GTK_COLOR_SELECTION (data), color);
1629         }
1630       return TRUE;
1631     }
1632
1633   return FALSE;
1634 }
1635
1636 static gboolean
1637 palette_popup (GtkWidget *widget,
1638                gpointer   data)
1639 {
1640   GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
1641
1642   do_popup (colorsel, widget, GDK_CURRENT_TIME);
1643   return TRUE;
1644 }
1645
1646
1647 static GtkWidget*
1648 palette_new (GtkColorSelection *colorsel)
1649 {
1650   GtkWidget *retval;
1651
1652   static const GtkTargetEntry targets[] = {
1653     { "application/x-color", 0 }
1654   };
1655
1656   retval = gtk_drawing_area_new ();
1657
1658   gtk_widget_set_can_focus (retval, TRUE);
1659
1660   g_object_set_data (G_OBJECT (retval), I_("color_set"), GINT_TO_POINTER (0));
1661   gtk_widget_set_events (retval, GDK_BUTTON_PRESS_MASK
1662                          | GDK_BUTTON_RELEASE_MASK
1663                          | GDK_EXPOSURE_MASK
1664                          | GDK_ENTER_NOTIFY_MASK
1665                          | GDK_LEAVE_NOTIFY_MASK);
1666
1667   g_signal_connect (retval, "draw",
1668                     G_CALLBACK (palette_draw), colorsel);
1669   g_signal_connect (retval, "button-press-event",
1670                     G_CALLBACK (palette_press), colorsel);
1671   g_signal_connect (retval, "button-release-event",
1672                     G_CALLBACK (palette_release), colorsel);
1673   g_signal_connect (retval, "enter-notify-event",
1674                     G_CALLBACK (palette_enter), colorsel);
1675   g_signal_connect (retval, "leave-notify-event",
1676                     G_CALLBACK (palette_leave), colorsel);
1677   g_signal_connect (retval, "key-press-event",
1678                     G_CALLBACK (palette_activate), colorsel);
1679   g_signal_connect (retval, "popup-menu",
1680                     G_CALLBACK (palette_popup), colorsel);
1681
1682   gtk_drag_dest_set (retval,
1683                      GTK_DEST_DEFAULT_HIGHLIGHT |
1684                      GTK_DEST_DEFAULT_MOTION |
1685                      GTK_DEST_DEFAULT_DROP,
1686                      targets, 1,
1687                      GDK_ACTION_COPY);
1688
1689   g_signal_connect (retval, "drag-end",
1690                     G_CALLBACK (palette_drag_end), NULL);
1691   g_signal_connect (retval, "drag-data-received",
1692                     G_CALLBACK (palette_drop_handle), colorsel);
1693
1694   gtk_widget_set_tooltip_text (retval,
1695     _("Click this palette entry to make it the current color. "
1696       "To change this entry, drag a color swatch here or right-click "
1697       "it and select \"Save color here.\""));
1698   return retval;
1699 }
1700
1701
1702 /* The actual GtkColorSelection widget */
1703
1704 static GdkCursor *
1705 make_picker_cursor (GdkScreen *screen)
1706 {
1707   GdkCursor *cursor;
1708
1709   cursor = gdk_cursor_new_from_name (gdk_screen_get_display (screen),
1710                                      "color-picker");
1711
1712   if (!cursor)
1713     {
1714       GdkPixbuf *pixbuf;
1715
1716       pixbuf = gdk_pixbuf_new_from_data (dropper_bits,
1717                                          GDK_COLORSPACE_RGB, TRUE, 8,
1718                                          DROPPER_WIDTH, DROPPER_HEIGHT,
1719                                          DROPPER_STRIDE,
1720                                          NULL, NULL);
1721
1722       cursor = gdk_cursor_new_from_pixbuf (gdk_screen_get_display (screen),
1723                                            pixbuf,
1724                                            DROPPER_X_HOT, DROPPER_Y_HOT);
1725
1726       g_object_unref (pixbuf);
1727     }
1728
1729   return cursor;
1730 }
1731
1732 static void
1733 grab_color_at_pointer (GdkScreen *screen,
1734                        GdkDevice *device,
1735                        gint       x_root,
1736                        gint       y_root,
1737                        gpointer   data)
1738 {
1739   GdkPixbuf *pixbuf;
1740   guchar *pixels;
1741   GtkColorSelection *colorsel = data;
1742   GtkColorSelectionPrivate *priv;
1743   GdkColor color;
1744   GdkWindow *root_window = gdk_screen_get_root_window (screen);
1745
1746   priv = colorsel->private_data;
1747
1748   pixbuf = gdk_pixbuf_get_from_window (root_window,
1749                                        x_root, y_root,
1750                                        1, 1);
1751   if (!pixbuf)
1752     {
1753       gint x, y;
1754       GdkWindow *window = gdk_device_get_window_at_position (device, &x, &y);
1755       if (!window)
1756         return;
1757       pixbuf = gdk_pixbuf_get_from_window (window,
1758                                            x, y,
1759                                            1, 1);
1760       if (!pixbuf)
1761         return;
1762     }
1763   pixels = gdk_pixbuf_get_pixels (pixbuf);
1764   color.red = pixels[0] * 0x101;
1765   color.green = pixels[1] * 0x101;
1766   color.blue = pixels[2] * 0x101;
1767   g_object_unref (pixbuf);
1768
1769   priv->color[COLORSEL_RED] = SCALE (color.red);
1770   priv->color[COLORSEL_GREEN] = SCALE (color.green);
1771   priv->color[COLORSEL_BLUE] = SCALE (color.blue);
1772
1773   gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
1774                   priv->color[COLORSEL_GREEN],
1775                   priv->color[COLORSEL_BLUE],
1776                   &priv->color[COLORSEL_HUE],
1777                   &priv->color[COLORSEL_SATURATION],
1778                   &priv->color[COLORSEL_VALUE]);
1779
1780   update_color (colorsel);
1781 }
1782
1783 static void
1784 shutdown_eyedropper (GtkWidget *widget)
1785 {
1786   GtkColorSelection *colorsel;
1787   GtkColorSelectionPrivate *priv;
1788
1789   colorsel = GTK_COLOR_SELECTION (widget);
1790   priv = colorsel->private_data;
1791
1792   if (priv->has_grab)
1793     {
1794       gdk_device_ungrab (priv->keyboard_device, priv->grab_time);
1795       gdk_device_ungrab (priv->pointer_device, priv->grab_time);
1796       gtk_device_grab_remove (priv->dropper_grab_widget, priv->pointer_device);
1797
1798       priv->has_grab = FALSE;
1799       priv->keyboard_device = NULL;
1800       priv->pointer_device = NULL;
1801     }
1802 }
1803
1804 static void
1805 mouse_motion (GtkWidget      *invisible,
1806               GdkEventMotion *event,
1807               gpointer        data)
1808 {
1809   grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event),
1810                          gdk_event_get_device ((GdkEvent *) event),
1811                          event->x_root, event->y_root, data);
1812 }
1813
1814 static gboolean
1815 mouse_release (GtkWidget      *invisible,
1816                GdkEventButton *event,
1817                gpointer        data)
1818 {
1819   /* GtkColorSelection *colorsel = data; */
1820
1821   if (event->button != GDK_BUTTON_PRIMARY)
1822     return FALSE;
1823
1824   grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event),
1825                          gdk_event_get_device ((GdkEvent *) event),
1826                          event->x_root, event->y_root, data);
1827
1828   shutdown_eyedropper (GTK_WIDGET (data));
1829
1830   g_signal_handlers_disconnect_by_func (invisible,
1831                                         mouse_motion,
1832                                         data);
1833   g_signal_handlers_disconnect_by_func (invisible,
1834                                         mouse_release,
1835                                         data);
1836
1837   return TRUE;
1838 }
1839
1840 /* Helper Functions */
1841
1842 static gboolean
1843 key_press (GtkWidget   *invisible,
1844            GdkEventKey *event,
1845            gpointer     data)
1846 {
1847   GdkScreen *screen = gdk_event_get_screen ((GdkEvent *) event);
1848   GdkDevice *device, *pointer_device;
1849   guint state = event->state & gtk_accelerator_get_default_mod_mask ();
1850   gint x, y;
1851   gint dx, dy;
1852
1853   device = gdk_event_get_device ((GdkEvent * ) event);
1854   pointer_device = gdk_device_get_associated_device (device);
1855   gdk_device_get_position (pointer_device, NULL, &x, &y);
1856
1857   dx = 0;
1858   dy = 0;
1859
1860   switch (event->keyval)
1861     {
1862     case GDK_KEY_space:
1863     case GDK_KEY_Return:
1864     case GDK_KEY_ISO_Enter:
1865     case GDK_KEY_KP_Enter:
1866     case GDK_KEY_KP_Space:
1867       grab_color_at_pointer (screen, pointer_device, x, y, data);
1868       /* fall through */
1869
1870     case GDK_KEY_Escape:
1871       shutdown_eyedropper (data);
1872
1873       g_signal_handlers_disconnect_by_func (invisible,
1874                                             mouse_press,
1875                                             data);
1876       g_signal_handlers_disconnect_by_func (invisible,
1877                                             key_press,
1878                                             data);
1879
1880       return TRUE;
1881
1882     case GDK_KEY_Up:
1883     case GDK_KEY_KP_Up:
1884       dy = state == GDK_MOD1_MASK ? -BIG_STEP : -1;
1885       break;
1886
1887     case GDK_KEY_Down:
1888     case GDK_KEY_KP_Down:
1889       dy = state == GDK_MOD1_MASK ? BIG_STEP : 1;
1890       break;
1891
1892     case GDK_KEY_Left:
1893     case GDK_KEY_KP_Left:
1894       dx = state == GDK_MOD1_MASK ? -BIG_STEP : -1;
1895       break;
1896
1897     case GDK_KEY_Right:
1898     case GDK_KEY_KP_Right:
1899       dx = state == GDK_MOD1_MASK ? BIG_STEP : 1;
1900       break;
1901
1902     default:
1903       return FALSE;
1904     }
1905
1906   gdk_device_warp (pointer_device, screen, x + dx, y + dy);
1907
1908   return TRUE;
1909
1910 }
1911
1912 static gboolean
1913 mouse_press (GtkWidget      *invisible,
1914              GdkEventButton *event,
1915              gpointer        data)
1916 {
1917   if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY)
1918     {
1919       g_signal_connect (invisible, "motion-notify-event",
1920                         G_CALLBACK (mouse_motion), data);
1921       g_signal_connect (invisible, "button-release-event",
1922                         G_CALLBACK (mouse_release), data);
1923       g_signal_handlers_disconnect_by_func (invisible,
1924                                             mouse_press,
1925                                             data);
1926       g_signal_handlers_disconnect_by_func (invisible,
1927                                             key_press,
1928                                             data);
1929       return TRUE;
1930     }
1931
1932   return FALSE;
1933 }
1934
1935 /* when the button is clicked */
1936 static void
1937 get_screen_color (GtkWidget *button)
1938 {
1939   GtkColorSelection *colorsel = g_object_get_data (G_OBJECT (button), "COLORSEL");
1940   GtkColorSelectionPrivate *priv = colorsel->private_data;
1941   GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
1942   GdkDevice *device, *keyb_device, *pointer_device;
1943   GdkCursor *picker_cursor;
1944   GdkGrabStatus grab_status;
1945   GdkWindow *window;
1946   GtkWidget *grab_widget, *toplevel;
1947
1948   guint32 time = gtk_get_current_event_time ();
1949
1950   device = gtk_get_current_event_device ();
1951
1952   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
1953     {
1954       keyb_device = device;
1955       pointer_device = gdk_device_get_associated_device (device);
1956     }
1957   else
1958     {
1959       pointer_device = device;
1960       keyb_device = gdk_device_get_associated_device (device);
1961     }
1962
1963   if (priv->dropper_grab_widget == NULL)
1964     {
1965       grab_widget = gtk_window_new (GTK_WINDOW_POPUP);
1966       gtk_window_set_screen (GTK_WINDOW (grab_widget), screen);
1967       gtk_window_resize (GTK_WINDOW (grab_widget), 1, 1);
1968       gtk_window_move (GTK_WINDOW (grab_widget), -100, -100);
1969       gtk_widget_show (grab_widget);
1970
1971       gtk_widget_add_events (grab_widget,
1972                              GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
1973
1974       toplevel = gtk_widget_get_toplevel (GTK_WIDGET (colorsel));
1975
1976       if (GTK_IS_WINDOW (toplevel))
1977         {
1978           if (gtk_window_has_group (GTK_WINDOW (toplevel)))
1979             gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
1980                                          GTK_WINDOW (grab_widget));
1981         }
1982
1983       priv->dropper_grab_widget = grab_widget;
1984     }
1985
1986   window = gtk_widget_get_window (priv->dropper_grab_widget);
1987
1988   if (gdk_device_grab (keyb_device,
1989                        window,
1990                        GDK_OWNERSHIP_APPLICATION, FALSE,
1991                        GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
1992                        NULL, time) != GDK_GRAB_SUCCESS)
1993     return;
1994
1995   picker_cursor = make_picker_cursor (screen);
1996   grab_status = gdk_device_grab (pointer_device,
1997                                  window,
1998                                  GDK_OWNERSHIP_APPLICATION,
1999                                  FALSE,
2000                                  GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
2001                                  picker_cursor,
2002                                  time);
2003   g_object_unref (picker_cursor);
2004
2005   if (grab_status != GDK_GRAB_SUCCESS)
2006     {
2007       gdk_device_ungrab (keyb_device, time);
2008       return;
2009     }
2010
2011   gtk_device_grab_add (priv->dropper_grab_widget,
2012                        pointer_device,
2013                        TRUE);
2014
2015   priv->grab_time = time;
2016   priv->has_grab = TRUE;
2017   priv->keyboard_device = keyb_device;
2018   priv->pointer_device = pointer_device;
2019
2020   g_signal_connect (priv->dropper_grab_widget, "button-press-event",
2021                     G_CALLBACK (mouse_press), colorsel);
2022   g_signal_connect (priv->dropper_grab_widget, "key-press-event",
2023                     G_CALLBACK (key_press), colorsel);
2024 }
2025
2026 static void
2027 hex_changed (GtkWidget *hex_entry,
2028              gpointer   data)
2029 {
2030   GtkColorSelection *colorsel;
2031   GtkColorSelectionPrivate *priv;
2032   GdkRGBA color;
2033   gchar *text;
2034
2035   colorsel = GTK_COLOR_SELECTION (data);
2036   priv = colorsel->private_data;
2037
2038   if (priv->changing)
2039     return;
2040
2041   text = gtk_editable_get_chars (GTK_EDITABLE (priv->hex_entry), 0, -1);
2042   if (gdk_rgba_parse (&color, text))
2043     {
2044       priv->color[COLORSEL_RED]   = color.red;
2045       priv->color[COLORSEL_GREEN] = color.green;
2046       priv->color[COLORSEL_BLUE]  = color.blue;
2047       gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
2048                       priv->color[COLORSEL_GREEN],
2049                       priv->color[COLORSEL_BLUE],
2050                       &priv->color[COLORSEL_HUE],
2051                       &priv->color[COLORSEL_SATURATION],
2052                       &priv->color[COLORSEL_VALUE]);
2053       update_color (colorsel);
2054     }
2055   g_free (text);
2056 }
2057
2058 static gboolean
2059 hex_focus_out (GtkWidget     *hex_entry,
2060                GdkEventFocus *event,
2061                gpointer       data)
2062 {
2063   hex_changed (hex_entry, data);
2064
2065   return FALSE;
2066 }
2067
2068 static void
2069 hsv_changed (GtkWidget *hsv,
2070              gpointer   data)
2071 {
2072   GtkColorSelection *colorsel;
2073   GtkColorSelectionPrivate *priv;
2074
2075   colorsel = GTK_COLOR_SELECTION (data);
2076   priv = colorsel->private_data;
2077
2078   if (priv->changing)
2079     return;
2080
2081   gtk_hsv_get_color (GTK_HSV (hsv),
2082                      &priv->color[COLORSEL_HUE],
2083                      &priv->color[COLORSEL_SATURATION],
2084                      &priv->color[COLORSEL_VALUE]);
2085   gtk_hsv_to_rgb (priv->color[COLORSEL_HUE],
2086                   priv->color[COLORSEL_SATURATION],
2087                   priv->color[COLORSEL_VALUE],
2088                   &priv->color[COLORSEL_RED],
2089                   &priv->color[COLORSEL_GREEN],
2090                   &priv->color[COLORSEL_BLUE]);
2091   update_color (colorsel);
2092 }
2093
2094 static void
2095 adjustment_changed (GtkAdjustment *adjustment,
2096                     gpointer       data)
2097 {
2098   GtkColorSelection *colorsel;
2099   GtkColorSelectionPrivate *priv;
2100
2101   colorsel = GTK_COLOR_SELECTION (g_object_get_data (G_OBJECT (adjustment), "COLORSEL"));
2102   priv = colorsel->private_data;
2103
2104   if (priv->changing)
2105     return;
2106
2107   switch (GPOINTER_TO_INT (data))
2108     {
2109     case COLORSEL_SATURATION:
2110     case COLORSEL_VALUE:
2111       priv->color[GPOINTER_TO_INT (data)] = gtk_adjustment_get_value (adjustment) / 100;
2112       gtk_hsv_to_rgb (priv->color[COLORSEL_HUE],
2113                       priv->color[COLORSEL_SATURATION],
2114                       priv->color[COLORSEL_VALUE],
2115                       &priv->color[COLORSEL_RED],
2116                       &priv->color[COLORSEL_GREEN],
2117                       &priv->color[COLORSEL_BLUE]);
2118       break;
2119     case COLORSEL_HUE:
2120       priv->color[GPOINTER_TO_INT (data)] = gtk_adjustment_get_value (adjustment) / 360;
2121       gtk_hsv_to_rgb (priv->color[COLORSEL_HUE],
2122                       priv->color[COLORSEL_SATURATION],
2123                       priv->color[COLORSEL_VALUE],
2124                       &priv->color[COLORSEL_RED],
2125                       &priv->color[COLORSEL_GREEN],
2126                       &priv->color[COLORSEL_BLUE]);
2127       break;
2128     case COLORSEL_RED:
2129     case COLORSEL_GREEN:
2130     case COLORSEL_BLUE:
2131       priv->color[GPOINTER_TO_INT (data)] = gtk_adjustment_get_value (adjustment) / 255;
2132
2133       gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
2134                       priv->color[COLORSEL_GREEN],
2135                       priv->color[COLORSEL_BLUE],
2136                       &priv->color[COLORSEL_HUE],
2137                       &priv->color[COLORSEL_SATURATION],
2138                       &priv->color[COLORSEL_VALUE]);
2139       break;
2140     default:
2141       priv->color[GPOINTER_TO_INT (data)] = gtk_adjustment_get_value (adjustment) / 255;
2142       break;
2143     }
2144   update_color (colorsel);
2145 }
2146
2147 static void
2148 opacity_entry_changed (GtkWidget *opacity_entry,
2149                        gpointer   data)
2150 {
2151   GtkColorSelection *colorsel;
2152   GtkColorSelectionPrivate *priv;
2153   GtkAdjustment *adj;
2154   gchar *text;
2155
2156   colorsel = GTK_COLOR_SELECTION (data);
2157   priv = colorsel->private_data;
2158
2159   if (priv->changing)
2160     return;
2161
2162   text = gtk_editable_get_chars (GTK_EDITABLE (priv->opacity_entry), 0, -1);
2163   adj = gtk_range_get_adjustment (GTK_RANGE (priv->opacity_slider));
2164   gtk_adjustment_set_value (adj, g_strtod (text, NULL));
2165
2166   update_color (colorsel);
2167
2168   g_free (text);
2169 }
2170
2171 static void
2172 make_label_spinbutton (GtkColorSelection *colorsel,
2173                        GtkWidget        **spinbutton,
2174                        gchar             *text,
2175                        GtkWidget         *table,
2176                        gint               i,
2177                        gint               j,
2178                        gint               channel_type,
2179                        const gchar       *tooltip)
2180 {
2181   GtkWidget *label;
2182   GtkAdjustment *adjust;
2183
2184   if (channel_type == COLORSEL_HUE)
2185     {
2186       adjust = gtk_adjustment_new (0.0, 0.0, 360.0, 1.0, 1.0, 0.0);
2187     }
2188   else if (channel_type == COLORSEL_SATURATION ||
2189            channel_type == COLORSEL_VALUE)
2190     {
2191       adjust = gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 1.0, 0.0);
2192     }
2193   else
2194     {
2195       adjust = gtk_adjustment_new (0.0, 0.0, 255.0, 1.0, 1.0, 0.0);
2196     }
2197   g_object_set_data (G_OBJECT (adjust), I_("COLORSEL"), colorsel);
2198   *spinbutton = gtk_spin_button_new (adjust, 10.0, 0);
2199
2200   gtk_widget_set_tooltip_text (*spinbutton, tooltip);
2201
2202   g_signal_connect (adjust, "value-changed",
2203                     G_CALLBACK (adjustment_changed),
2204                     GINT_TO_POINTER (channel_type));
2205   label = gtk_label_new_with_mnemonic (text);
2206   gtk_label_set_mnemonic_widget (GTK_LABEL (label), *spinbutton);
2207
2208   gtk_widget_set_halign (label, GTK_ALIGN_START);
2209   gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
2210   gtk_grid_attach (GTK_GRID (table), label, i, j, 1, 1);
2211   gtk_grid_attach (GTK_GRID (table), *spinbutton, i+1, j, 1, 1);
2212 }
2213
2214 static void
2215 make_palette_frame (GtkColorSelection *colorsel,
2216                     GtkWidget         *table,
2217                     gint               i,
2218                     gint               j)
2219 {
2220   GtkWidget *frame;
2221   GtkColorSelectionPrivate *priv;
2222
2223   priv = colorsel->private_data;
2224   frame = gtk_frame_new (NULL);
2225   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
2226   priv->custom_palette[i][j] = palette_new (colorsel);
2227   gtk_widget_set_size_request (priv->custom_palette[i][j], CUSTOM_PALETTE_ENTRY_WIDTH, CUSTOM_PALETTE_ENTRY_HEIGHT);
2228   gtk_container_add (GTK_CONTAINER (frame), priv->custom_palette[i][j]);
2229   gtk_grid_attach (GTK_GRID (table), frame, i, j, 1, 1);
2230 }
2231
2232 /* Set the palette entry [x][y] to be the currently selected one. */
2233 static void
2234 set_selected_palette (GtkColorSelection *colorsel, int x, int y)
2235 {
2236   GtkColorSelectionPrivate *priv = colorsel->private_data;
2237
2238   gtk_widget_grab_focus (priv->custom_palette[x][y]);
2239 }
2240
2241 static double
2242 scale_round (double val, double factor)
2243 {
2244   val = floor (val * factor + 0.5);
2245   val = MAX (val, 0);
2246   val = MIN (val, factor);
2247   return val;
2248 }
2249
2250 static void
2251 update_color (GtkColorSelection *colorsel)
2252 {
2253   GtkColorSelectionPrivate *priv = colorsel->private_data;
2254   gchar entryval[12];
2255   gchar opacity_text[32];
2256   gchar *ptr;
2257
2258   priv->changing = TRUE;
2259   color_sample_update_samples (colorsel);
2260
2261   gtk_hsv_set_color (GTK_HSV (priv->triangle_colorsel),
2262                      priv->color[COLORSEL_HUE],
2263                      priv->color[COLORSEL_SATURATION],
2264                      priv->color[COLORSEL_VALUE]);
2265   gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2266                             (GTK_SPIN_BUTTON (priv->hue_spinbutton)),
2267                             scale_round (priv->color[COLORSEL_HUE], 360));
2268   gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2269                             (GTK_SPIN_BUTTON (priv->sat_spinbutton)),
2270                             scale_round (priv->color[COLORSEL_SATURATION], 100));
2271   gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2272                             (GTK_SPIN_BUTTON (priv->val_spinbutton)),
2273                             scale_round (priv->color[COLORSEL_VALUE], 100));
2274   gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2275                             (GTK_SPIN_BUTTON (priv->red_spinbutton)),
2276                             scale_round (priv->color[COLORSEL_RED], 255));
2277   gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2278                             (GTK_SPIN_BUTTON (priv->green_spinbutton)),
2279                             scale_round (priv->color[COLORSEL_GREEN], 255));
2280   gtk_adjustment_set_value (gtk_spin_button_get_adjustment
2281                             (GTK_SPIN_BUTTON (priv->blue_spinbutton)),
2282                             scale_round (priv->color[COLORSEL_BLUE], 255));
2283   gtk_adjustment_set_value (gtk_range_get_adjustment
2284                             (GTK_RANGE (priv->opacity_slider)),
2285                             scale_round (priv->color[COLORSEL_OPACITY], 255));
2286
2287   g_snprintf (opacity_text, 32, "%.0f", scale_round (priv->color[COLORSEL_OPACITY], 255));
2288   gtk_entry_set_text (GTK_ENTRY (priv->opacity_entry), opacity_text);
2289
2290   g_snprintf (entryval, 11, "#%2X%2X%2X",
2291               (guint) (scale_round (priv->color[COLORSEL_RED], 255)),
2292               (guint) (scale_round (priv->color[COLORSEL_GREEN], 255)),
2293               (guint) (scale_round (priv->color[COLORSEL_BLUE], 255)));
2294
2295   for (ptr = entryval; *ptr; ptr++)
2296     if (*ptr == ' ')
2297       *ptr = '0';
2298   gtk_entry_set_text (GTK_ENTRY (priv->hex_entry), entryval);
2299   priv->changing = FALSE;
2300
2301   g_object_ref (colorsel);
2302
2303   g_signal_emit (colorsel, color_selection_signals[COLOR_CHANGED], 0);
2304
2305   g_object_freeze_notify (G_OBJECT (colorsel));
2306   g_object_notify (G_OBJECT (colorsel), "current-color");
2307   g_object_notify (G_OBJECT (colorsel), "current-alpha");
2308   g_object_thaw_notify (G_OBJECT (colorsel));
2309
2310   g_object_unref (colorsel);
2311 }
2312
2313 static void
2314 update_palette (GtkColorSelection *colorsel)
2315 {
2316   GdkColor *current_colors;
2317   gint i, j;
2318
2319   current_colors = get_current_colors (colorsel);
2320
2321   for (i = 0; i < GTK_CUSTOM_PALETTE_HEIGHT; i++)
2322     {
2323       for (j = 0; j < GTK_CUSTOM_PALETTE_WIDTH; j++)
2324         {
2325           gint index;
2326
2327           index = i * GTK_CUSTOM_PALETTE_WIDTH + j;
2328
2329           gtk_color_selection_set_palette_color (colorsel,
2330                                                  index,
2331                                                  &current_colors[index]);
2332         }
2333     }
2334
2335   g_free (current_colors);
2336 }
2337
2338 static void
2339 palette_change_notify_instance (GObject    *object,
2340                                 GParamSpec *pspec,
2341                                 gpointer    data)
2342 {
2343   update_palette (GTK_COLOR_SELECTION (data));
2344 }
2345
2346 static void
2347 default_noscreen_change_palette_func (const GdkColor *colors,
2348                                       gint            n_colors)
2349 {
2350   default_change_palette_func (gdk_screen_get_default (), colors, n_colors);
2351 }
2352
2353 static void
2354 default_change_palette_func (GdkScreen      *screen,
2355                              const GdkColor *colors,
2356                              gint            n_colors)
2357 {
2358   gchar *str;
2359
2360   str = gtk_color_selection_palette_to_string (colors, n_colors);
2361
2362   gtk_settings_set_string_property (gtk_settings_get_for_screen (screen),
2363                                     "gtk-color-palette",
2364                                     str,
2365                                     "gtk_color_selection_palette_to_string");
2366
2367   g_free (str);
2368 }
2369
2370 /**
2371  * gtk_color_selection_new:
2372  *
2373  * Creates a new GtkColorSelection.
2374  *
2375  * Return value: a new #GtkColorSelection
2376  */
2377 GtkWidget *
2378 gtk_color_selection_new (void)
2379 {
2380   GtkColorSelection *colorsel;
2381   GtkColorSelectionPrivate *priv;
2382   gdouble color[4];
2383   color[0] = 1.0;
2384   color[1] = 1.0;
2385   color[2] = 1.0;
2386   color[3] = 1.0;
2387
2388   colorsel = g_object_new (GTK_TYPE_COLOR_SELECTION, NULL);
2389   priv = colorsel->private_data;
2390   set_color_internal (colorsel, color);
2391   gtk_color_selection_set_has_opacity_control (colorsel, TRUE);
2392
2393   /* We want to make sure that default_set is FALSE.
2394    * This way the user can still set it.
2395    */
2396   priv->default_set = FALSE;
2397   priv->default_alpha_set = FALSE;
2398
2399   return GTK_WIDGET (colorsel);
2400 }
2401
2402 /**
2403  * gtk_color_selection_get_has_opacity_control:
2404  * @colorsel: a #GtkColorSelection
2405  *
2406  * Determines whether the colorsel has an opacity control.
2407  *
2408  * Return value: %TRUE if the @colorsel has an opacity control,
2409  *     %FALSE if it does't
2410  */
2411 gboolean
2412 gtk_color_selection_get_has_opacity_control (GtkColorSelection *colorsel)
2413 {
2414   GtkColorSelectionPrivate *priv;
2415
2416   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
2417
2418   priv = colorsel->private_data;
2419
2420   return priv->has_opacity;
2421 }
2422
2423 /**
2424  * gtk_color_selection_set_has_opacity_control:
2425  * @colorsel: a #GtkColorSelection
2426  * @has_opacity: %TRUE if @colorsel can set the opacity, %FALSE otherwise
2427  *
2428  * Sets the @colorsel to use or not use opacity.
2429  */
2430 void
2431 gtk_color_selection_set_has_opacity_control (GtkColorSelection *colorsel,
2432                                              gboolean           has_opacity)
2433 {
2434   GtkColorSelectionPrivate *priv;
2435
2436   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2437
2438   priv = colorsel->private_data;
2439   has_opacity = has_opacity != FALSE;
2440
2441   if (priv->has_opacity != has_opacity)
2442     {
2443       priv->has_opacity = has_opacity;
2444       if (has_opacity)
2445         {
2446           gtk_widget_show (priv->opacity_slider);
2447           gtk_widget_show (priv->opacity_label);
2448           gtk_widget_show (priv->opacity_entry);
2449         }
2450       else
2451         {
2452           gtk_widget_hide (priv->opacity_slider);
2453           gtk_widget_hide (priv->opacity_label);
2454           gtk_widget_hide (priv->opacity_entry);
2455         }
2456       color_sample_update_samples (colorsel);
2457
2458       g_object_notify (G_OBJECT (colorsel), "has-opacity-control");
2459     }
2460 }
2461
2462 /**
2463  * gtk_color_selection_get_has_palette:
2464  * @colorsel: a #GtkColorSelection
2465  *
2466  * Determines whether the color selector has a color palette.
2467  *
2468  * Return value: %TRUE if the selector has a palette, %FALSE if it hasn't
2469  */
2470 gboolean
2471 gtk_color_selection_get_has_palette (GtkColorSelection *colorsel)
2472 {
2473   GtkColorSelectionPrivate *priv;
2474
2475   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
2476
2477   priv = colorsel->private_data;
2478
2479   return priv->has_palette;
2480 }
2481
2482 /**
2483  * gtk_color_selection_set_has_palette:
2484  * @colorsel: a #GtkColorSelection
2485  * @has_palette: %TRUE if palette is to be visible, %FALSE otherwise
2486  *
2487  * Shows and hides the palette based upon the value of @has_palette.
2488  */
2489 void
2490 gtk_color_selection_set_has_palette (GtkColorSelection *colorsel,
2491                                      gboolean           has_palette)
2492 {
2493   GtkColorSelectionPrivate *priv;
2494   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2495
2496   priv = colorsel->private_data;
2497   has_palette = has_palette != FALSE;
2498
2499   if (priv->has_palette != has_palette)
2500     {
2501       priv->has_palette = has_palette;
2502       if (has_palette)
2503         gtk_widget_show (priv->palette_frame);
2504       else
2505         gtk_widget_hide (priv->palette_frame);
2506
2507       update_tooltips (colorsel);
2508
2509       g_object_notify (G_OBJECT (colorsel), "has-palette");
2510     }
2511 }
2512
2513 /**
2514  * gtk_color_selection_set_current_color:
2515  * @colorsel: a #GtkColorSelection
2516  * @color: a #GdkColor to set the current color with
2517  *
2518  * Sets the current color to be @color.
2519  *
2520  * The first time this is called, it will also set
2521  * the original color to be @color too.
2522  *
2523  * Deprecated: 3.4: Use gtk_color_selection_set_current_rgba() instead.
2524  */
2525 void
2526 gtk_color_selection_set_current_color (GtkColorSelection *colorsel,
2527                                        const GdkColor    *color)
2528 {
2529   GtkColorSelectionPrivate *priv;
2530   gint i;
2531
2532   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2533   g_return_if_fail (color != NULL);
2534
2535   priv = colorsel->private_data;
2536   priv->changing = TRUE;
2537   priv->color[COLORSEL_RED] = SCALE (color->red);
2538   priv->color[COLORSEL_GREEN] = SCALE (color->green);
2539   priv->color[COLORSEL_BLUE] = SCALE (color->blue);
2540   gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
2541                   priv->color[COLORSEL_GREEN],
2542                   priv->color[COLORSEL_BLUE],
2543                   &priv->color[COLORSEL_HUE],
2544                   &priv->color[COLORSEL_SATURATION],
2545                   &priv->color[COLORSEL_VALUE]);
2546   if (priv->default_set == FALSE)
2547     {
2548       for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
2549         priv->old_color[i] = priv->color[i];
2550     }
2551   priv->default_set = TRUE;
2552   update_color (colorsel);
2553 }
2554
2555 /**
2556  * gtk_color_selection_set_current_alpha:
2557  * @colorsel: a #GtkColorSelection
2558  * @alpha: an integer between 0 and 65535
2559  *
2560  * Sets the current opacity to be @alpha.
2561  *
2562  * The first time this is called, it will also set
2563  * the original opacity to be @alpha too.
2564  */
2565 void
2566 gtk_color_selection_set_current_alpha (GtkColorSelection *colorsel,
2567                                        guint16            alpha)
2568 {
2569   GtkColorSelectionPrivate *priv;
2570   gint i;
2571
2572   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2573
2574   priv = colorsel->private_data;
2575   priv->changing = TRUE;
2576   priv->color[COLORSEL_OPACITY] = SCALE (alpha);
2577   if (priv->default_alpha_set == FALSE)
2578     {
2579       for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
2580         priv->old_color[i] = priv->color[i];
2581     }
2582   priv->default_alpha_set = TRUE;
2583   update_color (colorsel);
2584 }
2585
2586 /**
2587  * gtk_color_selection_get_current_color:
2588  * @colorsel: a #GtkColorSelection
2589  * @color: (out): a #GdkColor to fill in with the current color
2590  *
2591  * Sets @color to be the current color in the GtkColorSelection widget.
2592  *
2593  * Deprecated: 3.4: Use gtk_color_selection_get_current_rgba() instead.
2594  */
2595 void
2596 gtk_color_selection_get_current_color (GtkColorSelection *colorsel,
2597                                        GdkColor          *color)
2598 {
2599   GtkColorSelectionPrivate *priv;
2600
2601   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2602   g_return_if_fail (color != NULL);
2603
2604   priv = colorsel->private_data;
2605   color->red = UNSCALE (priv->color[COLORSEL_RED]);
2606   color->green = UNSCALE (priv->color[COLORSEL_GREEN]);
2607   color->blue = UNSCALE (priv->color[COLORSEL_BLUE]);
2608 }
2609
2610 /**
2611  * gtk_color_selection_get_current_alpha:
2612  * @colorsel: a #GtkColorSelection
2613  *
2614  * Returns the current alpha value.
2615  *
2616  * Return value: an integer between 0 and 65535
2617  */
2618 guint16
2619 gtk_color_selection_get_current_alpha (GtkColorSelection *colorsel)
2620 {
2621   GtkColorSelectionPrivate *priv;
2622
2623   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), 0);
2624
2625   priv = colorsel->private_data;
2626   return priv->has_opacity ? UNSCALE (priv->color[COLORSEL_OPACITY]) : 65535;
2627 }
2628
2629 /**
2630  * gtk_color_selection_set_previous_color:
2631  * @colorsel: a #GtkColorSelection
2632  * @color: a #GdkColor to set the previous color with
2633  *
2634  * Sets the 'previous' color to be @color.
2635  *
2636  * This function should be called with some hesitations,
2637  * as it might seem confusing to have that color change.
2638  * Calling gtk_color_selection_set_current_color() will also
2639  * set this color the first time it is called.
2640  *
2641  * Deprecated: 3.4: Use gtk_color_selection_set_previous_rgba() instead.
2642  */
2643 void
2644 gtk_color_selection_set_previous_color (GtkColorSelection *colorsel,
2645                                         const GdkColor    *color)
2646 {
2647   GtkColorSelectionPrivate *priv;
2648
2649   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2650   g_return_if_fail (color != NULL);
2651
2652   priv = colorsel->private_data;
2653   priv->changing = TRUE;
2654   priv->old_color[COLORSEL_RED] = SCALE (color->red);
2655   priv->old_color[COLORSEL_GREEN] = SCALE (color->green);
2656   priv->old_color[COLORSEL_BLUE] = SCALE (color->blue);
2657   gtk_rgb_to_hsv (priv->old_color[COLORSEL_RED],
2658                   priv->old_color[COLORSEL_GREEN],
2659                   priv->old_color[COLORSEL_BLUE],
2660                   &priv->old_color[COLORSEL_HUE],
2661                   &priv->old_color[COLORSEL_SATURATION],
2662                   &priv->old_color[COLORSEL_VALUE]);
2663   color_sample_update_samples (colorsel);
2664   priv->default_set = TRUE;
2665   priv->changing = FALSE;
2666 }
2667
2668 /**
2669  * gtk_color_selection_set_previous_alpha:
2670  * @colorsel: a #GtkColorSelection
2671  * @alpha: an integer between 0 and 65535
2672  *
2673  * Sets the 'previous' alpha to be @alpha.
2674  *
2675  * This function should be called with some hesitations,
2676  * as it might seem confusing to have that alpha change.
2677  */
2678 void
2679 gtk_color_selection_set_previous_alpha (GtkColorSelection *colorsel,
2680                                         guint16            alpha)
2681 {
2682   GtkColorSelectionPrivate *priv;
2683
2684   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2685
2686   priv = colorsel->private_data;
2687   priv->changing = TRUE;
2688   priv->old_color[COLORSEL_OPACITY] = SCALE (alpha);
2689   color_sample_update_samples (colorsel);
2690   priv->default_alpha_set = TRUE;
2691   priv->changing = FALSE;
2692 }
2693
2694
2695 /**
2696  * gtk_color_selection_get_previous_color:
2697  * @colorsel: a #GtkColorSelection
2698  * @color: (out): a #GdkColor to fill in with the original color value
2699  *
2700  * Fills @color in with the original color value.
2701  *
2702  * Deprecated: 3.4: Use gtk_color_selection_get_previous_rgba() instead.
2703  */
2704 void
2705 gtk_color_selection_get_previous_color (GtkColorSelection *colorsel,
2706                                         GdkColor           *color)
2707 {
2708   GtkColorSelectionPrivate *priv;
2709
2710   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2711   g_return_if_fail (color != NULL);
2712
2713   priv = colorsel->private_data;
2714   color->red = UNSCALE (priv->old_color[COLORSEL_RED]);
2715   color->green = UNSCALE (priv->old_color[COLORSEL_GREEN]);
2716   color->blue = UNSCALE (priv->old_color[COLORSEL_BLUE]);
2717 }
2718
2719 /**
2720  * gtk_color_selection_get_previous_alpha:
2721  * @colorsel: a #GtkColorSelection
2722  *
2723  * Returns the previous alpha value.
2724  *
2725  * Return value: an integer between 0 and 65535
2726  */
2727 guint16
2728 gtk_color_selection_get_previous_alpha (GtkColorSelection *colorsel)
2729 {
2730   GtkColorSelectionPrivate *priv;
2731
2732   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), 0);
2733
2734   priv = colorsel->private_data;
2735   return priv->has_opacity ? UNSCALE (priv->old_color[COLORSEL_OPACITY]) : 65535;
2736 }
2737
2738 /**
2739  * gtk_color_selection_set_current_rgba:
2740  * @colorsel: a #GtkColorSelection
2741  * @rgba: A #GdkRGBA to set the current color with
2742  *
2743  * Sets the current color to be @rgba.
2744  *
2745  * The first time this is called, it will also set
2746  * the original color to be @rgba too.
2747  *
2748  * Since: 3.0
2749  */
2750 void
2751 gtk_color_selection_set_current_rgba (GtkColorSelection *colorsel,
2752                                       const GdkRGBA     *rgba)
2753 {
2754   GtkColorSelectionPrivate *priv;
2755   gint i;
2756
2757   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2758   g_return_if_fail (rgba != NULL);
2759
2760   priv = colorsel->private_data;
2761   priv->changing = TRUE;
2762
2763   priv->color[COLORSEL_RED] = CLAMP (rgba->red, 0, 1);
2764   priv->color[COLORSEL_GREEN] = CLAMP (rgba->green, 0, 1);
2765   priv->color[COLORSEL_BLUE] = CLAMP (rgba->blue, 0, 1);
2766   priv->color[COLORSEL_OPACITY] = CLAMP (rgba->alpha, 0, 1);
2767
2768   gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
2769                   priv->color[COLORSEL_GREEN],
2770                   priv->color[COLORSEL_BLUE],
2771                   &priv->color[COLORSEL_HUE],
2772                   &priv->color[COLORSEL_SATURATION],
2773                   &priv->color[COLORSEL_VALUE]);
2774
2775   if (priv->default_set == FALSE)
2776     {
2777       for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
2778         priv->old_color[i] = priv->color[i];
2779     }
2780
2781   priv->default_set = TRUE;
2782   update_color (colorsel);
2783 }
2784
2785 /**
2786  * gtk_color_selection_get_current_rgba:
2787  * @colorsel: a #GtkColorSelection
2788  * @rgba: (out): a #GdkRGBA to fill in with the current color
2789  *
2790  * Sets @rgba to be the current color in the GtkColorSelection widget.
2791  *
2792  * Since: 3.0
2793  */
2794 void
2795 gtk_color_selection_get_current_rgba (GtkColorSelection *colorsel,
2796                                       GdkRGBA           *rgba)
2797 {
2798   GtkColorSelectionPrivate *priv;
2799
2800   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2801   g_return_if_fail (rgba != NULL);
2802
2803   priv = colorsel->private_data;
2804   rgba->red = priv->color[COLORSEL_RED];
2805   rgba->green = priv->color[COLORSEL_GREEN];
2806   rgba->blue = priv->color[COLORSEL_BLUE];
2807   rgba->alpha = (priv->has_opacity) ? priv->color[COLORSEL_OPACITY] : 1;
2808 }
2809
2810 /**
2811  * gtk_color_selection_set_previous_rgba:
2812  * @colorsel: a #GtkColorSelection
2813  * @rgba: a #GdkRGBA to set the previous color with
2814  *
2815  * Sets the 'previous' color to be @rgba.
2816  *
2817  * This function should be called with some hesitations,
2818  * as it might seem confusing to have that color change.
2819  * Calling gtk_color_selection_set_current_rgba() will also
2820  * set this color the first time it is called.
2821  *
2822  * Since: 3.0
2823  */
2824 void
2825 gtk_color_selection_set_previous_rgba (GtkColorSelection *colorsel,
2826                                        const GdkRGBA     *rgba)
2827 {
2828   GtkColorSelectionPrivate *priv;
2829
2830   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2831   g_return_if_fail (rgba != NULL);
2832
2833   priv = colorsel->private_data;
2834   priv->changing = TRUE;
2835
2836   priv->old_color[COLORSEL_RED] = CLAMP (rgba->red, 0, 1);
2837   priv->old_color[COLORSEL_GREEN] = CLAMP (rgba->green, 0, 1);
2838   priv->old_color[COLORSEL_BLUE] = CLAMP (rgba->blue, 0, 1);
2839   priv->old_color[COLORSEL_OPACITY] = CLAMP (rgba->alpha, 0, 1);
2840
2841   gtk_rgb_to_hsv (priv->old_color[COLORSEL_RED],
2842                   priv->old_color[COLORSEL_GREEN],
2843                   priv->old_color[COLORSEL_BLUE],
2844                   &priv->old_color[COLORSEL_HUE],
2845                   &priv->old_color[COLORSEL_SATURATION],
2846                   &priv->old_color[COLORSEL_VALUE]);
2847
2848   color_sample_update_samples (colorsel);
2849   priv->default_set = TRUE;
2850   priv->changing = FALSE;
2851 }
2852
2853 /**
2854  * gtk_color_selection_get_previous_rgba:
2855  * @colorsel: a #GtkColorSelection
2856  * @rgba: (out): a #GdkRGBA to fill in with the original color value
2857  *
2858  * Fills @rgba in with the original color value.
2859  *
2860  * Since: 3.0
2861  */
2862 void
2863 gtk_color_selection_get_previous_rgba (GtkColorSelection *colorsel,
2864                                        GdkRGBA           *rgba)
2865 {
2866   GtkColorSelectionPrivate *priv;
2867
2868   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2869   g_return_if_fail (rgba != NULL);
2870
2871   priv = colorsel->private_data;
2872   rgba->red = priv->old_color[COLORSEL_RED];
2873   rgba->green = priv->old_color[COLORSEL_GREEN];
2874   rgba->blue = priv->old_color[COLORSEL_BLUE];
2875   rgba->alpha = (priv->has_opacity) ? priv->old_color[COLORSEL_OPACITY] : 1;
2876 }
2877
2878 /**
2879  * gtk_color_selection_set_palette_color:
2880  * @colorsel: a #GtkColorSelection
2881  * @index: the color index of the palette
2882  * @color: A #GdkColor to set the palette with
2883  *
2884  * Sets the palette located at @index to have @color as its color.
2885  */
2886 static void
2887 gtk_color_selection_set_palette_color (GtkColorSelection *colorsel,
2888                                        gint               index,
2889                                        GdkColor          *color)
2890 {
2891   GtkColorSelectionPrivate *priv;
2892   gint x, y;
2893   gdouble col[3];
2894
2895   g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
2896   g_return_if_fail (index >= 0  && index < GTK_CUSTOM_PALETTE_WIDTH*GTK_CUSTOM_PALETTE_HEIGHT);
2897
2898   x = index % GTK_CUSTOM_PALETTE_WIDTH;
2899   y = index / GTK_CUSTOM_PALETTE_WIDTH;
2900
2901   priv = colorsel->private_data;
2902   col[0] = SCALE (color->red);
2903   col[1] = SCALE (color->green);
2904   col[2] = SCALE (color->blue);
2905
2906   palette_set_color (priv->custom_palette[x][y], colorsel, col);
2907 }
2908
2909 /**
2910  * gtk_color_selection_is_adjusting:
2911  * @colorsel: a #GtkColorSelection
2912  *
2913  * Gets the current state of the @colorsel.
2914  *
2915  * Return value: %TRUE if the user is currently dragging
2916  *     a color around, and %FALSE if the selection has stopped
2917  */
2918 gboolean
2919 gtk_color_selection_is_adjusting (GtkColorSelection *colorsel)
2920 {
2921   GtkColorSelectionPrivate *priv;
2922
2923   g_return_val_if_fail (GTK_IS_COLOR_SELECTION (colorsel), FALSE);
2924
2925   priv = colorsel->private_data;
2926
2927   return (gtk_hsv_is_adjusting (GTK_HSV (priv->triangle_colorsel)));
2928 }
2929
2930
2931 /**
2932  * gtk_color_selection_palette_from_string:
2933  * @str: a string encoding a color palette
2934  * @colors: (out) (array length=n_colors): return location for
2935  *     allocated array of #GdkColor
2936  * @n_colors: return location for length of array
2937  *
2938  * Parses a color palette string; the string is a colon-separated
2939  * list of color names readable by gdk_color_parse().
2940  *
2941  * Return value: %TRUE if a palette was successfully parsed
2942  */
2943 gboolean
2944 gtk_color_selection_palette_from_string (const gchar  *str,
2945                                          GdkColor    **colors,
2946                                          gint         *n_colors)
2947 {
2948   GdkColor *retval;
2949   gint count;
2950   gchar *p;
2951   gchar *start;
2952   gchar *copy;
2953
2954   count = 0;
2955   retval = NULL;
2956   copy = g_strdup (str);
2957
2958   start = copy;
2959   p = copy;
2960   while (TRUE)
2961     {
2962       if (*p == ':' || *p == '\0')
2963         {
2964           gboolean done = TRUE;
2965
2966           if (start == p)
2967             {
2968               goto failed; /* empty entry */
2969             }
2970
2971           if (*p)
2972             {
2973               *p = '\0';
2974               done = FALSE;
2975             }
2976
2977           retval = g_renew (GdkColor, retval, count + 1);
2978           if (!gdk_color_parse (start, retval + count))
2979             {
2980               goto failed;
2981             }
2982
2983           ++count;
2984
2985           if (done)
2986             break;
2987           else
2988             start = p + 1;
2989         }
2990
2991       ++p;
2992     }
2993
2994   g_free (copy);
2995
2996   if (colors)
2997     *colors = retval;
2998   else
2999     g_free (retval);
3000
3001   if (n_colors)
3002     *n_colors = count;
3003
3004   return TRUE;
3005
3006  failed:
3007   g_free (copy);
3008   g_free (retval);
3009
3010   if (colors)
3011     *colors = NULL;
3012   if (n_colors)
3013     *n_colors = 0;
3014
3015   return FALSE;
3016 }
3017
3018 /**
3019  * gtk_color_selection_palette_to_string:
3020  * @colors: (array length=n_colors): an array of colors
3021  * @n_colors: length of the array
3022  *
3023  * Encodes a palette as a string, useful for persistent storage.
3024  *
3025  * Return value: allocated string encoding the palette
3026  */
3027 gchar*
3028 gtk_color_selection_palette_to_string (const GdkColor *colors,
3029                                        gint            n_colors)
3030 {
3031   gint i;
3032   gchar **strs = NULL;
3033   gchar *retval;
3034
3035   if (n_colors == 0)
3036     return g_strdup ("");
3037
3038   strs = g_new0 (gchar*, n_colors + 1);
3039
3040   i = 0;
3041   while (i < n_colors)
3042     {
3043       gchar *ptr;
3044
3045       strs[i] =
3046         g_strdup_printf ("#%2X%2X%2X",
3047                          colors[i].red / 256,
3048                          colors[i].green / 256,
3049                          colors[i].blue / 256);
3050
3051       for (ptr = strs[i]; *ptr; ptr++)
3052         if (*ptr == ' ')
3053           *ptr = '0';
3054
3055       ++i;
3056     }
3057
3058   retval = g_strjoinv (":", strs);
3059
3060   g_strfreev (strs);
3061
3062   return retval;
3063 }
3064
3065 /**
3066  * gtk_color_selection_set_change_palette_with_screen_hook: (skip)
3067  * @func: a function to call when the custom palette needs saving
3068  *
3069  * Installs a global function to be called whenever the user
3070  * tries to modify the palette in a color selection.
3071  *
3072  * This function should save the new palette contents, and update
3073  * the #GtkSettings:gtk-color-palette GtkSettings property so all
3074  * GtkColorSelection widgets will be modified.
3075  *
3076  * Return value: the previous change palette hook (that was replaced)
3077  *
3078  * Since: 2.2
3079  */
3080 GtkColorSelectionChangePaletteWithScreenFunc
3081 gtk_color_selection_set_change_palette_with_screen_hook (GtkColorSelectionChangePaletteWithScreenFunc func)
3082 {
3083   GtkColorSelectionChangePaletteWithScreenFunc old;
3084
3085   old = change_palette_hook;
3086
3087   change_palette_hook = func;
3088
3089   return old;
3090 }
3091
3092 static void
3093 make_control_relations (AtkObject *atk_obj,
3094                         GtkWidget *widget)
3095 {
3096   AtkObject *obj;
3097
3098   obj = gtk_widget_get_accessible (widget);
3099   atk_object_add_relationship (atk_obj, ATK_RELATION_CONTROLLED_BY, obj);
3100   atk_object_add_relationship (obj, ATK_RELATION_CONTROLLER_FOR, atk_obj);
3101 }
3102
3103 static void
3104 make_all_relations (AtkObject                *atk_obj,
3105                     GtkColorSelectionPrivate *priv)
3106 {
3107   make_control_relations (atk_obj, priv->hue_spinbutton);
3108   make_control_relations (atk_obj, priv->sat_spinbutton);
3109   make_control_relations (atk_obj, priv->val_spinbutton);
3110   make_control_relations (atk_obj, priv->red_spinbutton);
3111   make_control_relations (atk_obj, priv->green_spinbutton);
3112   make_control_relations (atk_obj, priv->blue_spinbutton);
3113 }