gtkcolorsel.c 76.9 KB
Newer Older
1
/* GTK - The GIMP Toolkit
2
 * Copyright (C) 2000 Red Hat, Inc.
Elliot Lee's avatar
Elliot Lee committed
3 4 5
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16 17 18
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
19
 */
20 21

/*
22
 * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
23 24 25 26 27
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

28
#include "gdkconfig.h"
29
#include <math.h>
30

31
#include "gdk/gdkkeysyms.h"
Elliot Lee's avatar
Elliot Lee committed
32
#include "gtkcolorsel.h"
33
#include "gtkhsv.h"
Owen Taylor's avatar
Owen Taylor committed
34
#include "gtkwindow.h"
35 36 37 38
#include "gtkselection.h"
#include "gtkdnd.h"
#include "gtkdrawingarea.h"
#include "gtkhbox.h"
39
#include "gtkhbbox.h"
40 41 42 43
#include "gtkrc.h"
#include "gtkframe.h"
#include "gtktable.h"
#include "gtklabel.h"
44
#include "gtkmarshalers.h"
Manish Singh's avatar
Manish Singh committed
45
#include "gtkimage.h"
46 47 48 49 50 51
#include "gtkspinbutton.h"
#include "gtkrange.h"
#include "gtkhscale.h"
#include "gtkentry.h"
#include "gtkbutton.h"
#include "gtkhseparator.h"
52 53 54 55 56
#include "gtktooltips.h"
#include "gtkinvisible.h"
#include "gtkmenuitem.h"
#include "gtkmain.h"
#include "gtksettings.h"
57
#include "gtkintl.h"
58
#include "gtkimage.h"
59
#include "gtkstock.h"
Elliot Lee's avatar
Elliot Lee committed
60

61 62
#include <string.h>

63 64 65 66
/* Number of elements in the custom palatte */
#define GTK_CUSTOM_PALETTE_WIDTH 10
#define GTK_CUSTOM_PALETTE_HEIGHT 2

67 68 69 70 71 72 73
/* Conversion between 0->1 double and and guint16. See
 * scale_round() below for more general conversions
 */
#define SCALE(i) (i / 65535.)
#define UNSCALE(d) ((guint16)(d * 65535 + 0.5))


74
enum {
Elliot Lee's avatar
Elliot Lee committed
75 76 77 78
  COLOR_CHANGED,
  LAST_SIGNAL
};

79 80 81 82 83
enum {
  PROP_0,
  PROP_HAS_PALETTE,
  PROP_HAS_OPACITY_CONTROL,
  PROP_CURRENT_COLOR,
84
  PROP_CURRENT_ALPHA
85 86
};

87
enum {
88 89 90 91 92 93 94 95
  COLORSEL_RED = 0,
  COLORSEL_GREEN = 1,
  COLORSEL_BLUE = 2,
  COLORSEL_OPACITY = 3,
  COLORSEL_HUE,
  COLORSEL_SATURATION,
  COLORSEL_VALUE,
  COLORSEL_NUM_CHANNELS
Elliot Lee's avatar
Elliot Lee committed
96 97
};

98
typedef struct _ColorSelectionPrivate ColorSelectionPrivate;
99

100
struct _ColorSelectionPrivate
Elliot Lee's avatar
Elliot Lee committed
101
{
102 103
  guint has_opacity : 1;
  guint has_palette : 1;
104 105
  guint changing : 1;
  guint default_set : 1;
106
  guint default_alpha_set : 1;
107
  
108 109
  gdouble color[COLORSEL_NUM_CHANNELS];
  gdouble old_color[COLORSEL_NUM_CHANNELS];
110
  
111 112 113 114 115 116 117 118 119 120 121 122
  GtkWidget *triangle_colorsel;
  GtkWidget *hue_spinbutton;
  GtkWidget *sat_spinbutton;
  GtkWidget *val_spinbutton;
  GtkWidget *red_spinbutton;
  GtkWidget *green_spinbutton;
  GtkWidget *blue_spinbutton;
  GtkWidget *opacity_slider;
  GtkWidget *opacity_label;
  GtkWidget *opacity_entry;
  GtkWidget *palette_frame;
  GtkWidget *hex_entry;
123
  
124
  /* The Palette code */
125 126
  GtkWidget *custom_palette [GTK_CUSTOM_PALETTE_WIDTH][GTK_CUSTOM_PALETTE_HEIGHT];
  
127 128 129 130 131
  /* The color_sample stuff */
  GtkWidget *sample_area;
  GtkWidget *old_sample;
  GtkWidget *cur_sample;
  GtkWidget *colorsel;
132 133 134 135 136 137

  /* Tooltips group */
  GtkTooltips *tooltips;

  /* Window for grabbing on */
  GtkWidget *dropper_grab_widget;
138 139

  /* Connection to settings */
140
  gulong settings_connection;
Elliot Lee's avatar
Elliot Lee committed
141 142 143
};


144
static void gtk_color_selection_init		(GtkColorSelection	 *colorsel);
145
static void gtk_color_selection_class_init	(GtkColorSelectionClass	 *klass);
146
static void gtk_color_selection_destroy		(GtkObject		 *object);
147
static void gtk_color_selection_finalize        (GObject		 *object);
148
static void update_color			(GtkColorSelection	 *colorsel);
149 150 151 152 153 154 155 156
static void gtk_color_selection_set_property    (GObject                 *object,
					         guint                    prop_id,
					         const GValue            *value,
					         GParamSpec              *pspec);
static void gtk_color_selection_get_property    (GObject                 *object,
					         guint                    prop_id,
					         GValue                  *value,
					         GParamSpec              *pspec);
157

158 159
static void gtk_color_selection_realize         (GtkWidget               *widget);
static void gtk_color_selection_unrealize       (GtkWidget               *widget);
160
static void gtk_color_selection_show_all        (GtkWidget               *widget);
161

162 163 164
static void     gtk_color_selection_set_palette_color   (GtkColorSelection *colorsel,
                                                         gint               index,
                                                         GdkColor          *color);
165 166
static GdkGC   *get_focus_gc                            (GtkWidget         *drawing_area,
							 gint              *focus_width);
167 168 169 170
static void     default_noscreen_change_palette_func    (const GdkColor    *colors,
							 gint               n_colors);
static void     default_change_palette_func             (GdkScreen	   *screen,
							 const GdkColor    *colors,
171
							 gint               n_colors);
172

173
static gpointer parent_class = NULL;
174 175
static guint color_selection_signals[LAST_SIGNAL] = { 0 };

176
static const gchar default_colors[] = "black:white:gray50:red:purple:blue:light blue:green:yellow:orange:lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90";
177

