]> Pileus Git - ~andy/gtk/blob - gtk/gtkcolorswatch.c
color-swatch: add a color-light/color-dark style class for intensity
[~andy/gtk] / gtk / gtkcolorswatch.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2012 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include "gtkcolorswatch.h"
23
24 #include "gtkroundedboxprivate.h"
25 #include "gtkdnd.h"
26 #include "gtkicontheme.h"
27 #include "gtkmain.h"
28 #include "gtkmenu.h"
29 #include "gtkmenuitem.h"
30 #include "gtkmenushell.h"
31 #include "gtkprivate.h"
32 #include "gtkintl.h"
33
34
35 struct _GtkColorSwatchPrivate
36 {
37   GdkRGBA color;
38   gdouble radius[4];
39   gchar *icon;
40   guint    selected         : 1;
41   guint    has_color        : 1;
42   guint    can_drop         : 1;
43   guint    contains_pointer : 1;
44   guint    use_alpha        : 1;
45 };
46
47 enum
48 {
49   PROP_ZERO,
50   PROP_RGBA,
51   PROP_SELECTED
52 };
53
54 enum
55 {
56   ACTIVATE,
57   CUSTOMIZE,
58   LAST_SIGNAL
59 };
60
61 static guint signals[LAST_SIGNAL];
62
63 G_DEFINE_TYPE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_DRAWING_AREA)
64
65 static void
66 gtk_color_swatch_init (GtkColorSwatch *swatch)
67 {
68   swatch->priv = G_TYPE_INSTANCE_GET_PRIVATE (swatch,
69                                               GTK_TYPE_COLOR_SWATCH,
70                                               GtkColorSwatchPrivate);
71
72   gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
73   gtk_widget_set_events (GTK_WIDGET (swatch), GDK_BUTTON_PRESS_MASK
74                                               | GDK_BUTTON_RELEASE_MASK
75                                               | GDK_EXPOSURE_MASK
76                                               | GDK_ENTER_NOTIFY_MASK
77                                               | GDK_LEAVE_NOTIFY_MASK);
78   swatch->priv->use_alpha = TRUE;
79 }
80
81 #define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
82
83 static cairo_pattern_t *
84 get_checkered_pattern (void)
85 {
86   /* need to respect pixman's stride being a multiple of 4 */
87   static unsigned char data[8] = { 0xFF, 0x00, 0x00, 0x00,
88                                    0x00, 0xFF, 0x00, 0x00 };
89   static cairo_surface_t *checkered = NULL;
90   cairo_pattern_t *pattern;
91
92   if (checkered == NULL)
93     checkered = cairo_image_surface_create_for_data (data,
94                                                      CAIRO_FORMAT_A8,
95                                                      2, 2, 4);
96
97   pattern = cairo_pattern_create_for_surface (checkered);
98   cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
99   cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
100
101   return pattern;
102 }
103
104 static gboolean
105 swatch_draw (GtkWidget *widget,
106              cairo_t   *cr)
107 {
108   GtkColorSwatch *swatch = (GtkColorSwatch*)widget;
109   GtkRoundedBox box;
110   gint i;
111   gdouble width, height;
112   GtkStyleContext *context;
113   GtkStateFlags state;
114   GdkRGBA bg;
115
116   context = gtk_widget_get_style_context (widget);
117   state = gtk_widget_get_state_flags (widget);
118   width = gtk_widget_get_allocated_width (widget);
119   height = gtk_widget_get_allocated_height (widget);
120
121   gtk_style_context_save (context);
122   cairo_save (cr);
123
124   gtk_style_context_set_state (context, state);
125
126   _gtk_rounded_box_init_rect (&box, 0, 0, width, height);
127   for (i = 0; i < 4; i++)
128     box.corner[i].horizontal = box.corner[i].vertical = swatch->priv->radius[i];
129
130   _gtk_rounded_box_path (&box, cr);
131
132   cairo_clip_preserve (cr);
133
134   if (swatch->priv->has_color)
135     {
136       cairo_pattern_t *pattern;
137       cairo_matrix_t matrix;
138
139       if (swatch->priv->use_alpha)
140         {
141           cairo_set_source_rgb (cr, 0.33, 0.33, 0.33);
142           cairo_fill_preserve (cr);
143           cairo_set_source_rgb (cr, 0.66, 0.66, 0.66);
144
145           pattern = get_checkered_pattern ();
146           cairo_matrix_init_scale (&matrix, 0.125, 0.125);
147           cairo_pattern_set_matrix (pattern, &matrix);
148           cairo_mask (cr, pattern);
149           cairo_pattern_destroy (pattern);
150
151           gdk_cairo_set_source_rgba (cr, &swatch->priv->color);
152         }
153       else
154         {
155           cairo_set_source_rgb (cr,
156                                 swatch->priv->color.red,
157                                 swatch->priv->color.green,
158                                 swatch->priv->color.blue);
159         }
160       cairo_fill_preserve (cr);
161     }
162
163   cairo_set_source_rgb (cr, 0.4, 0.4, 0.4);
164   cairo_set_line_width (cr, 1);
165   cairo_stroke (cr);
166
167   if (gtk_widget_has_visible_focus (widget))
168     {
169       cairo_set_line_width (cr, 2);
170       if (swatch->priv->has_color && INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) < 0.5)
171         cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
172       else
173         cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
174       _gtk_rounded_box_shrink (&box, 3, 3, 3, 3);
175       _gtk_rounded_box_path (&box, cr);
176       cairo_stroke (cr);
177     }
178
179   if (swatch->priv->icon)
180     {
181       GdkPixbuf *pixbuf;
182       GtkIconTheme *theme;
183       theme = gtk_icon_theme_get_default ();
184       pixbuf = gtk_icon_theme_load_icon (theme, "list-add-symbolic", 16,
185                                          GTK_ICON_LOOKUP_GENERIC_FALLBACK
186                                          | GTK_ICON_LOOKUP_USE_BUILTIN,
187                                          NULL);
188
189       gtk_render_icon (context, cr, pixbuf,
190                        (width - gdk_pixbuf_get_width (pixbuf)) / 2,
191                        (height - gdk_pixbuf_get_height (pixbuf)) / 2);
192       g_object_unref (pixbuf);
193     }
194   else  if (swatch->priv->selected)
195     {
196       gtk_style_context_get_background_color (context, state, &bg);
197       cairo_new_sub_path (cr);
198       cairo_arc (cr, width / 2, height / 2, 10, 0, 2 * G_PI);
199       cairo_close_path (cr);
200       gdk_cairo_set_source_rgba (cr, &bg);
201       cairo_fill_preserve (cr);
202       if (INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) > 0.5)
203         cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
204       else
205         cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
206       cairo_set_line_width (cr, 2);
207       cairo_stroke (cr);
208       gtk_style_context_set_state (context, state | GTK_STATE_FLAG_ACTIVE);
209       gtk_render_check (context, cr, width / 2 - 5, height / 2 - 5, 10, 10);
210     }
211
212   cairo_restore (cr);
213   gtk_style_context_restore (context);
214
215   return FALSE;
216 }
217
218 static void
219 drag_set_color_icon (GdkDragContext *context,
220                      const GdkRGBA  *color)
221 {
222   cairo_surface_t *surface;
223   cairo_t *cr;
224
225   surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 48, 32);
226   cr = cairo_create (surface);
227   gdk_cairo_set_source_rgba (cr, color);
228   cairo_paint (cr);
229
230   cairo_surface_set_device_offset (surface, -4, -4);
231   gtk_drag_set_icon_surface (context, surface);
232
233   cairo_destroy (cr);
234   cairo_surface_destroy (surface);
235 }
236
237 static void
238 swatch_drag_begin (GtkWidget      *widget,
239                    GdkDragContext *context)
240 {
241   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
242   GdkRGBA color;
243
244   gtk_color_swatch_get_rgba (swatch, &color);
245   drag_set_color_icon (context, &color);
246 }
247
248 static void
249 swatch_drag_data_get (GtkWidget        *widget,
250                       GdkDragContext   *context,
251                       GtkSelectionData *selection_data,
252                       guint             info,
253                       guint             time)
254 {
255   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
256   guint16 vals[4];
257   GdkRGBA color;
258
259   gtk_color_swatch_get_rgba (swatch, &color);
260
261   vals[0] = color.red * 0xffff;
262   vals[1] = color.green * 0xffff;
263   vals[2] = color.blue * 0xffff;
264   vals[3] = color.alpha * 0xffff;
265
266   gtk_selection_data_set (selection_data,
267                           gdk_atom_intern_static_string ("application/x-color"),
268                           16, (guchar *)vals, 8);
269 }
270
271 static void
272 swatch_drag_data_received (GtkWidget        *widget,
273                            GdkDragContext   *context,
274                            gint              x,
275                            gint              y,
276                            GtkSelectionData *selection_data,
277                            guint             info,
278                            guint             time)
279 {
280   gint length;
281   guint16 *vals;
282   GdkRGBA color;
283
284   length = gtk_selection_data_get_length (selection_data);
285
286   if (length < 0)
287     return;
288
289   /* We accept drops with the wrong format, since the KDE color
290    * chooser incorrectly drops application/x-color with format 8.
291    */
292   if (length != 8)
293     {
294       g_warning ("Received invalid color data\n");
295       return;
296     }
297
298   vals = (guint16 *) gtk_selection_data_get_data (selection_data);
299
300   color.red   = (gdouble)vals[0] / 0xffff;
301   color.green = (gdouble)vals[1] / 0xffff;
302   color.blue  = (gdouble)vals[2] / 0xffff;
303   color.alpha = (gdouble)vals[3] / 0xffff;
304
305   gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color);
306 }
307
308 static void
309 swatch_get_preferred_width (GtkWidget *widget,
310                             gint      *min,
311                             gint      *nat)
312 {
313   *min = *nat = 48;
314 }
315
316 static void
317 swatch_get_preferred_height (GtkWidget *widget,
318                              gint      *min,
319                              gint      *nat)
320 {
321   *min = *nat = 32;
322 }
323
324 static gboolean
325 swatch_key_press (GtkWidget   *widget,
326                   GdkEventKey *event)
327 {
328   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
329
330   if (event->keyval == GDK_KEY_space ||
331       event->keyval == GDK_KEY_Return ||
332       event->keyval == GDK_KEY_ISO_Enter||
333       event->keyval == GDK_KEY_KP_Enter ||
334       event->keyval == GDK_KEY_KP_Space)
335     {
336       if (swatch->priv->has_color && !swatch->priv->selected)
337         gtk_color_swatch_set_selected (swatch, TRUE);
338       else
339         g_signal_emit (swatch, signals[ACTIVATE], 0);
340       return TRUE;
341     }
342
343   if (GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->key_press_event (widget, event))
344     return TRUE;
345
346   return FALSE;
347 }
348
349 static gboolean
350 swatch_enter_notify (GtkWidget        *widget,
351                      GdkEventCrossing *event)
352 {
353   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
354   swatch->priv->contains_pointer = TRUE;
355   return FALSE;
356 }
357
358 static gboolean
359 swatch_leave_notify (GtkWidget        *widget,
360                      GdkEventCrossing *event)
361 {
362   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
363   swatch->priv->contains_pointer = FALSE;
364   return FALSE;
365 }
366
367 static void
368 emit_customize (GtkColorSwatch *swatch)
369 {
370   g_signal_emit (swatch, signals[CUSTOMIZE], 0);
371 }
372
373 static void
374 popup_position_func (GtkMenu   *menu,
375                      gint      *x,
376                      gint      *y,
377                      gboolean  *push_in,
378                      gpointer   user_data)
379 {
380   GtkWidget *widget;
381   GtkRequisition req;
382   gint root_x, root_y;
383   GdkScreen *screen;
384   GdkWindow *window;
385   GdkRectangle monitor;
386   gint monitor_num;
387
388   widget = GTK_WIDGET (user_data);
389   g_return_if_fail (gtk_widget_get_realized (widget));
390   window = gtk_widget_get_window (widget);
391
392   screen = gtk_widget_get_screen (widget);
393   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
394   if (monitor_num < 0)
395     monitor_num = 0;
396   gtk_menu_set_monitor (menu, monitor_num);
397
398   gdk_window_get_origin (window, &root_x, &root_y);
399   gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
400
401   /* Put corner of menu centered on swatch */
402   *x = root_x + gtk_widget_get_allocated_width (widget) / 2;
403   *y = root_y + gtk_widget_get_allocated_height (widget) / 2;
404
405   /* Ensure sanity */
406   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
407   *x = CLAMP (*x, monitor.x, MAX (monitor.x, monitor.width - req.width));
408   *y = CLAMP (*y, monitor.y, MAX (monitor.y, monitor.height - req.height));
409 }
410
411 static void
412 do_popup (GtkWidget      *swatch,
413           GdkEventButton *event)
414 {
415   GtkWidget *menu;
416   GtkWidget *item;
417
418   menu = gtk_menu_new ();
419   item = gtk_menu_item_new_with_mnemonic (_("_Customize"));
420   gtk_menu_attach_to_widget (GTK_MENU (menu), swatch, NULL);
421
422   g_signal_connect_swapped (item, "activate",
423                             G_CALLBACK (emit_customize), swatch);
424
425   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
426
427   gtk_widget_show_all (item);
428
429   if (event)
430     gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
431                     NULL, NULL, event->button, event->time);
432   else
433     gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
434                     popup_position_func, swatch,
435                     0, gtk_get_current_event_time ());
436 }
437
438 static gboolean
439 swatch_button_press (GtkWidget      *widget,
440                      GdkEventButton *event)
441 {
442   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
443
444   gtk_widget_grab_focus (widget);
445
446   if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
447       swatch->priv->has_color)
448     {
449       do_popup (widget, event);
450       return TRUE;
451     }
452   else if (event->type == GDK_2BUTTON_PRESS &&
453            event->button == GDK_BUTTON_PRIMARY)
454     {
455       g_signal_emit (swatch, signals[ACTIVATE], 0);
456       return TRUE;
457     }
458
459   return FALSE;
460 }
461
462 static gboolean
463 swatch_button_release (GtkWidget      *widget,
464                        GdkEventButton *event)
465 {
466   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
467
468   if (event->button == GDK_BUTTON_PRIMARY &&
469       swatch->priv->contains_pointer)
470     {
471       if (!swatch->priv->has_color)
472         {
473           g_signal_emit (swatch, signals[ACTIVATE], 0);
474           return TRUE;
475         }
476       else if (!swatch->priv->selected)
477         {
478           gtk_color_swatch_set_selected (swatch, TRUE);
479           return TRUE;
480         }
481     }
482
483   return FALSE;
484 }
485
486 static gboolean
487 swatch_popup_menu (GtkWidget *swatch)
488 {
489   do_popup (swatch, NULL);
490   return TRUE;
491 }
492
493 /* GObject implementation {{{1 */
494
495 static void
496 swatch_get_property (GObject    *object,
497                      guint       prop_id,
498                      GValue     *value,
499                      GParamSpec *pspec)
500 {
501   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
502   GdkRGBA color;
503
504   switch (prop_id)
505     {
506     case PROP_RGBA:
507       gtk_color_swatch_get_rgba (swatch, &color);
508       g_value_set_boxed (value, &color);
509       break;
510     case PROP_SELECTED:
511       g_value_set_boolean (value, swatch->priv->selected);
512       break;
513     default:
514       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
515       break;
516     }
517 }
518
519 static void
520 swatch_set_property (GObject      *object,
521                      guint         prop_id,
522                      const GValue *value,
523                      GParamSpec   *pspec)
524 {
525   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
526
527   switch (prop_id)
528     {
529     case PROP_RGBA:
530       gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
531       break;
532     case PROP_SELECTED:
533       gtk_color_swatch_set_selected (swatch, g_value_get_boolean (value));
534       break;
535     default:
536       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
537       break;
538     }
539 }
540
541 static void
542 swatch_finalize (GObject *object)
543 {
544   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
545
546   g_free (swatch->priv->icon);
547
548   G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
549 }
550
551 static void
552 gtk_color_swatch_class_init (GtkColorSwatchClass *class)
553 {
554   GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
555   GObjectClass *object_class = (GObjectClass *)class;
556
557   object_class->get_property = swatch_get_property;
558   object_class->set_property = swatch_set_property;
559   object_class->finalize = swatch_finalize;
560
561   widget_class->get_preferred_width = swatch_get_preferred_width;
562   widget_class->get_preferred_height = swatch_get_preferred_height;
563   widget_class->draw = swatch_draw;
564   widget_class->drag_begin = swatch_drag_begin;
565   widget_class->drag_data_get = swatch_drag_data_get;
566   widget_class->drag_data_received = swatch_drag_data_received;
567   widget_class->key_press_event = swatch_key_press;
568   widget_class->popup_menu = swatch_popup_menu;
569   widget_class->button_press_event = swatch_button_press;
570   widget_class->button_release_event = swatch_button_release;
571   widget_class->enter_notify_event = swatch_enter_notify;
572   widget_class->leave_notify_event = swatch_leave_notify;
573
574   signals[ACTIVATE] =
575     g_signal_new ("activate",
576                   GTK_TYPE_COLOR_SWATCH,
577                   G_SIGNAL_RUN_FIRST,
578                   G_STRUCT_OFFSET (GtkColorSwatchClass, activate),
579                   NULL, NULL, NULL, G_TYPE_NONE, 0);
580
581   signals[CUSTOMIZE] =
582     g_signal_new ("customize",
583                   GTK_TYPE_COLOR_SWATCH,
584                   G_SIGNAL_RUN_FIRST,
585                   G_STRUCT_OFFSET (GtkColorSwatchClass, customize),
586                   NULL, NULL, NULL, G_TYPE_NONE, 0);
587
588   g_object_class_install_property (object_class, PROP_RGBA,
589       g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"),
590                           GDK_TYPE_RGBA, GTK_PARAM_READWRITE));
591
592   g_object_class_install_property (object_class, PROP_SELECTED,
593       g_param_spec_boolean ("selected", P_("Selected"), P_("Selected"),
594                             FALSE, GTK_PARAM_READWRITE));
595
596   g_type_class_add_private (object_class, sizeof (GtkColorSwatchPrivate));
597 }
598
599 /* Public API {{{1 */
600
601 GtkWidget *
602 gtk_color_swatch_new (void)
603 {
604   return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SWATCH, NULL);
605 }
606
607 static const GtkTargetEntry dnd_targets[] = {
608   { "application/x-color", 0 }
609 };
610
611 void
612 gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
613                            const GdkRGBA  *color)
614 {
615   GtkStyleContext *context;
616
617   context = gtk_widget_get_style_context (GTK_WIDGET (swatch));
618
619   if (!swatch->priv->has_color)
620     {
621       gtk_drag_source_set (GTK_WIDGET (swatch),
622                            GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
623                            dnd_targets, G_N_ELEMENTS (dnd_targets),
624                            GDK_ACTION_COPY | GDK_ACTION_MOVE);
625     }
626   else
627     {
628       gtk_style_context_remove_class (context, "color-light");
629       gtk_style_context_remove_class (context, "color-dark");
630     }
631
632   swatch->priv->has_color = TRUE;
633   swatch->priv->color = *color;
634
635   if (INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) > 0.5)
636     gtk_style_context_add_class (context, "color-light");
637   else
638     gtk_style_context_add_class (context, "color-dark");
639
640   gtk_widget_queue_draw (GTK_WIDGET (swatch));
641   g_object_notify (G_OBJECT (swatch), "rgba");
642 }
643
644 gboolean
645 gtk_color_swatch_get_rgba (GtkColorSwatch *swatch,
646                            GdkRGBA        *color)
647 {
648   if (swatch->priv->has_color)
649     {
650       color->red = swatch->priv->color.red;
651       color->green = swatch->priv->color.green;
652       color->blue = swatch->priv->color.blue;
653       color->alpha = swatch->priv->color.alpha;
654       return TRUE;
655     }
656   else
657     {
658       color->red = 1.0;
659       color->green = 1.0;
660       color->blue = 1.0;
661       color->alpha = 1.0;
662       return FALSE;
663     }
664 }
665
666 void
667 gtk_color_swatch_set_corner_radii (GtkColorSwatch *swatch,
668                                    gdouble         top_left,
669                                    gdouble         top_right,
670                                    gdouble         bottom_right,
671                                    gdouble         bottom_left)
672 {
673   swatch->priv->radius[0] = top_left;
674   swatch->priv->radius[1] = top_right;
675   swatch->priv->radius[2] = bottom_right;
676   swatch->priv->radius[3] = bottom_left;
677
678   gtk_widget_queue_draw (GTK_WIDGET (swatch));
679 }
680
681 void
682 gtk_color_swatch_set_selected (GtkColorSwatch *swatch,
683                                gboolean        selected)
684 {
685   if (swatch->priv->selected != selected)
686     {
687       swatch->priv->selected = selected;
688       gtk_widget_queue_draw (GTK_WIDGET (swatch));
689       g_object_notify (G_OBJECT (swatch), "selected");
690     }
691 }
692
693 void
694 gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
695                            const gchar    *icon)
696 {
697   swatch->priv->icon = g_strdup (icon);
698   gtk_widget_queue_draw (GTK_WIDGET (swatch));
699 }
700
701 void
702 gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
703                                gboolean        can_drop)
704 {
705   if (!swatch->priv->can_drop)
706     gtk_drag_dest_set (GTK_WIDGET (swatch),
707                        GTK_DEST_DEFAULT_HIGHLIGHT |
708                        GTK_DEST_DEFAULT_MOTION |
709                        GTK_DEST_DEFAULT_DROP,
710                        dnd_targets, G_N_ELEMENTS (dnd_targets),
711                        GDK_ACTION_COPY);
712
713   swatch->priv->can_drop = can_drop;
714 }
715
716 void
717 gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
718                                 gboolean        use_alpha)
719 {
720   swatch->priv->use_alpha = use_alpha;
721   gtk_widget_queue_draw (GTK_WIDGET (swatch));
722 }
723
724 /* vim:set foldmethod=marker: */