]> Pileus Git - ~andy/gtk/blob - gtk/gtkcolorbutton.c
More of the same
[~andy/gtk] / gtk / gtkcolorbutton.c
1 /*
2  * GTK - The GIMP Toolkit
3  * Copyright (C) 1998, 1999 Red Hat, Inc.
4  * All rights reserved.
5  *
6  * This Library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This Library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with the Gnome Library; see the file COPYING.LIB.  If not,
18  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /* Color picker button for GNOME
22  *
23  * Author: Federico Mena <federico@nuclecu.unam.mx>
24  *
25  * Modified by the GTK+ Team and others 2003.  See the AUTHORS
26  * file for a list of people on the GTK+ Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
29  */
30
31 #include <config.h>
32
33 #include "gtkcolorbutton.h"
34 #include "gdk/gdkkeysyms.h"
35 #include "gdk-pixbuf/gdk-pixbuf.h"
36 #include "gtkbutton.h"
37 #include "gtkmain.h"
38 #include "gtkalignment.h"
39 #include "gtkcolorsel.h"
40 #include "gtkcolorseldialog.h"
41 #include "gtkdnd.h"
42 #include "gtkdrawingarea.h"
43 #include "gtkframe.h"
44 #include "gtksignal.h"
45 #include "gtkmarshalers.h"
46 #include "gtkprivate.h"
47 #include "gtkintl.h"
48 #include "gtkalias.h"
49
50 /* Size of checks and gray levels for alpha compositing checkerboard */
51 #define CHECK_SIZE  4
52 #define CHECK_DARK  21845  /* 65535 / 3     */
53 #define CHECK_LIGHT 43690 
54
55 #define GTK_COLOR_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_COLOR_BUTTON, GtkColorButtonPrivate))
56
57 struct _GtkColorButtonPrivate 
58 {
59   GdkPixbuf *pixbuf;    /* Pixbuf for rendering sample */
60   GdkGC *gc;            /* GC for drawing */
61   
62   GtkWidget *draw_area; /* Widget where we draw the color sample */
63   GtkWidget *cs_dialog; /* Color selection dialog */
64   
65   gchar *title;         /* Title for the color selection window */
66   
67   GdkColor color;
68   guint16 alpha;
69   
70   guint use_alpha : 1;  /* Use alpha or not */
71 };
72
73 /* Properties */
74 enum 
75 {
76   PROP_0,
77   PROP_USE_ALPHA,
78   PROP_TITLE,
79   PROP_COLOR,
80   PROP_ALPHA
81 };
82
83 /* Signals */
84 enum 
85 {
86   COLOR_SET,
87   LAST_SIGNAL
88 };
89
90 /* gobject signals */
91 static void gtk_color_button_finalize      (GObject             *object);
92 static void gtk_color_button_set_property  (GObject        *object,
93                                             guint           param_id,
94                                             const GValue   *value,
95                                             GParamSpec     *pspec);
96 static void gtk_color_button_get_property  (GObject        *object,
97                                             guint           param_id,
98                                             GValue         *value,
99                                             GParamSpec     *pspec);
100
101 /* gtkwidget signals */
102 static void gtk_color_button_realize       (GtkWidget *widget);
103 static void gtk_color_button_unrealize     (GtkWidget *widget);
104 static void gtk_color_button_state_changed (GtkWidget           *widget, 
105                                             GtkStateType         previous_state);
106 static void gtk_color_button_style_set     (GtkWidget *widget, 
107                                             GtkStyle  *previous_style);
108
109 /* gtkbutton signals */
110 static void gtk_color_button_clicked       (GtkButton           *button);
111
112 /* source side drag signals */
113 static void gtk_color_button_drag_begin (GtkWidget        *widget,
114                                          GdkDragContext   *context,
115                                          gpointer          data);
116 static void gtk_color_button_drag_data_get (GtkWidget        *widget,
117                                             GdkDragContext   *context,
118                                             GtkSelectionData *selection_data,
119                                             guint             info,
120                                             guint             time,
121                                             GtkColorButton   *color_button);
122
123 /* target side drag signals */
124 static void gtk_color_button_drag_data_received (GtkWidget        *widget,
125                                                  GdkDragContext   *context,
126                                                  gint              x,
127                                                  gint              y,
128                                                  GtkSelectionData *selection_data,
129                                                  guint             info,
130                                                  guint32           time,
131                                                  GtkColorButton   *color_button);
132
133
134 static guint color_button_signals[LAST_SIGNAL] = { 0 };
135
136 static const GtkTargetEntry drop_types[] = { { "application/x-color", 0, 0 } };
137
138 G_DEFINE_TYPE (GtkColorButton, gtk_color_button, GTK_TYPE_BUTTON)
139
140 static void
141 gtk_color_button_class_init (GtkColorButtonClass *klass)
142 {
143   GObjectClass *gobject_class;
144   GtkWidgetClass *widget_class;
145   GtkButtonClass *button_class;
146
147   gobject_class = G_OBJECT_CLASS (klass);
148   widget_class = GTK_WIDGET_CLASS (klass);
149   button_class = GTK_BUTTON_CLASS (klass);
150
151   gobject_class->get_property = gtk_color_button_get_property;
152   gobject_class->set_property = gtk_color_button_set_property;
153   gobject_class->finalize = gtk_color_button_finalize;
154   widget_class->state_changed = gtk_color_button_state_changed;
155   widget_class->realize = gtk_color_button_realize;
156   widget_class->unrealize = gtk_color_button_unrealize;
157   widget_class->style_set = gtk_color_button_style_set;
158   button_class->clicked = gtk_color_button_clicked;
159   klass->color_set = NULL;
160
161   /**
162    * GtkColorButton:use-alpha:
163    *
164    * If this property is set to %TRUE, the color swatch on the button is rendered against a 
165    * checkerboard background to show its opacity and the opacity slider is displayed in the 
166    * color selection dialog. 
167    *
168    * Since: 2.4
169    */
170   g_object_class_install_property (gobject_class,
171                                    PROP_USE_ALPHA,
172                                    g_param_spec_boolean ("use-alpha", P_("Use alpha"), 
173                                                          P_("Whether or not to give the color an alpha value"),
174                                                          FALSE,
175                                                          GTK_PARAM_READWRITE));
176
177   /**
178    * GtkColorButton:title:
179    *
180    * The title of the color selection dialog
181    *
182    * Since: 2.4
183    */
184   g_object_class_install_property (gobject_class,
185                                    PROP_TITLE,
186                                    g_param_spec_string ("title", 
187                                                         P_("Title"), 
188                                                         P_("The title of the color selection dialog"),
189                                                         _("Pick a Color"),
190                                                         GTK_PARAM_READWRITE));
191
192   /**
193    * GtkColorButton:color:
194    *
195    * The selected color.
196    *
197    * Since: 2.4
198    */
199   g_object_class_install_property (gobject_class,
200                                    PROP_COLOR,
201                                    g_param_spec_boxed ("color",
202                                                        P_("Current Color"),
203                                                        P_("The selected color"),
204                                                        GDK_TYPE_COLOR,
205                                                        GTK_PARAM_READWRITE));
206
207   /**
208    * GtkColorButton:alpha:
209    *
210    * The selected opacity value (0 fully transparent, 65535 fully opaque). 
211    *
212    * Since: 2.4
213    */
214   g_object_class_install_property (gobject_class,
215                                    PROP_ALPHA,
216                                    g_param_spec_uint ("alpha",
217                                                       P_("Current Alpha"),
218                                                       P_("The selected opacity value (0 fully transparent, 65535 fully opaque)"),
219                                                       0, 65535, 65535,
220                                                       GTK_PARAM_READWRITE));
221         
222   /**
223    * GtkColorButton::color-set:
224    * @widget: the object which received the signal.
225    * 
226    * The ::color-set signal is emitted when the user selects a color. When handling this signal,
227    * use gtk_color_button_get_color() and gtk_color_button_get_alpha() to find out which color 
228    * was just selected.
229    *
230    * Since: 2.4
231    */
232   color_button_signals[COLOR_SET] = g_signal_new (I_("color_set"),
233                                                   G_TYPE_FROM_CLASS (gobject_class),
234                                                   G_SIGNAL_RUN_FIRST,
235                                                   G_STRUCT_OFFSET (GtkColorButtonClass, color_set),
236                                                   NULL, NULL,
237                                                   _gtk_marshal_VOID__VOID,
238                                                   G_TYPE_NONE, 0);
239
240   g_type_class_add_private (gobject_class, sizeof (GtkColorButtonPrivate));
241 }
242
243 static void
244 render (GtkColorButton *color_button)
245 {
246   gint dark_r, dark_g, dark_b;
247   gint light_r, light_g, light_b;
248   gint i, j, rowstride;
249   gint width, height;
250   gint c1[3], c2[3];
251   guchar *pixels;
252   guint8 insensitive_r = 0;
253   guint8 insensitive_g = 0;
254   guint8 insensitive_b = 0;
255
256   width = color_button->priv->draw_area->allocation.width;
257   height = color_button->priv->draw_area->allocation.height;
258   if (color_button->priv->pixbuf == NULL || 
259       gdk_pixbuf_get_width (color_button->priv->pixbuf) != width ||
260       gdk_pixbuf_get_height (color_button->priv->pixbuf) != height) 
261     {
262       if (color_button->priv->pixbuf != NULL)
263         g_object_unref (color_button->priv->pixbuf);
264       color_button->priv->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
265     }
266   
267
268   /* Compute dark and light check colors */
269
270   insensitive_r = GTK_WIDGET(color_button)->style->bg[GTK_STATE_INSENSITIVE].red >> 8;
271   insensitive_g = GTK_WIDGET(color_button)->style->bg[GTK_STATE_INSENSITIVE].green >> 8;
272   insensitive_b = GTK_WIDGET(color_button)->style->bg[GTK_STATE_INSENSITIVE].blue >> 8;
273
274   if (color_button->priv->use_alpha) 
275     {
276       dark_r = ((CHECK_DARK << 16) + (color_button->priv->color.red - CHECK_DARK) * color_button->priv->alpha) >> 24;
277       dark_g = ((CHECK_DARK << 16) + (color_button->priv->color.green - CHECK_DARK) * color_button->priv->alpha) >> 24;
278       dark_b = ((CHECK_DARK << 16) + (color_button->priv->color.blue - CHECK_DARK) * color_button->priv->alpha) >> 24;
279       
280       light_r = ((CHECK_LIGHT << 16) + (color_button->priv->color.red - CHECK_LIGHT) * color_button->priv->alpha) >> 24;
281       light_g = ((CHECK_LIGHT << 16) + (color_button->priv->color.green - CHECK_LIGHT) * color_button->priv->alpha) >> 24;
282       light_b = ((CHECK_LIGHT << 16) + (color_button->priv->color.blue - CHECK_LIGHT) * color_button->priv->alpha) >> 24;
283     } 
284   else 
285     {
286       dark_r = light_r = color_button->priv->color.red >> 8;
287       dark_g = light_g = color_button->priv->color.green >> 8;
288       dark_b = light_b = color_button->priv->color.blue >> 8;
289     }
290
291   /* Fill image buffer */
292   pixels = gdk_pixbuf_get_pixels (color_button->priv->pixbuf);
293   rowstride = gdk_pixbuf_get_rowstride (color_button->priv->pixbuf);
294   for (j = 0; j < height; j++) 
295     {
296       if ((j / CHECK_SIZE) & 1) 
297         {
298           c1[0] = dark_r;
299           c1[1] = dark_g;
300           c1[2] = dark_b;
301           
302           c2[0] = light_r;
303           c2[1] = light_g;
304           c2[2] = light_b;
305         } 
306       else 
307         {
308           c1[0] = light_r;
309           c1[1] = light_g;
310           c1[2] = light_b;
311           
312           c2[0] = dark_r;
313           c2[1] = dark_g;
314           c2[2] = dark_b;
315         }
316       
317     for (i = 0; i < width; i++) 
318       {
319         if (!GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (color_button)) && (i+j)%2) 
320           {
321             *(pixels + j * rowstride + i * 3) = insensitive_r;
322             *(pixels + j * rowstride + i * 3 + 1) = insensitive_g;
323             *(pixels + j * rowstride + i * 3 + 2) = insensitive_b;
324           } 
325         else if ((i / CHECK_SIZE) & 1) 
326           {
327             *(pixels + j * rowstride + i * 3)     = c1[0];
328             *(pixels + j * rowstride + i * 3 + 1) = c1[1];
329             *(pixels + j * rowstride + i * 3 + 2) = c1[2];
330           }
331         else
332           {
333             *(pixels + j * rowstride + i * 3)     = c2[0];
334             *(pixels + j * rowstride + i * 3 + 1) = c2[1];
335             *(pixels + j * rowstride + i * 3 + 2) = c2[2];
336           }
337       }
338     }
339 }
340
341 /* Handle exposure events for the color picker's drawing area */
342 static gint
343 expose_event (GtkWidget      *widget, 
344               GdkEventExpose *event, 
345               gpointer        data)
346 {
347   GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
348
349   gint width = color_button->priv->draw_area->allocation.width;
350   gint height = color_button->priv->draw_area->allocation.height;
351
352   if (color_button->priv->pixbuf == NULL ||
353       width != gdk_pixbuf_get_width (color_button->priv->pixbuf) ||
354       height != gdk_pixbuf_get_height (color_button->priv->pixbuf)) 
355     render (color_button);
356
357   gdk_draw_pixbuf (widget->window,
358                    color_button->priv->gc,
359                    color_button->priv->pixbuf,
360                    event->area.x - widget->allocation.x,
361                    event->area.y - widget->allocation.y,
362                    event->area.x,
363                    event->area.y,
364                    event->area.width,
365                    event->area.height,
366                    GDK_RGB_DITHER_MAX,
367                    event->area.x - widget->allocation.x,
368                    event->area.y - widget->allocation.y);
369   return FALSE;
370 }
371
372 static void
373 gtk_color_button_realize (GtkWidget *widget)
374 {
375   GtkColorButton *color_button = GTK_COLOR_BUTTON (widget);
376
377   GTK_WIDGET_CLASS (gtk_color_button_parent_class)->realize (widget);
378
379   color_button->priv->gc = gdk_gc_new (widget->window);
380
381   render (color_button);
382 }
383
384 static void
385 gtk_color_button_unrealize (GtkWidget *widget)
386 {
387   GtkColorButton *color_button = GTK_COLOR_BUTTON (widget);
388
389   g_object_unref (color_button->priv->gc);
390   color_button->priv->gc = NULL;
391
392   GTK_WIDGET_CLASS (gtk_color_button_parent_class)->unrealize (widget);
393 }
394
395 static void
396 gtk_color_button_style_set (GtkWidget *widget, 
397                             GtkStyle  *previous_style)
398 {
399   GtkColorButton *color_button = GTK_COLOR_BUTTON (widget);
400
401   GTK_WIDGET_CLASS (gtk_color_button_parent_class)->style_set (widget, previous_style);
402
403   if (GTK_WIDGET_REALIZED (widget)) 
404     {
405       if (color_button->priv->pixbuf != NULL)
406         g_object_unref (color_button->priv->pixbuf);
407       color_button->priv->pixbuf = NULL;
408     }
409 }
410
411 static void
412 gtk_color_button_state_changed (GtkWidget   *widget, 
413                                           GtkStateType previous_state)
414 {
415   GtkColorButton *color_button = GTK_COLOR_BUTTON (widget);
416
417   if (widget->state == GTK_STATE_INSENSITIVE || previous_state == GTK_STATE_INSENSITIVE)
418     {
419       if (color_button->priv->pixbuf != NULL)
420         g_object_unref (color_button->priv->pixbuf);
421       color_button->priv->pixbuf = NULL;
422     }
423 }
424
425 static void
426 gtk_color_button_drag_data_received (GtkWidget        *widget,
427                                      GdkDragContext   *context,
428                                      gint              x,
429                                      gint              y,
430                                      GtkSelectionData *selection_data,
431                                      guint             info,
432                                      guint32           time,
433                                      GtkColorButton   *color_button)
434 {
435   guint16 *dropped;
436
437   if (selection_data->length < 0)
438     return;
439
440   /* We accept drops with the wrong format, since the KDE color
441    * chooser incorrectly drops application/x-color with format 8.
442    */
443   if (selection_data->length != 8) 
444     {
445       g_warning (_("Received invalid color data\n"));
446       return;
447     }
448
449
450   dropped = (guint16 *)selection_data->data;
451
452   color_button->priv->color.red = dropped[0];
453   color_button->priv->color.green = dropped[1];
454   color_button->priv->color.blue = dropped[2];
455   color_button->priv->alpha = dropped[3];
456
457   if (color_button->priv->pixbuf != NULL)
458     g_object_unref (color_button->priv->pixbuf);
459   color_button->priv->pixbuf = NULL;
460
461   gtk_widget_queue_draw (color_button->priv->draw_area);
462
463   g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
464
465   g_object_freeze_notify (G_OBJECT (color_button));
466   g_object_notify (G_OBJECT (color_button), "color");
467   g_object_notify (G_OBJECT (color_button), "alpha");
468   g_object_thaw_notify (G_OBJECT (color_button));
469 }
470
471 static void
472 set_color_icon (GdkDragContext *context,
473                 GdkColor       *color)
474 {
475   GdkPixbuf *pixbuf;
476   guint32 pixel;
477
478   pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
479                            8, 48, 32);
480
481   pixel = ((color->red & 0xff00) << 16) | 
482           ((color->green & 0xff00) << 8) | 
483            (color->blue & 0xff00);
484
485   gdk_pixbuf_fill (pixbuf, pixel);
486   
487   gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
488   g_object_unref (pixbuf);
489 }
490
491 static void
492 gtk_color_button_drag_begin (GtkWidget      *widget,
493                              GdkDragContext *context,
494                              gpointer        data)
495 {
496   GtkColorButton *color_button = data;
497   
498   set_color_icon (context, &color_button->priv->color);
499 }
500
501 static void
502 gtk_color_button_drag_data_get (GtkWidget        *widget,
503                                 GdkDragContext   *context,
504                                 GtkSelectionData *selection_data,
505                                 guint             info,
506                                 guint             time,
507                                 GtkColorButton   *color_button)
508 {
509   guint16 dropped[4];
510
511   dropped[0] = color_button->priv->color.red;
512   dropped[1] = color_button->priv->color.green;
513   dropped[2] = color_button->priv->color.blue;
514   dropped[3] = color_button->priv->alpha;
515
516   gtk_selection_data_set (selection_data, selection_data->target,
517                           16, (guchar *)dropped, 8);
518 }
519
520 static void
521 gtk_color_button_init (GtkColorButton *color_button)
522 {
523   GtkWidget *alignment;
524   GtkWidget *frame;
525   PangoLayout *layout;
526   PangoRectangle rect;
527
528   /* Create the widgets */
529   color_button->priv = GTK_COLOR_BUTTON_GET_PRIVATE (color_button);
530
531   gtk_widget_push_composite_child ();
532
533   alignment = gtk_alignment_new (0.5, 0.5, 0.5, 1.0);
534   gtk_container_set_border_width (GTK_CONTAINER (alignment), 1);
535   gtk_container_add (GTK_CONTAINER (color_button), alignment);
536   gtk_widget_show (alignment);
537
538   frame = gtk_frame_new (NULL);
539   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
540   gtk_container_add (GTK_CONTAINER (alignment), frame);
541   gtk_widget_show (frame);
542
543   /* Just some widget we can hook to expose-event on */
544   color_button->priv->draw_area = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
545
546   layout = gtk_widget_create_pango_layout (GTK_WIDGET (color_button), "Black");
547   pango_layout_get_pixel_extents (layout, NULL, &rect);
548   g_object_unref (layout);
549
550   gtk_widget_set_size_request (color_button->priv->draw_area, rect.width - 2, rect.height - 2);
551   g_signal_connect (color_button->priv->draw_area, "expose-event",
552                     G_CALLBACK (expose_event), color_button);
553   gtk_container_add (GTK_CONTAINER (frame), color_button->priv->draw_area);
554   gtk_widget_show (color_button->priv->draw_area);
555
556   color_button->priv->title = g_strdup (_("Pick a Color")); /* default title */
557
558   /* Create the buffer for the image so that we can create an image.  
559    * Also create the picker's pixmap.
560    */
561   color_button->priv->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, rect.width, rect.height);
562
563   color_button->priv->gc = NULL;
564
565   /* Start with opaque black, alpha disabled */
566
567   color_button->priv->color.red = 0;
568   color_button->priv->color.green = 0;
569   color_button->priv->color.blue = 0;
570   color_button->priv->alpha = 65535;
571   color_button->priv->use_alpha = FALSE;
572
573   gtk_drag_dest_set (GTK_WIDGET (color_button),
574                      GTK_DEST_DEFAULT_MOTION |
575                      GTK_DEST_DEFAULT_HIGHLIGHT |
576                      GTK_DEST_DEFAULT_DROP,
577                      drop_types, 1, GDK_ACTION_COPY);
578   gtk_drag_source_set (GTK_WIDGET(color_button),
579                        GDK_BUTTON1_MASK|GDK_BUTTON3_MASK,
580                        drop_types, 1,
581                        GDK_ACTION_COPY);
582   g_signal_connect (color_button, "drag_begin",
583                     G_CALLBACK (gtk_color_button_drag_begin), color_button);
584   g_signal_connect (color_button, "drag_data_received",
585                     G_CALLBACK (gtk_color_button_drag_data_received), color_button);
586   g_signal_connect (color_button, "drag_data_get",
587                     G_CALLBACK (gtk_color_button_drag_data_get), color_button);
588
589   gtk_widget_pop_composite_child ();
590 }
591
592 static void
593 gtk_color_button_finalize (GObject *object)
594 {
595   GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
596
597   if (color_button->priv->cs_dialog != NULL)
598     gtk_widget_destroy (color_button->priv->cs_dialog);
599   color_button->priv->cs_dialog = NULL;
600
601   if (color_button->priv->pixbuf != NULL)
602     g_object_unref (color_button->priv->pixbuf);
603   color_button->priv->pixbuf = NULL;
604
605   g_free (color_button->priv->title);
606   color_button->priv->title = NULL;
607
608   G_OBJECT_CLASS (gtk_color_button_parent_class)->finalize (object);
609 }
610
611
612 /**
613  * gtk_color_button_new:
614  *
615  * Creates a new color button. This returns a widget in the form of
616  * a small button containing a swatch representing the current selected 
617  * color. When the button is clicked, a color-selection dialog will open, 
618  * allowing the user to select a color. The swatch will be updated to reflect 
619  * the new color when the user finishes.
620  *
621  * Returns: a new color button.
622  *
623  * Since: 2.4
624  */
625 GtkWidget *
626 gtk_color_button_new (void)
627 {
628   return g_object_new (GTK_TYPE_COLOR_BUTTON, NULL);
629 }
630
631 /**
632  * gtk_color_button_new_with_color:
633  * @color: A #GdkColor to set the current color with.
634  *
635  * Creates a new color button. 
636  *
637  * Returns: a new color button.
638  *
639  * Since: 2.4
640  */
641 GtkWidget *
642 gtk_color_button_new_with_color (const GdkColor *color)
643 {
644   return g_object_new (GTK_TYPE_COLOR_BUTTON, "color", color, NULL);
645 }
646
647 static void
648 dialog_ok_clicked (GtkWidget *widget, 
649                    gpointer   data)
650 {
651   GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
652   GtkColorSelection *color_selection;
653
654   color_selection = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog)->colorsel);
655
656   gtk_color_selection_get_current_color (color_selection, &color_button->priv->color);
657   color_button->priv->alpha = gtk_color_selection_get_current_alpha (color_selection);
658
659   if (color_button->priv->pixbuf != NULL)
660     g_object_unref (color_button->priv->pixbuf);
661   color_button->priv->pixbuf = NULL;
662
663   gtk_widget_hide (color_button->priv->cs_dialog);
664
665   gtk_widget_queue_draw (color_button->priv->draw_area);
666
667   g_signal_emit (color_button, color_button_signals[COLOR_SET], 0);
668
669   g_object_freeze_notify (G_OBJECT (color_button));
670   g_object_notify (G_OBJECT (color_button), "color");
671   g_object_notify (G_OBJECT (color_button), "alpha");
672   g_object_thaw_notify (G_OBJECT (color_button));
673 }
674
675 static gboolean
676 dialog_destroy (GtkWidget *widget, 
677                 gpointer   data)
678 {
679   GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
680   
681   color_button->priv->cs_dialog = NULL;
682
683   return FALSE;
684 }
685
686 static void
687 dialog_cancel_clicked (GtkWidget *widget,
688                        gpointer   data)
689 {
690   GtkColorButton *color_button = GTK_COLOR_BUTTON (data);
691   
692   gtk_widget_hide (color_button->priv->cs_dialog);  
693 }
694
695 static void
696 gtk_color_button_clicked (GtkButton *button)
697 {
698   GtkColorButton *color_button = GTK_COLOR_BUTTON (button);
699   GtkColorSelectionDialog *color_dialog;
700
701   /* if dialog already exists, make sure it's shown and raised */
702   if (!color_button->priv->cs_dialog) 
703     {
704       /* Create the dialog and connects its buttons */
705       GtkWidget *parent;
706       
707       parent = gtk_widget_get_toplevel (GTK_WIDGET (color_button));
708       
709       color_button->priv->cs_dialog = gtk_color_selection_dialog_new (color_button->priv->title);
710       
711       color_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
712
713       if (parent)
714         gtk_window_set_transient_for (GTK_WINDOW (color_dialog),
715                                       GTK_WINDOW (parent));
716       
717       g_signal_connect (color_dialog->ok_button, "clicked",
718                         G_CALLBACK (dialog_ok_clicked), color_button);
719       g_signal_connect (color_dialog->cancel_button, "clicked",
720                         G_CALLBACK (dialog_cancel_clicked), color_button);
721       g_signal_connect (color_dialog, "destroy",
722                         G_CALLBACK (dialog_destroy), color_button);
723       
724       /* If there is a grabbed window, set new dialog as modal */
725       if (gtk_grab_get_current ())
726         gtk_window_set_modal (GTK_WINDOW (color_button->priv->cs_dialog),TRUE);
727     }
728
729   color_dialog = GTK_COLOR_SELECTION_DIALOG (color_button->priv->cs_dialog);
730
731   gtk_color_selection_set_has_opacity_control (GTK_COLOR_SELECTION (color_dialog->colorsel),
732                                                color_button->priv->use_alpha);
733   
734   gtk_color_selection_set_previous_color (GTK_COLOR_SELECTION (color_dialog->colorsel), 
735                                           &color_button->priv->color);
736   gtk_color_selection_set_previous_alpha (GTK_COLOR_SELECTION (color_dialog->colorsel), 
737                                           color_button->priv->alpha);
738
739   gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (color_dialog->colorsel), 
740                                          &color_button->priv->color);
741   gtk_color_selection_set_current_alpha (GTK_COLOR_SELECTION (color_dialog->colorsel), 
742                                          color_button->priv->alpha);
743
744   gtk_window_present (GTK_WINDOW (color_button->priv->cs_dialog));
745 }
746
747 /**
748  * gtk_color_button_set_color:
749  * @color_button: a #GtkColorButton.
750  * @color: A #GdkColor to set the current color with.
751  *
752  * Sets the current color to be @color.
753  *
754  * Since: 2.4
755  **/
756 void
757 gtk_color_button_set_color (GtkColorButton *color_button,
758                             const GdkColor *color)
759 {
760   g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
761   g_return_if_fail (color != NULL);
762
763   color_button->priv->color.red = color->red;
764   color_button->priv->color.green = color->green;
765   color_button->priv->color.blue = color->blue;
766
767   if (color_button->priv->pixbuf != NULL)
768     g_object_unref (color_button->priv->pixbuf);
769   color_button->priv->pixbuf = NULL;
770
771   gtk_widget_queue_draw (color_button->priv->draw_area);
772   
773   g_object_notify (G_OBJECT (color_button), "color");
774 }
775
776
777 /**
778  * gtk_color_button_set_alpha:
779  * @color_button: a #GtkColorButton.
780  * @alpha: an integer between 0 and 65535.
781  *
782  * Sets the current opacity to be @alpha. 
783  *
784  * Since: 2.4
785  **/
786 void
787 gtk_color_button_set_alpha (GtkColorButton *color_button,
788                             guint16         alpha)
789 {
790   g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
791
792   color_button->priv->alpha = alpha;
793
794   if (color_button->priv->pixbuf != NULL)
795     g_object_unref (color_button->priv->pixbuf);
796   color_button->priv->pixbuf = NULL;
797
798   gtk_widget_queue_draw (color_button->priv->draw_area);
799
800   g_object_notify (G_OBJECT (color_button), "alpha");
801 }
802
803 /**
804  * gtk_color_button_get_color:
805  * @color_button: a #GtkColorButton.
806  * @color: a #GdkColor to fill in with the current color.
807  *
808  * Sets @color to be the current color in the #GtkColorButton widget.
809  *
810  * Since: 2.4
811  **/
812 void
813 gtk_color_button_get_color (GtkColorButton *color_button,
814                             GdkColor       *color)
815 {
816   g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
817   
818   color->red = color_button->priv->color.red;
819   color->green = color_button->priv->color.green;
820   color->blue = color_button->priv->color.blue;
821 }
822
823 /**
824  * gtk_color_button_get_alpha:
825  * @color_button: a #GtkColorButton.
826  *
827  * Returns the current alpha value. 
828  *
829  * Return value: an integer between 0 and 65535.
830  *
831  * Since: 2.4
832  **/
833 guint16
834 gtk_color_button_get_alpha (GtkColorButton *color_button)
835 {
836   g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), 0);
837   
838   return color_button->priv->alpha;
839 }
840
841 /**
842  * gtk_color_button_set_use_alpha:
843  * @color_button: a #GtkColorButton.
844  * @use_alpha: %TRUE if color button should use alpha channel, %FALSE if not.
845  *
846  * Sets whether or not the color button should use the alpha channel.
847  *
848  * Since: 2.4
849  */
850 void
851 gtk_color_button_set_use_alpha (GtkColorButton *color_button, 
852                                 gboolean        use_alpha)
853 {
854   g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
855
856   use_alpha = (use_alpha != FALSE);
857
858   if (color_button->priv->use_alpha != use_alpha) 
859     {
860       color_button->priv->use_alpha = use_alpha;
861
862       render (color_button);
863       gtk_widget_queue_draw (color_button->priv->draw_area);
864
865       g_object_notify (G_OBJECT (color_button), "use-alpha");
866     }
867 }
868
869 /**
870  * gtk_color_button_get_use_alpha:
871  * @color_button: a #GtkColorButton.
872  *
873  * Does the color selection dialog use the alpha channel?
874  *
875  * Returns: %TRUE if the color sample uses alpha channel, %FALSE if not.
876  *
877  * Since: 2.4
878  */
879 gboolean
880 gtk_color_button_get_use_alpha (GtkColorButton *color_button)
881 {
882   g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), FALSE);
883
884   return color_button->priv->use_alpha;
885 }
886
887
888 /**
889  * gtk_color_button_set_title:
890  * @color_button: a #GtkColorButton
891  * @title: String containing new window title.
892  *
893  * Sets the title for the color selection dialog.
894  *
895  * Since: 2.4
896  */
897 void
898 gtk_color_button_set_title (GtkColorButton *color_button, 
899                             const gchar    *title)
900 {
901   gchar *old_title;
902
903   g_return_if_fail (GTK_IS_COLOR_BUTTON (color_button));
904
905   old_title = color_button->priv->title;
906   color_button->priv->title = g_strdup (title);
907   g_free (old_title);
908
909   if (color_button->priv->cs_dialog)
910     gtk_window_set_title (GTK_WINDOW (color_button->priv->cs_dialog), 
911                           color_button->priv->title);
912   
913   g_object_notify (G_OBJECT (color_button), "title");
914 }
915
916 /**
917  * gtk_color_button_get_title:
918  * @color_button: a #GtkColorButton
919  *
920  * Gets the title of the color selection dialog.
921  *
922  * Returns: An internal string, do not free the return value
923  *
924  * Since: 2.4
925  */
926 G_CONST_RETURN gchar *
927 gtk_color_button_get_title (GtkColorButton *color_button)
928 {
929   g_return_val_if_fail (GTK_IS_COLOR_BUTTON (color_button), NULL);
930
931   return color_button->priv->title;
932 }
933
934 static void
935 gtk_color_button_set_property (GObject      *object,
936                                guint         param_id,
937                                const GValue *value,
938                                GParamSpec   *pspec)
939 {
940   GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
941
942   switch (param_id) 
943     {
944     case PROP_USE_ALPHA:
945       gtk_color_button_set_use_alpha (color_button, g_value_get_boolean (value));
946       break;
947     case PROP_TITLE:
948       gtk_color_button_set_title (color_button, g_value_get_string (value));
949       break;
950     case PROP_COLOR:
951       gtk_color_button_set_color (color_button, g_value_get_boxed (value));
952       break;
953     case PROP_ALPHA:
954       gtk_color_button_set_alpha (color_button, g_value_get_uint (value));
955       break;
956     default:
957       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
958       break;
959     }
960 }
961
962 static void
963 gtk_color_button_get_property (GObject    *object,
964                                guint       param_id,
965                                GValue     *value,
966                                GParamSpec *pspec)
967 {
968   GtkColorButton *color_button = GTK_COLOR_BUTTON (object);
969   GdkColor color;
970
971   switch (param_id) 
972     {
973     case PROP_USE_ALPHA:
974       g_value_set_boolean (value, gtk_color_button_get_use_alpha (color_button));
975       break;
976     case PROP_TITLE:
977       g_value_set_string (value, gtk_color_button_get_title (color_button));
978       break;
979     case PROP_COLOR:
980       gtk_color_button_get_color (color_button, &color);
981       g_value_set_boxed (value, &color);
982       break;
983     case PROP_ALPHA:
984       g_value_set_uint (value, gtk_color_button_get_alpha (color_button));
985       break;
986     default:
987       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
988       break;
989     }
990 }
991
992 #define __GTK_COLOR_BUTTON_C__
993 #include "gtkaliasdef.c"