178 179
static GtkColorSelectionChangePaletteFunc noscreen_change_palette_hook = default_noscreen_change_palette_func;
static GtkColorSelectionChangePaletteWithScreenFunc change_palette_hook = default_change_palette_func;
180 181 182 183 184 185 186 187

/* The cursor for the dropper */
#define DROPPER_WIDTH 17
#define DROPPER_HEIGHT 17
#define DROPPER_X_HOT 2
#define DROPPER_Y_HOT 16


Matthias Clasen's avatar
Matthias Clasen committed
188
static const guchar dropper_bits[] = {
189 190 191 192 193 194
  0xff, 0x8f, 0x01, 0xff, 0x77, 0x01, 0xff, 0xfb, 0x00, 0xff, 0xf8, 0x00,
  0x7f, 0xff, 0x00, 0xff, 0x7e, 0x01, 0xff, 0x9d, 0x01, 0xff, 0xd8, 0x01,
  0x7f, 0xd4, 0x01, 0x3f, 0xee, 0x01, 0x1f, 0xff, 0x01, 0x8f, 0xff, 0x01,
  0xc7, 0xff, 0x01, 0xe3, 0xff, 0x01, 0xf3, 0xff, 0x01, 0xfd, 0xff, 0x01,
  0xff, 0xff, 0x01, };

Matthias Clasen's avatar
Matthias Clasen committed
195
static const guchar dropper_mask[] = {
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
  0x00, 0x70, 0x00, 0x00, 0xf8, 0x00, 0x00, 0xfc, 0x01, 0x00, 0xff, 0x01,
  0x80, 0xff, 0x01, 0x00, 0xff, 0x00, 0x00, 0x7f, 0x00, 0x80, 0x3f, 0x00,
  0xc0, 0x3f, 0x00, 0xe0, 0x13, 0x00, 0xf0, 0x01, 0x00, 0xf8, 0x00, 0x00,
  0x7c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x0d, 0x00, 0x00,
  0x02, 0x00, 0x00, };


/*
 *
 * The Sample Color
 *
 */
#define SAMPLE_WIDTH  64
#define SAMPLE_HEIGHT 28

static void color_sample_draw_sample (GtkColorSelection *colorsel, int which);
static void color_sample_draw_samples (GtkColorSelection *colorsel);
Elliot Lee's avatar
Elliot Lee committed
213

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
static void
set_color_internal (GtkColorSelection *colorsel,
		    gdouble           *color)
{
  ColorSelectionPrivate *priv;
  gint i;
  
  priv = colorsel->private_data;
  priv->changing = TRUE;
  priv->color[COLORSEL_RED] = color[0];
  priv->color[COLORSEL_GREEN] = color[1];
  priv->color[COLORSEL_BLUE] = color[2];
  priv->color[COLORSEL_OPACITY] = color[3];
  gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
		  priv->color[COLORSEL_GREEN],
		  priv->color[COLORSEL_BLUE],
		  &priv->color[COLORSEL_HUE],
		  &priv->color[COLORSEL_SATURATION],
		  &priv->color[COLORSEL_VALUE]);
  if (priv->default_set == FALSE)
    {
      for (i = 0; i < COLORSEL_NUM_CHANNELS; i++)
	priv->old_color[i] = priv->color[i];
    }
  priv->default_set = TRUE;
  priv->default_alpha_set = TRUE;
  update_color (colorsel);
}

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
static void
set_color_icon (GdkDragContext *context,
		gdouble        *colors)
{
  GdkPixbuf *pixbuf;
  guint32 pixel;

  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,
			   8, 48, 32);

  pixel = (((UNSCALE (colors[COLORSEL_RED])   & 0xff00) << 16) |
	   ((UNSCALE (colors[COLORSEL_GREEN]) & 0xff00) << 8) |
	   ((UNSCALE (colors[COLORSEL_BLUE])  & 0xff00)));

  gdk_pixbuf_fill (pixbuf, pixel);
  
  gtk_drag_set_icon_pixbuf (context, pixbuf, -2, -2);
Manish Singh's avatar
Manish Singh committed
260
  g_object_unref (pixbuf);
261 262
}

263
static void
264 265 266
color_sample_drag_begin (GtkWidget      *widget,
			 GdkDragContext *context,
			 gpointer        data)
Elliot Lee's avatar
Elliot Lee committed
267
{
268 269 270
  GtkColorSelection *colorsel = data;
  ColorSelectionPrivate *priv;
  gdouble *colsrc;
271
  
272
  priv = colorsel->private_data;
273
  
274 275 276 277
  if (widget == priv->old_sample)
    colsrc = priv->old_color;
  else
    colsrc = priv->color;
278 279

  set_color_icon (context, colsrc);
Elliot Lee's avatar
Elliot Lee committed
280 281
}

282
static void
283 284 285
color_sample_drag_end (GtkWidget      *widget,
		       GdkDragContext *context,
		       gpointer        data)
Elliot Lee's avatar
Elliot Lee committed
286
{
Manish Singh's avatar
Manish Singh committed
287
  g_object_set_data (G_OBJECT (widget), "gtk-color-selection-drag-window", NULL);
288
}
Elliot Lee's avatar
Elliot Lee committed
289

290 291 292 293 294 295 296 297 298 299 300 301 302 303
static void
color_sample_drop_handle (GtkWidget        *widget,
			  GdkDragContext   *context,
			  gint              x,
			  gint              y,
			  GtkSelectionData *selection_data,
			  guint             info,
			  guint             time,
			  gpointer          data)
{
  GtkColorSelection *colorsel = data;
  ColorSelectionPrivate *priv;
  guint16 *vals;
  gdouble color[4];
304
  priv = colorsel->private_data;
305
  
306 307 308 309 310 311
  /* This is currently a guint16 array of the format:
   * R
   * G
   * B
   * opacity
   */
312
  
313 314
  if (selection_data->length < 0)
    return;
315
  
316 317 318 319 320
  if ((selection_data->format != 16) ||
      (selection_data->length != 8))
    {
      g_warning ("Received invalid color data\n");
      return;
Elliot Lee's avatar
Elliot Lee committed
321
    }
322
  
323
  vals = (guint16 *)selection_data->data;
324
  
325
  if (widget == priv->cur_sample)
326
    {
327 328 329 330
      color[0] = (gdouble)vals[0] / 0xffff;
      color[1] = (gdouble)vals[1] / 0xffff;
      color[2] = (gdouble)vals[2] / 0xffff;
      color[3] = (gdouble)vals[3] / 0xffff;
331
      
332
      set_color_internal (colorsel, color);
333 334 335 336
    }
}

