]> Pileus Git - ~andy/gtk/blob - gtk/gtkcolorswatch.c
color-swatch: render a background if the swatch doesn't have a color
[~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_WIDGET)
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   else
149     _gtk_theming_background_render (&background, cr);
150
151   gtk_render_frame (context, cr,
152                     0, 0, width, height);
153
154   if (gtk_widget_has_visible_focus (widget))
155     {
156       cairo_set_line_width (cr, 2);
157       if (swatch->priv->has_color && INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) < 0.5)
158         cairo_set_source_rgba (cr, 1., 1., 1., 0.4);
159       else
160         cairo_set_source_rgba (cr, 0., 0., 0., 0.4);
161       _gtk_rounded_box_shrink (&background.clip_box, 3, 3, 3, 3);
162       _gtk_rounded_box_path (&background.clip_box, cr);
163       cairo_stroke (cr);
164     }
165
166   if (swatch->priv->icon)
167     {
168       icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, 16,
169                                               GTK_ICON_LOOKUP_GENERIC_FALLBACK
170                                               | GTK_ICON_LOOKUP_USE_BUILTIN);
171     }
172   else if ((state & GTK_STATE_FLAG_SELECTED) != 0)
173     {
174       GdkRGBA bg, border;
175       GtkBorder border_width;
176       GIcon *gicon;
177
178       gtk_style_context_add_class (context, "color-active-badge");
179       gtk_style_context_get_background_color (context, state, &bg);
180       gtk_style_context_get_border_color (context, state, &border);
181       gtk_style_context_get_border (context, state, &border_width);
182
183       cairo_new_sub_path (cr);
184       cairo_arc (cr, width / 2, height / 2, 10, 0, 2 * G_PI);
185       cairo_close_path (cr);
186       gdk_cairo_set_source_rgba (cr, &bg);
187       cairo_fill_preserve (cr);
188
189       gdk_cairo_set_source_rgba (cr, &border);
190       cairo_set_line_width (cr, border_width.left);
191       cairo_stroke (cr);
192
193       gicon = g_themed_icon_new ("object-select-symbolic");
194       /* fallback for themes that don't have object-select-symbolic */
195       g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply");
196
197       icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, 16,
198                                                   GTK_ICON_LOOKUP_GENERIC_FALLBACK
199                                                   | GTK_ICON_LOOKUP_USE_BUILTIN);
200       g_object_unref (gicon);
201     }
202
203   if (icon_info != NULL)
204     {
205       GdkPixbuf *pixbuf;
206
207       pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context,
208                                                         NULL, NULL);
209
210       if (pixbuf != NULL)
211         {
212           gtk_render_icon (context, cr, pixbuf,
213                            (width - gdk_pixbuf_get_width (pixbuf)) / 2,
214                            (height - gdk_pixbuf_get_height (pixbuf)) / 2);
215           g_object_unref (pixbuf);
216         }
217
218       gtk_icon_info_free (icon_info);
219     }
220
221   cairo_restore (cr);
222   gtk_style_context_restore (context);
223
224   return FALSE;
225 }
226
227 static void
228 drag_set_color_icon (GdkDragContext *context,
229                      const GdkRGBA  *color)
230 {
231   cairo_surface_t *surface;
232   cairo_t *cr;
233
234   surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 48, 32);
235   cr = cairo_create (surface);
236   gdk_cairo_set_source_rgba (cr, color);
237   cairo_paint (cr);
238
239   cairo_surface_set_device_offset (surface, -4, -4);
240   gtk_drag_set_icon_surface (context, surface);
241
242   cairo_destroy (cr);
243   cairo_surface_destroy (surface);
244 }
245
246 static void
247 swatch_drag_begin (GtkWidget      *widget,
248                    GdkDragContext *context)
249 {
250   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
251   GdkRGBA color;
252
253   gtk_color_swatch_get_rgba (swatch, &color);
254   drag_set_color_icon (context, &color);
255 }
256
257 static void
258 swatch_drag_data_get (GtkWidget        *widget,
259                       GdkDragContext   *context,
260                       GtkSelectionData *selection_data,
261                       guint             info,
262                       guint             time)
263 {
264   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
265   guint16 vals[4];
266   GdkRGBA color;
267
268   gtk_color_swatch_get_rgba (swatch, &color);
269
270   vals[0] = color.red * 0xffff;
271   vals[1] = color.green * 0xffff;
272   vals[2] = color.blue * 0xffff;
273   vals[3] = color.alpha * 0xffff;
274
275   gtk_selection_data_set (selection_data,
276                           gdk_atom_intern_static_string ("application/x-color"),
277                           16, (guchar *)vals, 8);
278 }
279
280 static void
281 swatch_drag_data_received (GtkWidget        *widget,
282                            GdkDragContext   *context,
283                            gint              x,
284                            gint              y,
285                            GtkSelectionData *selection_data,
286                            guint             info,
287                            guint             time)
288 {
289   gint length;
290   guint16 *vals;
291   GdkRGBA color;
292
293   length = gtk_selection_data_get_length (selection_data);
294
295   if (length < 0)
296     return;
297
298   /* We accept drops with the wrong format, since the KDE color
299    * chooser incorrectly drops application/x-color with format 8.
300    */
301   if (length != 8)
302     {
303       g_warning ("Received invalid color data\n");
304       return;
305     }
306
307   vals = (guint16 *) gtk_selection_data_get_data (selection_data);
308
309   color.red   = (gdouble)vals[0] / 0xffff;
310   color.green = (gdouble)vals[1] / 0xffff;
311   color.blue  = (gdouble)vals[2] / 0xffff;
312   color.alpha = (gdouble)vals[3] / 0xffff;
313
314   gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color);
315 }
316
317 static void
318 swatch_get_preferred_width (GtkWidget *widget,
319                             gint      *min,
320                             gint      *nat)
321 {
322   *min = *nat = 48;
323 }
324
325 static void
326 swatch_get_preferred_height (GtkWidget *widget,
327                              gint      *min,
328                              gint      *nat)
329 {
330   *min = *nat = 32;
331 }
332
333 static gboolean
334 swatch_key_press (GtkWidget   *widget,
335                   GdkEventKey *event)
336 {
337   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
338
339   if (event->keyval == GDK_KEY_space ||
340       event->keyval == GDK_KEY_Return ||
341       event->keyval == GDK_KEY_ISO_Enter||
342       event->keyval == GDK_KEY_KP_Enter ||
343       event->keyval == GDK_KEY_KP_Space)
344     {
345       if (swatch->priv->has_color && 
346           swatch->priv->selectable &&
347           (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0)
348         gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
349       else
350         g_signal_emit (swatch, signals[ACTIVATE], 0);
351       return TRUE;
352     }
353
354   if (GTK_WIDGET_CLASS (gtk_color_swatch_parent_class)->key_press_event (widget, event))
355     return TRUE;
356
357   return FALSE;
358 }
359
360 static gboolean
361 swatch_enter_notify (GtkWidget        *widget,
362                      GdkEventCrossing *event)
363 {
364   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
365   swatch->priv->contains_pointer = TRUE;
366   return FALSE;
367 }
368
369 static gboolean
370 swatch_leave_notify (GtkWidget        *widget,
371                      GdkEventCrossing *event)
372 {
373   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
374   swatch->priv->contains_pointer = FALSE;
375   return FALSE;
376 }
377
378 static void
379 emit_customize (GtkColorSwatch *swatch)
380 {
381   g_signal_emit (swatch, signals[CUSTOMIZE], 0);
382 }
383
384 static void
385 popup_position_func (GtkMenu   *menu,
386                      gint      *x,
387                      gint      *y,
388                      gboolean  *push_in,
389                      gpointer   user_data)
390 {
391   GtkWidget *widget;
392   GtkRequisition req;
393   gint root_x, root_y;
394   GdkScreen *screen;
395   GdkWindow *window;
396   GdkRectangle monitor;
397   gint monitor_num;
398
399   widget = GTK_WIDGET (user_data);
400   g_return_if_fail (gtk_widget_get_realized (widget));
401   window = gtk_widget_get_window (widget);
402
403   screen = gtk_widget_get_screen (widget);
404   monitor_num = gdk_screen_get_monitor_at_window (screen, window);
405   if (monitor_num < 0)
406     monitor_num = 0;
407   gtk_menu_set_monitor (menu, monitor_num);
408
409   gdk_window_get_origin (window, &root_x, &root_y);
410   gtk_widget_get_preferred_size (GTK_WIDGET (menu), &req, NULL);
411
412   /* Put corner of menu centered on swatch */
413   *x = root_x + gtk_widget_get_allocated_width (widget) / 2;
414   *y = root_y + gtk_widget_get_allocated_height (widget) / 2;
415
416   /* Ensure sanity */
417   gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
418   *x = CLAMP (*x, monitor.x, MAX (monitor.x, monitor.width - req.width));
419   *y = CLAMP (*y, monitor.y, MAX (monitor.y, monitor.height - req.height));
420 }
421
422 static void
423 do_popup (GtkWidget      *swatch,
424           GdkEventButton *event)
425 {
426   GtkWidget *menu;
427   GtkWidget *item;
428
429   menu = gtk_menu_new ();
430   item = gtk_menu_item_new_with_mnemonic (_("_Customize"));
431   gtk_menu_attach_to_widget (GTK_MENU (menu), swatch, NULL);
432
433   g_signal_connect_swapped (item, "activate",
434                             G_CALLBACK (emit_customize), swatch);
435
436   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
437
438   gtk_widget_show_all (item);
439
440   if (event)
441     gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
442                     NULL, NULL, event->button, event->time);
443   else
444     gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
445                     popup_position_func, swatch,
446                     0, gtk_get_current_event_time ());
447 }
448
449 static gboolean
450 swatch_button_press (GtkWidget      *widget,
451                      GdkEventButton *event)
452 {
453   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
454
455   gtk_widget_grab_focus (widget);
456
457   if (gdk_event_triggers_context_menu ((GdkEvent *) event) &&
458       swatch->priv->has_color)
459     {
460       do_popup (widget, event);
461       return TRUE;
462     }
463   else if (event->type == GDK_2BUTTON_PRESS &&
464            event->button == GDK_BUTTON_PRIMARY)
465     {
466       g_signal_emit (swatch, signals[ACTIVATE], 0);
467       return TRUE;
468     }
469
470   return FALSE;
471 }
472
473 static gboolean
474 swatch_button_release (GtkWidget      *widget,
475                        GdkEventButton *event)
476 {
477   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (widget);
478   GtkStateFlags flags;
479
480   if (event->button == GDK_BUTTON_PRIMARY &&
481       swatch->priv->contains_pointer)
482     {
483       flags = gtk_widget_get_state_flags (widget);
484       if (!swatch->priv->has_color)
485         {
486           g_signal_emit (swatch, signals[ACTIVATE], 0);
487           return TRUE;
488         }
489       else if (swatch->priv->selectable &&
490                (flags & GTK_STATE_FLAG_SELECTED) == 0)
491         {
492           gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
493           return TRUE;
494         }
495     }
496
497   return FALSE;
498 }
499
500 static void
501 swatch_realize (GtkWidget *widget)
502 {
503   GtkAllocation allocation;
504   GdkWindow *window;
505   GdkWindowAttr attributes;
506   gint attributes_mask;
507
508   gtk_widget_set_realized (widget, TRUE);
509   gtk_widget_get_allocation (widget, &allocation);
510
511   attributes.window_type = GDK_WINDOW_CHILD;
512   attributes.x = allocation.x;
513   attributes.y = allocation.y;
514   attributes.width = allocation.width;
515   attributes.height = allocation.height;
516   attributes.wclass = GDK_INPUT_OUTPUT;
517   attributes.visual = gtk_widget_get_visual (widget);
518   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
519
520   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
521
522   window = gdk_window_new (gtk_widget_get_parent_window (widget),
523                            &attributes, attributes_mask);
524   gdk_window_set_user_data (window, widget);
525   gtk_widget_set_window (widget, window);
526 }
527
528 static gboolean
529 swatch_popup_menu (GtkWidget *swatch)
530 {
531   do_popup (swatch, NULL);
532   return TRUE;
533 }
534
535 /* GObject implementation {{{1 */
536
537 static void
538 swatch_get_property (GObject    *object,
539                      guint       prop_id,
540                      GValue     *value,
541                      GParamSpec *pspec)
542 {
543   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
544   GdkRGBA color;
545
546   switch (prop_id)
547     {
548     case PROP_RGBA:
549       gtk_color_swatch_get_rgba (swatch, &color);
550       g_value_set_boxed (value, &color);
551       break;
552     case PROP_SELECTABLE:
553       g_value_set_boolean (value, gtk_color_swatch_get_selectable (swatch));
554       break;
555     default:
556       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
557       break;
558     }
559 }
560
561 static void
562 swatch_set_property (GObject      *object,
563                      guint         prop_id,
564                      const GValue *value,
565                      GParamSpec   *pspec)
566 {
567   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
568
569   switch (prop_id)
570     {
571     case PROP_RGBA:
572       gtk_color_swatch_set_rgba (swatch, g_value_get_boxed (value));
573       break;
574     case PROP_SELECTABLE:
575       gtk_color_swatch_set_selectable (swatch, g_value_get_boolean (value));
576       break;
577     default:
578       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
579       break;
580     }
581 }
582
583 static void
584 swatch_finalize (GObject *object)
585 {
586   GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
587
588   g_free (swatch->priv->icon);
589
590   G_OBJECT_CLASS (gtk_color_swatch_parent_class)->finalize (object);
591 }
592
593 static void
594 gtk_color_swatch_class_init (GtkColorSwatchClass *class)
595 {
596   GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
597   GObjectClass *object_class = (GObjectClass *)class;
598
599   object_class->get_property = swatch_get_property;
600   object_class->set_property = swatch_set_property;
601   object_class->finalize = swatch_finalize;
602
603   widget_class->get_preferred_width = swatch_get_preferred_width;
604   widget_class->get_preferred_height = swatch_get_preferred_height;
605   widget_class->draw = swatch_draw;
606   widget_class->drag_begin = swatch_drag_begin;
607   widget_class->drag_data_get = swatch_drag_data_get;
608   widget_class->drag_data_received = swatch_drag_data_received;
609   widget_class->key_press_event = swatch_key_press;
610   widget_class->popup_menu = swatch_popup_menu;
611   widget_class->button_press_event = swatch_button_press;
612   widget_class->button_release_event = swatch_button_release;
613   widget_class->enter_notify_event = swatch_enter_notify;
614   widget_class->leave_notify_event = swatch_leave_notify;
615   widget_class->realize = swatch_realize;
616
617   signals[ACTIVATE] =
618     g_signal_new ("activate",
619                   GTK_TYPE_COLOR_SWATCH,
620                   G_SIGNAL_RUN_FIRST,
621                   G_STRUCT_OFFSET (GtkColorSwatchClass, activate),
622                   NULL, NULL, NULL, G_TYPE_NONE, 0);
623
624   signals[CUSTOMIZE] =
625     g_signal_new ("customize",
626                   GTK_TYPE_COLOR_SWATCH,
627                   G_SIGNAL_RUN_FIRST,
628                   G_STRUCT_OFFSET (GtkColorSwatchClass, customize),
629                   NULL, NULL, NULL, G_TYPE_NONE, 0);
630
631   g_object_class_install_property (object_class, PROP_RGBA,
632       g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"),
633                           GDK_TYPE_RGBA, GTK_PARAM_READWRITE));
634   g_object_class_install_property (object_class, PROP_SELECTABLE,
635       g_param_spec_boolean ("selectable", P_("Selectable"), P_("Whether the swatch is selectable"),
636                             TRUE, GTK_PARAM_READWRITE));
637
638   g_type_class_add_private (object_class, sizeof (GtkColorSwatchPrivate));
639
640   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_COLOR_SWATCH_ACCESSIBLE);
641 }
642
643 /* Public API {{{1 */
644
645 GtkWidget *
646 gtk_color_swatch_new (void)
647 {
648   return (GtkWidget *) g_object_new (GTK_TYPE_COLOR_SWATCH, NULL);
649 }
650
651 static const GtkTargetEntry dnd_targets[] = {
652   { "application/x-color", 0 }
653 };
654
655 void
656 gtk_color_swatch_set_rgba (GtkColorSwatch *swatch,
657                            const GdkRGBA  *color)
658 {
659   GtkStyleContext *context;
660
661   context = gtk_widget_get_style_context (GTK_WIDGET (swatch));
662
663   if (!swatch->priv->has_color)
664     {
665       gtk_drag_source_set (GTK_WIDGET (swatch),
666                            GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
667                            dnd_targets, G_N_ELEMENTS (dnd_targets),
668                            GDK_ACTION_COPY | GDK_ACTION_MOVE);
669     }
670   else
671     {
672       gtk_style_context_remove_class (context, "color-light");
673       gtk_style_context_remove_class (context, "color-dark");
674     }
675
676   swatch->priv->has_color = TRUE;
677   swatch->priv->color = *color;
678
679   if (INTENSITY (swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue) > 0.5)
680     gtk_style_context_add_class (context, "color-light");
681   else
682     gtk_style_context_add_class (context, "color-dark");
683
684   gtk_widget_queue_draw (GTK_WIDGET (swatch));
685   g_object_notify (G_OBJECT (swatch), "rgba");
686 }
687
688 gboolean
689 gtk_color_swatch_get_rgba (GtkColorSwatch *swatch,
690                            GdkRGBA        *color)
691 {
692   if (swatch->priv->has_color)
693     {
694       color->red = swatch->priv->color.red;
695       color->green = swatch->priv->color.green;
696       color->blue = swatch->priv->color.blue;
697       color->alpha = swatch->priv->color.alpha;
698       return TRUE;
699     }
700   else
701     {
702       color->red = 1.0;
703       color->green = 1.0;
704       color->blue = 1.0;
705       color->alpha = 1.0;
706       return FALSE;
707     }
708 }
709
710 void
711 gtk_color_swatch_set_icon (GtkColorSwatch *swatch,
712                            const gchar    *icon)
713 {
714   swatch->priv->icon = g_strdup (icon);
715   gtk_widget_queue_draw (GTK_WIDGET (swatch));
716 }
717
718 void
719 gtk_color_swatch_set_can_drop (GtkColorSwatch *swatch,
720                                gboolean        can_drop)
721 {
722   if (can_drop)
723     {
724       gtk_drag_dest_set (GTK_WIDGET (swatch),
725                          GTK_DEST_DEFAULT_HIGHLIGHT |
726                          GTK_DEST_DEFAULT_MOTION |
727                          GTK_DEST_DEFAULT_DROP,
728                          dnd_targets, G_N_ELEMENTS (dnd_targets),
729                          GDK_ACTION_COPY);
730     }
731   else
732     {
733       gtk_drag_dest_unset (GTK_WIDGET (swatch));
734     }
735 }
736
737 void
738 gtk_color_swatch_set_use_alpha (GtkColorSwatch *swatch,
739                                 gboolean        use_alpha)
740 {
741   swatch->priv->use_alpha = use_alpha;
742   gtk_widget_queue_draw (GTK_WIDGET (swatch));
743 }
744
745 void
746 gtk_color_swatch_set_selectable (GtkColorSwatch *swatch,
747                                  gboolean selectable)
748 {
749   if (selectable == swatch->priv->selectable)
750     return;
751
752   swatch->priv->selectable = selectable;
753   g_object_notify (G_OBJECT (swatch), "selectable");
754 }
755
756 gboolean
757 gtk_color_swatch_get_selectable (GtkColorSwatch *swatch)
758 {
759   return swatch->priv->selectable;
760 }
761
762 /* vim:set foldmethod=marker: */