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