static void
337 338 339 340 341 342
color_sample_drag_handle (GtkWidget        *widget,
			  GdkDragContext   *context,
			  GtkSelectionData *selection_data,
			  guint             info,
			  guint             time,
			  gpointer          data)
343
{
344 345 346 347
  GtkColorSelection *colorsel = data;
  ColorSelectionPrivate *priv;
  guint16 vals[4];
  gdouble *colsrc;
348
  
349
  priv = colorsel->private_data;
350
  
351 352 353 354
  if (widget == priv->old_sample)
    colsrc = priv->old_color;
  else
    colsrc = priv->color;
355
  
356 357 358
  vals[0] = colsrc[COLORSEL_RED] * 0xffff;
  vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
  vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
359
  vals[3] = priv->has_opacity ? colsrc[COLORSEL_OPACITY] * 0xffff : 0xffff;
360
  
361 362 363
  gtk_selection_data_set (selection_data,
			  gdk_atom_intern ("application/x-color", FALSE),
			  16, (guchar *)vals, 8);
Elliot Lee's avatar
Elliot Lee committed
364 365
}

366 367 368
/* which = 0 means draw old sample, which = 1 means draw new */
static void
color_sample_draw_sample (GtkColorSelection *colorsel, int which)
Elliot Lee's avatar
Elliot Lee committed
369
{
370 371 372 373 374 375
  GtkWidget *da;
  gint x, y, i, wid, heig, f, n, goff;
  guchar c[3 * 2], cc[3 * 4], *cp = c;
  gdouble o;
  guchar *buf;
  ColorSelectionPrivate *priv;
376
  
Elliot Lee's avatar
Elliot Lee committed
377
  g_return_if_fail (colorsel != NULL);
378
  priv = colorsel->private_data;
379
  
380 381 382
  g_return_if_fail (priv->sample_area != NULL);
  if (!GTK_WIDGET_DRAWABLE (priv->sample_area))
    return;
383
  
384 385 386 387
  if (which == 0)
    {
      da = priv->old_sample;
      for (n = 0, i = COLORSEL_RED; n < 3; n++, i++)
388
	c[n] = (guchar) (UNSCALE (priv->old_color[i]) >> 8);
389 390 391 392 393 394
      goff = 0;
    }
  else
    {
      da = priv->cur_sample;
      for (n = 0, i = COLORSEL_RED; n < 3; n++, i++)
395
	c[n] = (guchar) (UNSCALE (priv->color[i]) >> 8);
396
      goff =  priv->old_sample->allocation.width % 32;
Elliot Lee's avatar
Elliot Lee committed
397
    }
398
  
399 400
  wid = da->allocation.width;
  heig = da->allocation.height;
401
  
402
  buf = g_new (guchar, 3 * wid * heig);
403
  
404 405 406 407 408 409 410 411
#if 0
  i = COLORSEL_RED;
  for (n = 0; n < 3; n++)
    {
      c[n] = (guchar) (255.0 * priv->old_color[i]);
      c[n + 3] = (guchar) (255.0 * priv->color[i++]);
    }
#endif
412
  
413
  if (priv->has_opacity)
Elliot Lee's avatar
Elliot Lee committed
414
    {
415
      o = (which) ? priv->color[COLORSEL_OPACITY] : priv->old_color[COLORSEL_OPACITY];
416
      
417 418 419 420 421 422
      for (n = 0; n < 3; n++)
	{
	  cc[n] = (guchar) ((1.0 - o) * 192 + (o * (gdouble) c[n]));
	  cc[n + 3] = (guchar) ((1.0 - o) * 128 + (o * (gdouble) c[n]));
	}
      cp = cc;
Elliot Lee's avatar
Elliot Lee committed
423
    }
424
  
425 426
  i = 0;
  for (y = 0; y < heig; y++)
Elliot Lee's avatar
Elliot Lee committed
427
    {
428 429
      for (x = 0; x < wid; x++)
	{
430
	  if (priv->has_opacity)
431 432 433
	    f = 3 * ((((goff + x) % 32) < 16) ^ ((y % 32) < 16));
	  else
	    f = 0;
434
	  
435 436 437
	  for (n = 0; n < 3; n++)
	    buf[i++] = cp[n + f];
	}
Elliot Lee's avatar
Elliot Lee committed
438
    }
439
  
440 441 442 443 444 445 446
  gdk_draw_rgb_image (da->window,
		      da->style->black_gc,
		      0, 0,
		      wid, heig,
		      GDK_RGB_DITHER_NORMAL,
		      buf,
		      3*wid);
447 448
  
  
449
  g_free (buf);
Elliot Lee's avatar
Elliot Lee committed
450 451 452
}


453 454 455 456 457 458
static void
color_sample_draw_samples (GtkColorSelection *colorsel)
{
  color_sample_draw_sample (colorsel, 0);
  color_sample_draw_sample (colorsel, 1);
}
Elliot Lee's avatar
Elliot Lee committed
459

460
static gboolean
461 462 463
color_old_sample_expose (GtkWidget         *da,
			 GdkEventExpose    *event,
			 GtkColorSelection *colorsel)
464 465
{
  color_sample_draw_sample (colorsel, 0);
466
  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
467 468
}

469

470
static gboolean
471 472 473
color_cur_sample_expose (GtkWidget         *da,
			 GdkEventExpose    *event,
			 GtkColorSelection *colorsel)
Elliot Lee's avatar
Elliot Lee committed
474
{
475
  color_sample_draw_sample (colorsel, 1);
476
  return FALSE;
477
}
478

479 480 481
static void
color_sample_setup_dnd (GtkColorSelection *colorsel, GtkWidget *sample)
{
482
  static const GtkTargetEntry targets[] = {
483 484
    { "application/x-color", 0 }
  };
485
  ColorSelectionPrivate *priv;
486
  priv = colorsel->private_data;
487
  
488
  gtk_drag_source_set (sample,
489 490 491
		       GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
		       targets, 1,
		       GDK_ACTION_COPY | GDK_ACTION_MOVE);
492
  
Manish Singh's avatar
Manish Singh committed
493 494 495 496
  g_signal_connect (sample,
		    "drag_begin",
		    G_CALLBACK (color_sample_drag_begin),
		    colorsel);
497 498
  if (sample == priv->cur_sample)
    {
499
      
500 501 502 503 504 505
      gtk_drag_dest_set (sample,
			 GTK_DEST_DEFAULT_HIGHLIGHT |
			 GTK_DEST_DEFAULT_MOTION |
			 GTK_DEST_DEFAULT_DROP,
			 targets, 1,
			 GDK_ACTION_COPY);
506
      
Manish Singh's avatar
Manish Singh committed
507 508 509 510
      g_signal_connect (sample,
			"drag_end",
			G_CALLBACK (color_sample_drag_end),
			colorsel);
511
    }
512
  
Manish Singh's avatar
Manish Singh committed
513 514 515 516 517 518 519 520
  g_signal_connect (sample,
		    "drag_data_get",
		    G_CALLBACK (color_sample_drag_handle),
		    colorsel);
  g_signal_connect (sample,
		    "drag_data_received",
		    G_CALLBACK (color_sample_drop_handle),
		    colorsel);
521
  
Elliot Lee's avatar
Elliot Lee committed
522 523
}

524

525
static void
526
color_sample_new (GtkColorSelection *colorsel)
527
{
528
  ColorSelectionPrivate *priv;
529
  
530
  priv = colorsel->private_data;
531
  
532 533 534
  priv->sample_area = gtk_hbox_new (FALSE, 0);
  priv->old_sample = gtk_drawing_area_new ();
  priv->cur_sample = gtk_drawing_area_new ();
535 536 537 538 539 540

  /* We need enter/leave to do tooltips */
  gtk_widget_add_events (priv->old_sample,
                         GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
  gtk_widget_add_events (priv->cur_sample,
                         GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
541
  
542 543 544 545
  gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->old_sample,
		      TRUE, TRUE, 0);
  gtk_box_pack_start (GTK_BOX (priv->sample_area), priv->cur_sample,
		      TRUE, TRUE, 0);
546
  
Manish Singh's avatar
Manish Singh committed
547 548 549 550 551 552
  g_signal_connect (priv->old_sample, "expose_event",
		    G_CALLBACK (color_old_sample_expose),
		    colorsel);
  g_signal_connect (priv->cur_sample, "expose_event",
		    G_CALLBACK (color_cur_sample_expose),
		    colorsel);
553
  
554 555
  color_sample_setup_dnd (colorsel, priv->old_sample);
  color_sample_setup_dnd (colorsel, priv->cur_sample);
556 557 558 559 560 561 562 563 564

  gtk_tooltips_set_tip (priv->tooltips,
                        priv->old_sample,
                        _("The previously-selected color, for comparison to the color you're selecting now. You can drag this color to a palette entry, or select this color as current by dragging it to the other color swatch alongside."), NULL);


  gtk_tooltips_set_tip (priv->tooltips,
                        priv->cur_sample,
                        _("The color you've chosen. You can drag this color to a palette entry to save it for use in the future."), NULL);
565
  
566
  gtk_widget_show_all (priv->sample_area);
Elliot Lee's avatar
Elliot Lee committed
567 568
}

569 570 571 572 573 574

/*
 *
 * The palette area code
 *
 */
575 576
#define CUSTOM_PALETTE_ENTRY_WIDTH   20
#define CUSTOM_PALETTE_ENTRY_HEIGHT  20
577

Elliot Lee's avatar
Elliot Lee committed
578
static void
579
palette_get_color (GtkWidget *drawing_area, gdouble *color)
Elliot Lee's avatar
Elliot Lee committed
580
{
581
  gdouble *color_val;
582
  
583
  g_return_if_fail (color != NULL);
584
  
Manish Singh's avatar
Manish Singh committed
585
  color_val = g_object_get_data (G_OBJECT (drawing_area), "color_val");
586
  if (color_val == NULL)
Elliot Lee's avatar
Elliot Lee committed
587
    {
588 589 590 591 592 593
      /* Default to white for no good reason */
      color[0] = 1.0;
      color[1] = 1.0;
      color[2] = 1.0;
      color[3] = 1.0;
      return;
Elliot Lee's avatar
Elliot Lee committed
594
    }
595
  
596 597 598 599
  color[0] = color_val[0];
  color[1] = color_val[1];
  color[2] = color_val[2];
  color[3] = 1.0;
Elliot Lee's avatar
Elliot Lee committed
600 601
}

602
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
Elliot Lee's avatar
Elliot Lee committed
603
static void
604 605 606
palette_paint (GtkWidget    *drawing_area,
	       GdkRectangle *area,
	       gpointer      data)
Elliot Lee's avatar
Elliot Lee committed
607
{
608 609
  if (drawing_area->window == NULL)
    return;
610
  
611 612 613 614 615
  gdk_window_clear_area (drawing_area->window,
			 area->x,
			 area->y,
			 area->width, 
			 area->height);
616
  
617
  if (GTK_WIDGET_HAS_FOCUS (drawing_area))
618
    {
619 620
      gint focus_width;
      GdkGC *gc = get_focus_gc (drawing_area, &focus_width);
621
      gdk_draw_rectangle (drawing_area->window,
622 623 624 625
			  gc, FALSE, focus_width / 2, focus_width / 2,
			  drawing_area->allocation.width - focus_width,
			  drawing_area->allocation.height - focus_width);
      g_object_unref (gc);
Elliot Lee's avatar
Elliot Lee committed
626 627 628
    }
}

629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
static GdkGC *
get_focus_gc (GtkWidget *drawing_area,
	      gint      *focus_width)
{
  GdkGC *gc = gdk_gc_new (drawing_area->window);
  gdouble color[4];
  gint8 *dash_list;
  
  gtk_widget_style_get (drawing_area,
			"focus-line-width", focus_width,
			"focus-line-pattern", (gchar *)&dash_list,
			NULL);
      
  palette_get_color (drawing_area, color);
      
  if (INTENSITY (color[0], color[1], color[2]) > 0.5)
    gdk_gc_copy (gc, drawing_area->style->black_gc);
  else
    gdk_gc_copy (gc, drawing_area->style->white_gc);

  gdk_gc_set_line_attributes (gc, *focus_width,
			      dash_list[0] ? GDK_LINE_ON_OFF_DASH : GDK_LINE_SOLID,
			      GDK_CAP_BUTT, GDK_JOIN_MITER);

  if (dash_list[0])
654
    gdk_gc_set_dashes (gc, 0, dash_list, strlen ((char *)dash_list));
655

656 657
  g_free (dash_list);
  
658 659
  return gc;
}
Elliot Lee's avatar
Elliot Lee committed
660 661

static void
662 663 664
palette_drag_begin (GtkWidget      *widget,
		    GdkDragContext *context,
		    gpointer        data)
665 666
{
  gdouble colors[4];
667
  
668
  palette_get_color (widget, colors);
669
  set_color_icon (context, colors);
670 671
}

672
static void
673 674 675 676 677 678 679 680 681
palette_drag_handle (GtkWidget        *widget,
		     GdkDragContext   *context,
		     GtkSelectionData *selection_data,
		     guint             info,
		     guint             time,
		     gpointer          data)
{
  guint16 vals[4];
  gdouble colsrc[4];
682
  
683
  palette_get_color (widget, colsrc);
684
  
685 686 687 688
  vals[0] = colsrc[COLORSEL_RED] * 0xffff;
  vals[1] = colsrc[COLORSEL_GREEN] * 0xffff;
  vals[2] = colsrc[COLORSEL_BLUE] * 0xffff;
  vals[3] = 0xffff;
689
  
690 691 692 693 694
  gtk_selection_data_set (selection_data,
			  gdk_atom_intern ("application/x-color", FALSE),
			  16, (guchar *)vals, 8);
}

695 696 697 698 699
static void
palette_drag_end (GtkWidget      *widget,
		  GdkDragContext *context,
		  gpointer        data)
{
Manish Singh's avatar
Manish Singh committed
700
  g_object_set_data (G_OBJECT (widget), "gtk-color-selection-drag-window", NULL);
701 702
}

703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
static GdkColor *
get_current_colors (GtkColorSelection *colorsel)
{
  GtkSettings *settings;
  GdkColor *colors = NULL;
  gint n_colors = 0;
  gchar *palette;

  settings = gtk_widget_get_settings (GTK_WIDGET (colorsel));
  g_object_get (G_OBJECT (settings),
		"gtk-color-palette", &palette,
		NULL);
  
  if (!gtk_color_selection_palette_from_string (palette, &colors, &n_colors))
    {
      gtk_color_selection_palette_from_string (default_colors, &colors, &n_colors);
    }
  else
    {
      /* If there are less colors provided than the number of slots in the
       * color selection, we fill in the rest from the defaults.
       */
      if (n_colors < (GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT))
	{
	  GdkColor *tmp_colors = colors;
	  gint tmp_n_colors = n_colors;
	  
	  gtk_color_selection_palette_from_string (default_colors, &colors, &n_colors);
	  memcpy (colors, tmp_colors, sizeof (GdkColor) * tmp_n_colors);

	  g_free (tmp_colors);
	}
    }

  g_assert (n_colors >= GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
  g_free (palette);
  
  return colors;
}

743 744 745 746 747 748 749 750 751
/* Changes the model color */
static void
palette_change_color (GtkWidget         *drawing_area,
                      GtkColorSelection *colorsel,
                      gdouble           *color)
{
  gint x, y;
  ColorSelectionPrivate *priv;
  GdkColor gdk_color;
752 753
  GdkColor *current_colors;
  GdkScreen *screen;
754 755 756 757 758 759

  g_return_if_fail (GTK_IS_COLOR_SELECTION (colorsel));
  g_return_if_fail (GTK_IS_DRAWING_AREA (drawing_area));
  
  priv = colorsel->private_data;
  
760 761 762
  gdk_color.red = UNSCALE (color[0]);
  gdk_color.green = UNSCALE (color[1]);
  gdk_color.blue = UNSCALE (color[2]);
763 764

  x = 0;
765
  y = 0;			/* Quiet GCC */
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
  while (x < GTK_CUSTOM_PALETTE_WIDTH)
    {
      y = 0;
      while (y < GTK_CUSTOM_PALETTE_HEIGHT)
        {
          if (priv->custom_palette[x][y] == drawing_area)
            goto out;
          
          ++y;
        }

      ++x;
    }

 out:
  
  g_assert (x < GTK_CUSTOM_PALETTE_WIDTH || y < GTK_CUSTOM_PALETTE_HEIGHT);

784
  current_colors = get_current_colors (colorsel);
785 786
  current_colors[y * GTK_CUSTOM_PALETTE_WIDTH + x] = gdk_color;

787 788 789 790 791 792
  screen = gtk_widget_get_screen (GTK_WIDGET (colorsel));
  if (change_palette_hook != default_change_palette_func)
    (* change_palette_hook) (screen, current_colors, 
			     GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
  else if (noscreen_change_palette_hook != default_noscreen_change_palette_func)
    {
Owen Taylor's avatar
Owen Taylor committed
793
      if (screen != gdk_screen_get_default ())
794 795 796 797 798 799 800 801 802
	g_warning ("gtk_color_selection_set_change_palette_hook used by widget is not on the default screen.");
      (* noscreen_change_palette_hook) (current_colors, 
					GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);
    }
  else
    (* change_palette_hook) (screen, current_colors, 
			     GTK_CUSTOM_PALETTE_WIDTH * GTK_CUSTOM_PALETTE_HEIGHT);

  g_free (current_colors);
803 804 805
}

/* Changes the view color */
806
static void
807 808 809
palette_set_color (GtkWidget         *drawing_area,
		   GtkColorSelection *colorsel,
		   gdouble           *color)
810 811
{
  gdouble *new_color = g_new (double, 4);
812
  GdkColor gdk_color;
813
  
814 815 816
  gdk_color.red = UNSCALE (color[0]);
  gdk_color.green = UNSCALE (color[1]);
  gdk_color.blue = UNSCALE (color[2]);
817 818

  gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &gdk_color);
819
  
Manish Singh's avatar
Manish Singh committed
820
  if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) == 0)
821 822 823 824 825 826 827 828
    {
      static const GtkTargetEntry targets[] = {
	{ "application/x-color", 0 }
      };
      gtk_drag_source_set (drawing_area,
			   GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
			   targets, 1,
			   GDK_ACTION_COPY | GDK_ACTION_MOVE);
829
      
Manish Singh's avatar
Manish Singh committed
830 831 832 833 834 835 836 837
      g_signal_connect (drawing_area,
			"drag_begin",
			G_CALLBACK (palette_drag_begin),
			colorsel);
      g_signal_connect (drawing_area,
			"drag_data_get",
			G_CALLBACK (palette_drag_handle),
			colorsel);
838
      
Manish Singh's avatar
Manish Singh committed
839 840
      g_object_set_data (G_OBJECT (drawing_area), "color_set",
			 GINT_TO_POINTER (1));
841
    }
842

843 844 845 846
  new_color[0] = color[0];
  new_color[1] = color[1];
  new_color[2] = color[2];
  new_color[3] = 1.0;
847
  
848
  g_object_set_data_full (G_OBJECT (drawing_area), "color_val", new_color, (GDestroyNotify)g_free);
849 850
}

851
static gboolean
852 853 854
palette_expose (GtkWidget      *drawing_area,
		GdkEventExpose *event,
		gpointer        data)
855
{
856
  if (drawing_area->window == NULL)
857
    return FALSE;
858 859
  
  palette_paint (drawing_area, &(event->area), data);
860 861
  
  return FALSE;
862 863 864 865 866 867 868 869 870 871 872 873
}

static void
popup_position_func (GtkMenu   *menu,
                     gint      *x,
                     gint      *y,
                     gboolean  *push_in,
                     gpointer	user_data)
{
  GtkWidget *widget;
  GtkRequisition req;      
  gint root_x, root_y;
874
  GdkScreen *screen;
875 876 877 878 879 880 881 882 883 884 885 886 887 888
  
  widget = GTK_WIDGET (user_data);
  
  g_return_if_fail (GTK_WIDGET_REALIZED (widget));

  gdk_window_get_origin (widget->window, &root_x, &root_y);
  
  gtk_widget_size_request (GTK_WIDGET (menu), &req);

  /* Put corner of menu centered on color cell */
  *x = root_x + widget->allocation.width / 2;
  *y = root_y + widget->allocation.height / 2;

  /* Ensure sanity */
889 890 891
  screen = gtk_widget_get_screen (widget);
  *x = CLAMP (*x, 0, MAX (0, gdk_screen_get_width (screen) - req.width));
  *y = CLAMP (*y, 0, MAX (0, gdk_screen_get_height (screen) - req.height));
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
}

static void
save_color_selected (GtkWidget *menuitem,
                     gpointer   data)
{
  GtkColorSelection *colorsel;
  GtkWidget *drawing_area;
  ColorSelectionPrivate *priv;

  drawing_area = GTK_WIDGET (data);
  
  colorsel = GTK_COLOR_SELECTION (g_object_get_data (G_OBJECT (drawing_area),
                                                     "gtk-color-sel"));

  priv = colorsel->private_data;
  
  palette_change_color (drawing_area, colorsel, priv->color);  
}

static void
do_popup (GtkColorSelection *colorsel,
          GtkWidget         *drawing_area,
          guint32            timestamp)
{
  GtkWidget *menu;
  GtkWidget *mi;
  
  g_object_set_data (G_OBJECT (drawing_area),
                     "gtk-color-sel",
                     colorsel);
  
  menu = gtk_menu_new ();

926
  mi = gtk_menu_item_new_with_mnemonic (_("_Save color here"));
927

Manish Singh's avatar
Manish Singh committed
928 929 930
  g_signal_connect (mi, "activate",
                    G_CALLBACK (save_color_selected),
                    drawing_area);
931 932 933 934 935 936 937 938 939 940 941
  
  gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);

  gtk_widget_show_all (mi);

  gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
                  popup_position_func, drawing_area,
                  3, timestamp);
}


942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
static gboolean
palette_enter (GtkWidget        *drawing_area,
	       GdkEventCrossing *event,
	       gpointer        data)
{
  g_object_set_data (G_OBJECT (drawing_area),
		     "gtk-colorsel-have-pointer",
		     GUINT_TO_POINTER (TRUE));

  return FALSE;
}

static gboolean
palette_leave (GtkWidget        *drawing_area,
	       GdkEventCrossing *event,
	       gpointer        data)
{
  g_object_set_data (G_OBJECT (drawing_area),
		     "gtk-colorsel-have-pointer",
		     NULL);

  return FALSE;
}

static gboolean
967 968 969 970 971 972 973 974
palette_press (GtkWidget      *drawing_area,
	       GdkEventButton *event,
	       gpointer        data)
{
  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);

  gtk_widget_grab_focus (drawing_area);
  
975
  if (event->button == 3 &&
976
      event->type == GDK_BUTTON_PRESS)
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
    {
      do_popup (colorsel, drawing_area, event->time);
      return TRUE;
    }

  return FALSE;
}

static gboolean
palette_release (GtkWidget      *drawing_area,
		 GdkEventButton *event,
		 gpointer        data)
{
  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);

  gtk_widget_grab_focus (drawing_area);

  if (event->button == 1 &&
      g_object_get_data (G_OBJECT (drawing_area),
			 "gtk-colorsel-have-pointer") != NULL)
    {
Manish Singh's avatar
Manish Singh committed
998
      if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (drawing_area), "color_set")) != 0)
999 1000 1001
        {
          gdouble color[4];
          palette_get_color (drawing_area, color);
1002
          set_color_internal (colorsel, color);
1003 1004
        }
    }
1005 1006

  return FALSE;
1007 1008
}

1009
static void
1010 1011 1012 1013 1014 1015 1016 1017
palette_drop_handle (GtkWidget        *widget,
		     GdkDragContext   *context,
		     gint              x,
		     gint              y,
		     GtkSelectionData *selection_data,
		     guint             info,
		     guint             time,
		     gpointer          data)
Elliot Lee's avatar
Elliot Lee committed
1018
{
1019
  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);
1020
  guint16 *vals;
1021
  gdouble color[4];
1022
  
1023 1024
  if (selection_data->length < 0)
    return;
1025
  
1026
  if ((selection_data->format != 16) ||
1027 1028 1029 1030 1031
      (selection_data->length != 8))
    {
      g_warning ("Received invalid color data\n");
      return;
    }
1032
  
1033
  vals = (guint16 *)selection_data->data;
1034
  
1035 1036 1037 1038
  color[0] = (gdouble)vals[0] / 0xffff;
  color[1] = (gdouble)vals[1] / 0xffff;
  color[2] = (gdouble)vals[2] / 0xffff;
  color[3] = (gdouble)vals[3] / 0xffff;
1039 1040
  palette_change_color (widget, colorsel, color);
  set_color_internal (colorsel, color);
1041 1042
}

1043 1044 1045 1046
static gint
palette_activate (GtkWidget   *widget,
		  GdkEventKey *event,
		  gpointer     data)
1047
{
1048
  /* should have a drawing area subclass with an activate signal */
1049 1050 1051 1052
  if ((event->keyval == GDK_space) ||
      (event->keyval == GDK_Return) ||
      (event->keyval == GDK_KP_Enter) ||
      (event->keyval == GDK_KP_Space))
1053
    {
Manish Singh's avatar
Manish Singh committed
1054
      if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "color_set")) != 0)
1055 1056 1057
        {
          gdouble color[4];
          palette_get_color (widget, color);
1058
          set_color_internal (GTK_COLOR_SELECTION (data), color);
1059
        }
1060
      return TRUE;
1061
    }
1062
  
1063
  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1064 1065
}

1066
static gboolean
1067 1068 1069 1070 1071 1072
palette_popup (GtkWidget *widget,
               gpointer   data)
{
  GtkColorSelection *colorsel = GTK_COLOR_SELECTION (data);

  do_popup (colorsel, widget, GDK_CURRENT_TIME);
1073
  return TRUE;
1074 1075 1076
}
               

1077
static GtkWidget*
1078
palette_new (GtkColorSelection *colorsel)
Elliot Lee's avatar
Elliot Lee committed
1079
{
1080
  GtkWidget *retval;
1081
  ColorSelectionPrivate *priv;
1082 1083 1084 1085
  
  static const GtkTargetEntry targets[] = {
    { "application/x-color", 0 }
  };
1086 1087

  priv = colorsel->private_data;
1088
  
1089
  retval = gtk_drawing_area_new ();
1090 1091 1092

  GTK_WIDGET_SET_FLAGS (retval, GTK_CAN_FOCUS);
  
Manish Singh's avatar
Manish Singh committed
1093
  g_object_set_data (G_OBJECT (retval), "color_set", GINT_TO_POINTER (0)); 
1094 1095 1096 1097 1098
  gtk_widget_set_events (retval, GDK_BUTTON_PRESS_MASK
                         | GDK_BUTTON_RELEASE_MASK
                         | GDK_EXPOSURE_MASK
                         | GDK_ENTER_NOTIFY_MASK
                         | GDK_LEAVE_NOTIFY_MASK);
1099
  
Manish Singh's avatar
Manish Singh committed
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
  g_signal_connect (retval, "expose_event",
		    G_CALLBACK (palette_expose), colorsel);
  g_signal_connect (retval, "button_press_event",
		    G_CALLBACK (palette_press), colorsel);
  g_signal_connect (retval, "button_release_event",
		    G_CALLBACK (palette_release), colorsel);
  g_signal_connect (retval, "enter_notify_event",
		    G_CALLBACK (palette_enter), colorsel);
  g_signal_connect (retval, "leave_notify_event",
		    G_CALLBACK (palette_leave), colorsel);
  g_signal_connect (retval, "key_press_event",
		    G_CALLBACK (palette_activate), colorsel);
  g_signal_connect (retval, "popup_menu",
		    G_CALLBACK (palette_popup), colorsel);
1114
  
1115 1116 1117 1118 1119 1120
  gtk_drag_dest_set (retval,
		     GTK_DEST_DEFAULT_HIGHLIGHT |
		     GTK_DEST_DEFAULT_MOTION |
		     GTK_DEST_DEFAULT_DROP,
		     targets, 1,
		     GDK_ACTION_COPY);
1121
  
Manish Singh's avatar
Manish Singh committed
1122 1123 1124 1125
  g_signal_connect (retval, "drag_end",
                    G_CALLBACK (palette_drag_end), NULL);
  g_signal_connect (retval, "drag_data_received",
                    G_CALLBACK (palette_drop_handle), colorsel);
1126 1127 1128

  gtk_tooltips_set_tip (priv->tooltips,
                        retval,
Havoc Pennington's avatar
Havoc Pennington committed
1129
                        _("Click this palette entry to make it the current color. To change this entry, drag a color swatch here or right-click it and select \"Save color here.\""),
1130
                        NULL);
1131 1132
  return retval;
}
1133

Elliot Lee's avatar
Elliot Lee committed
1134

1135 1136 1137 1138 1139
/*
 *
 * The actual GtkColorSelection widget
 *
 */
Elliot Lee's avatar
Elliot Lee committed
1140

1141 1142
static GdkCursor *
make_picker_cursor (GdkScreen *screen)
Elliot Lee's avatar
Elliot Lee committed
1143
{
1144
  GdkCursor *cursor;
Manish Singh's avatar
Manish Singh committed
1145 1146 1147
  GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
  GdkColor fg = { 0, 0x0000, 0x0000, 0x0000 };
  GdkWindow *window = gdk_screen_get_root_window (screen);
1148
  
1149
  GdkPixmap *pixmap =
Manish Singh's avatar
Manish Singh committed
1150 1151
    gdk_bitmap_create_from_data (window, (gchar *) dropper_bits,
				 DROPPER_WIDTH, DROPPER_HEIGHT);
1152

1153
  GdkPixmap *mask =
Manish Singh's avatar
Manish Singh committed
1154 1155
    gdk_bitmap_create_from_data (window, (gchar *) dropper_mask,
				 DROPPER_WIDTH, DROPPER_HEIGHT);
1156

Manish Singh's avatar
Manish Singh committed
1157 1158
  cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg,
				       DROPPER_X_HOT, DROPPER_Y_HOT);
1159
  
Manish Singh's avatar
Manish Singh committed
1160 1161
  g_object_unref (pixmap);
  g_object_unref (mask);
1162 1163

  return cursor;
Elliot Lee's avatar
Elliot Lee committed
1164 1165 1166
}

static void
1167
grab_color_at_mouse (GdkScreen *screen,
1168 1169 1170
		     gint       x_root,
		     gint       y_root,
		     gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
1171
{
1172 1173 1174 1175
  GdkImage *image;
  guint32 pixel;
  GtkColorSelection *colorsel = data;
  ColorSelectionPrivate *priv;
1176
  GdkColor color;
1177 1178
  GdkColormap *colormap = gdk_screen_get_system_colormap (screen);
  GdkWindow *root_window = gdk_screen_get_root_window (screen);
1179
  
1180
  priv = colorsel->private_data;
1181
  
Manish Singh's avatar
Manish Singh committed
1182
  image = gdk_drawable_get_image (root_window, x_root, y_root, 1, 1);
1183
  pixel = gdk_image_get_pixel (image, 0, 0);
Manish Singh's avatar
Manish Singh committed
1184
  g_object_unref (image);
1185 1186 1187

  gdk_colormap_query_color (colormap, pixel, &color);
  
1188 1189 1190
  priv->color[COLORSEL_RED] = SCALE (color.red);
  priv->color[COLORSEL_GREEN] = SCALE (color.green);
  priv->color[COLORSEL_BLUE] = SCALE (color.blue);
1191
  
1192 1193 1194 1195 1196 1197
  gtk_rgb_to_hsv (priv->color[COLORSEL_RED],
		  priv->color[COLORSEL_GREEN],
		  priv->color[COLORSEL_BLUE],
		  &priv->color[COLORSEL_HUE],
		  &priv->color[COLORSEL_SATURATION],
		  &priv->color[COLORSEL_VALUE]);
1198

1199 1200
  update_color (colorsel);
}
Elliot Lee's avatar
Elliot Lee committed
1201

1202
static void
1203 1204 1205 1206
shutdown_eyedropper (GtkWidget *widget)
{
  GtkColorSelection *colorsel;
  ColorSelectionPrivate *priv;
1207 1208
  GdkDisplay *display = gtk_widget_get_display (widget);
  guint32 time = gtk_get_current_event_time ();
1209 1210 1211 1212

  colorsel = GTK_COLOR_SELECTION (widget);
  priv = colorsel->private_data;    

1213 1214
  gdk_display_keyboard_ungrab (display, time);
  gdk_display_pointer_ungrab (display, time);
1215 1216 1217 1218 1219
  gtk_grab_remove (priv->dropper_grab_widget);
}

static void
mouse_motion (GtkWidget      *invisible,
1220 1221
	      GdkEventMotion *event,
	      gpointer        data)
1222
{
1223 1224
  grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
		       event->x_root, event->y_root, data); 
Elliot Lee's avatar
Elliot Lee committed
1225 1226
}

1227
static gboolean
1228
mouse_release (GtkWidget      *invisible,
1229 1230
	       GdkEventButton *event,
	       gpointer        data)
Elliot Lee's avatar
Elliot Lee committed
1231
{
1232 1233
  GtkColorSelection *colorsel = data;
  ColorSelectionPrivate *priv;
1234 1235
  priv = colorsel->private_data;  

1236 1237 1238
  if (event->button != 1)
    return FALSE;

1239 1240
  grab_color_at_mouse (gdk_event_get_screen ((GdkEvent *)event),
		       event->x_root, event->y_root, data);
1241 1242 1243

  shutdown_eyedropper (GTK_WIDGET (data));
  
Manish Singh's avatar
Manish Singh committed
1244 1245 1246 1247 1248 1249
  g_signal_handlers_disconnect_by_func (invisible,
					mouse_motion,
					data);
  g_signal_handlers_disconnect_by_func (invisible,
					mouse_release,
					data);
1250

1251
  return TRUE;
1252
}
Elliot Lee's avatar
Elliot Lee committed
1253

1254
/* Helper Functions */
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268

static gboolean mouse_press (GtkWidget      *invisible,
                             GdkEventButton *event,
                             gpointer        data);

static gboolean
key_press (GtkWidget   *invisible,
           GdkEventKey *event,
           gpointer     data)
{  
  if (event->keyval == GDK_Escape)
    {
      shutdown_eyedropper (data);

Manish Singh's avatar
Manish Singh committed
1269 1270 1271 1272 1273 1274
      g_signal_handlers_disconnect_by_func (invisible,
					    mouse_press,
					    data);
      g_signal_handlers_disconnect_by_func (invisible,
					    key_press,
					    data);
1275 1276 1277 1278 1279 1280 1281
      
      return TRUE;
    }

  return FALSE;
}

1282
static gboolean
1283
mouse_press (GtkWidget      *invisible,
1284 1285
	     GdkEventButton *event,
	     gpointer        data)
1286 1287 1288
{
  GtkColorSelection *colorsel = data;
  ColorSelectionPrivate *priv;
1289
  priv = colorsel->private_data;
1290 1291 1292 1293
  
  if (event->type == GDK_BUTTON_PRESS &&
      event->button == 1)
    {
Manish Singh's avatar
Manish Singh committed
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
      g_signal_connect (invisible, "motion_notify_event",
                        G_CALLBACK (mouse_motion),
                        data);
      g_signal_connect (invisible, "button_release_event",
                        G_CALLBACK (mouse_release),
                        data);
      g_signal_handlers_disconnect_by_func (invisible,
					    mouse_press,
					    data);
      g_signal_handlers_disconnect_by_func (invisible,
					    key_press,
					    data);
1306 1307
      return TRUE;
    }
1308

1309
  return FALSE;
Elliot Lee's avatar
Elliot Lee committed
1310 1311
}

1312
/* when the button is clicked */
Elliot Lee's avatar
Elliot Lee committed
1313
static void
1314
get_screen_color (GtkWidget *button)
Elliot Lee's avatar
Elliot Lee committed
1315
{
Manish Singh's avatar
Manish Singh committed
1316
  GtkColorSelection *colorsel = g_object_get_data (G_OBJECT (button), "COLORSEL");
1317 1318 1319 1320
  ColorSelectionPrivate *priv = colorsel->private_data;
  GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (button));
  GdkCursor *picker_cursor;
  GdkGrabStatus grab_status;
1321
  
1322
  if (priv->dropper_grab_widget == NULL)
1323
    {
1324
      priv->dropper_grab_widget = gtk_invisible_new_for_screen (screen);
1325

1326 1327
      gtk_widget_add_events (priv->dropper_grab_widget,
                             GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
1328
      
1329
      gtk_widget_show (priv->dropper_grab_widget);
1330
    }
1331 1332 1333 1334

  if (gdk_keyboard_grab (priv->dropper_grab_widget->window,
                         FALSE,
                         gtk_get_current_event_time ()) != GDK_GRAB_SUCCESS)
1335
    return;
1336
  
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
  picker_cursor = make_picker_cursor (screen);
  grab_status = gdk_pointer_grab (priv->dropper_grab_widget->window,
				  FALSE,
				  GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK,
				  NULL,
				  picker_cursor,
				  gtk_get_current_event_time ());
  gdk_cursor_unref (picker_cursor);
  
  if (grab_status != GDK_GRAB_SUCCESS)
1347
    {
1348
      gdk_display_keyboard_ungrab (gtk_widget_get_display (button), GDK_CURRENT_TIME);
1349 1350 1351 1352 1353
      return;
    }

  gtk_grab_add (priv->dropper_grab_widget);
  
Manish Singh's avatar
Manish Singh committed
1354 1355 1356 1357
  g_signal_connect (priv->dropper_grab_widget, "button_press_event",
                    G_CALLBACK (mouse_press), colorsel);
  g_signal_connect (priv->dropper_grab_widget, "key_press_event",
                    G_CALLBACK (key_press), colorsel);
1358
}
Elliot Lee's avatar
Elliot Lee committed
1359

Havoc Pennington's avatar
Havoc Pennington committed
1360
static void
1361 1362
hex_changed (GtkWidget *hex_entry,
	     gpointer   data)
1363 1364 1365 1366 1367
{
  GtkColorSelection *colorsel;
  ColorSelectionPrivate *priv;
  GdkColor color;
  gchar *text;
1368
  
1369
  colorsel = GTK_COLOR_SELECTION (data);
1370
  priv = colorsel->private_data;
1371
  
1372 1373
  if (priv->changing)
    return;
1374
  
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389
  text = gtk_editable_get_chars (GTK_EDITABLE (priv->hex_entry), 0, -1);
  if (gdk_color_parse (text, &color))
    {
      priv->color[COLORSEL_RED] = CLAMP (color.red/65280.0, 0.0, 1.0);
      priv->color[COLORSEL_GREEN] = CLAMP (color.green/65280.0, 0.0, 1.0);
      priv->color[COLORSEL_BLUE] = CLAMP (color.blue/65280.0, 0.0, 1.0);
      gtk_rgb_to_hsv