Bug Summary

File:ctk/ctkhsv.c
Warning:line 655, column 20
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkhsv.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-170037-43636-1 -x c ctkhsv.c
1/* HSV color selector for CTK+
2 *
3 * Copyright (C) 1999 The Free Software Foundation
4 *
5 * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code)
6 * Federico Mena-Quintero <federico@gimp.org> (cleanup for CTK+)
7 * Jonathan Blandford <jrb@redhat.com> (cleanup for CTK+)
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * Modified by the CTK+ Team and others 1997-2000. See the AUTHORS
25 * file for a list of people on the CTK+ Team. See the ChangeLog
26 * files for a list of changes. These files are distributed with
27 * CTK+ at ftp://ftp.ctk.org/pub/ctk/.
28 */
29
30#include "config.h"
31
32#include <math.h>
33#include <string.h>
34
35#include "ctkhsv.h"
36#include "ctkbindings.h"
37#include "ctkmarshalers.h"
38#include "ctkrender.h"
39#include "ctkstylecontext.h"
40#include "ctktypebuiltins.h"
41#include "ctkintl.h"
42
43
44/**
45 * SECTION:ctkhsv
46 * @Short_description: A “color wheel” widget
47 * @Title: CtkHSV
48 * @See_also: #CtkColorSelection, #CtkColorSelectionDialog
49 *
50 * #CtkHSV is the “color wheel” part of a complete color selector widget.
51 * It allows to select a color by determining its HSV components in an
52 * intuitive way. Moving the selection around the outer ring changes the hue,
53 * and moving the selection point inside the inner triangle changes value and
54 * saturation.
55 */
56
57
58/* Default width/height */
59#define DEFAULT_SIZE100 100
60
61/* Default ring width */
62#define DEFAULT_RING_WIDTH10 10
63
64
65/* Dragging modes */
66typedef enum {
67 DRAG_NONE,
68 DRAG_H,
69 DRAG_SV
70} DragMode;
71
72/* Private part of the CtkHSV structure */
73struct _CtkHSVPrivate
74{
75 /* Color value */
76 double h;
77 double s;
78 double v;
79
80 /* Size and ring width */
81 int size;
82 int ring_width;
83
84 /* Window for capturing events */
85 CdkWindow *window;
86
87 /* Dragging mode */
88 DragMode mode;
89
90 guint focus_on_ring : 1;
91};
92
93
94/* Signal IDs */
95
96enum {
97 CHANGED,
98 MOVE,
99 LAST_SIGNAL
100};
101
102static void ctk_hsv_destroy (CtkWidget *widget);
103static void ctk_hsv_realize (CtkWidget *widget);
104static void ctk_hsv_unrealize (CtkWidget *widget);
105static void ctk_hsv_get_preferred_width (CtkWidget *widget,
106 gint *minimum,
107 gint *natural);
108static void ctk_hsv_get_preferred_height (CtkWidget *widget,
109 gint *minimum,
110 gint *natural);
111static void ctk_hsv_size_allocate (CtkWidget *widget,
112 CtkAllocation *allocation);
113static gboolean ctk_hsv_button_press (CtkWidget *widget,
114 CdkEventButton *event);
115static gboolean ctk_hsv_button_release (CtkWidget *widget,
116 CdkEventButton *event);
117static gboolean ctk_hsv_motion (CtkWidget *widget,
118 CdkEventMotion *event);
119static gboolean ctk_hsv_draw (CtkWidget *widget,
120 cairo_t *cr);
121static gboolean ctk_hsv_grab_broken (CtkWidget *widget,
122 CdkEventGrabBroken *event);
123static gboolean ctk_hsv_focus (CtkWidget *widget,
124 CtkDirectionType direction);
125static void ctk_hsv_move (CtkHSV *hsv,
126 CtkDirectionType dir);
127
128static guint hsv_signals[LAST_SIGNAL];
129
130G_DEFINE_TYPE_WITH_PRIVATE (CtkHSV, ctk_hsv, CTK_TYPE_WIDGET)static void ctk_hsv_init (CtkHSV *self); static void ctk_hsv_class_init
(CtkHSVClass *klass); static GType ctk_hsv_get_type_once (void
); static gpointer ctk_hsv_parent_class = ((void*)0); static gint
CtkHSV_private_offset; static void ctk_hsv_class_intern_init
(gpointer klass) { ctk_hsv_parent_class = g_type_class_peek_parent
(klass); if (CtkHSV_private_offset != 0) g_type_class_adjust_private_offset
(klass, &CtkHSV_private_offset); ctk_hsv_class_init ((CtkHSVClass
*) klass); } __attribute__ ((__unused__)) static inline gpointer
ctk_hsv_get_instance_private (CtkHSV *self) { return (((gpointer
) ((guint8*) (self) + (glong) (CtkHSV_private_offset)))); } GType
ctk_hsv_get_type (void) { static GType static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) * (&static_g_define_type_id) : ((void*)
0)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter_pointer (
&static_g_define_type_id)); })) ) { GType g_define_type_id
= ctk_hsv_get_type_once (); (__extension__ ({ _Static_assert
(sizeof *(&static_g_define_type_id) == sizeof (gpointer)
, "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id
) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer
((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id
)); })) ; } return static_g_define_type_id; } __attribute__ (
(__noinline__)) static GType ctk_hsv_get_type_once (void) { GType
g_define_type_id = g_type_register_static_simple ((ctk_widget_get_type
()), g_intern_static_string ("CtkHSV"), sizeof (CtkHSVClass)
, (GClassInitFunc)(void (*)(void)) ctk_hsv_class_intern_init,
sizeof (CtkHSV), (GInstanceInitFunc)(void (*)(void)) ctk_hsv_init
, (GTypeFlags) 0); { {{ CtkHSV_private_offset = g_type_add_instance_private
(g_define_type_id, sizeof (CtkHSVPrivate)); };} } return g_define_type_id
; }
131
132/* Class initialization function for the HSV color selector */
133static void
134ctk_hsv_class_init (CtkHSVClass *class)
135{
136 GObjectClass *gobject_class;
137 CtkWidgetClass *widget_class;
138 CtkHSVClass *hsv_class;
139 CtkBindingSet *binding_set;
140
141 gobject_class = (GObjectClass *) class;
142 widget_class = (CtkWidgetClass *) class;
143 hsv_class = CTK_HSV_CLASS (class)((((CtkHSVClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), ((ctk_hsv_get_type ()))))))
;
144
145 widget_class->destroy = ctk_hsv_destroy;
146 widget_class->realize = ctk_hsv_realize;
147 widget_class->unrealize = ctk_hsv_unrealize;
148 widget_class->get_preferred_width = ctk_hsv_get_preferred_width;
149 widget_class->get_preferred_height = ctk_hsv_get_preferred_height;
150 widget_class->size_allocate = ctk_hsv_size_allocate;
151 widget_class->button_press_event = ctk_hsv_button_press;
152 widget_class->button_release_event = ctk_hsv_button_release;
153 widget_class->motion_notify_event = ctk_hsv_motion;
154 widget_class->draw = ctk_hsv_draw;
155 widget_class->focus = ctk_hsv_focus;
156 widget_class->grab_broken_event = ctk_hsv_grab_broken;
157
158 ctk_widget_class_set_accessible_role (widget_class, ATK_ROLE_COLOR_CHOOSER);
159
160 hsv_class->move = ctk_hsv_move;
161
162 hsv_signals[CHANGED] =
163 g_signal_new (I_("changed")g_intern_static_string ("changed"),
164 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
165 G_SIGNAL_RUN_FIRST,
166 G_STRUCT_OFFSET (CtkHSVClass, changed)((glong) __builtin_offsetof(CtkHSVClass, changed)),
167 NULL((void*)0), NULL((void*)0),
168 NULL((void*)0),
169 G_TYPE_NONE((GType) ((1) << (2))), 0);
170
171 hsv_signals[MOVE] =
172 g_signal_new (I_("move")g_intern_static_string ("move"),
173 G_OBJECT_CLASS_TYPE (gobject_class)((((GTypeClass*) (gobject_class))->g_type)),
174 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
175 G_STRUCT_OFFSET (CtkHSVClass, move)((glong) __builtin_offsetof(CtkHSVClass, move)),
176 NULL((void*)0), NULL((void*)0),
177 NULL((void*)0),
178 G_TYPE_NONE((GType) ((1) << (2))), 1,
179 CTK_TYPE_DIRECTION_TYPE(ctk_direction_type_get_type ()));
180
181 binding_set = ctk_binding_set_by_class (class);
182
183 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Up0xff52, 0,
184 "move", 1,
185 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_UP);
186 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Up0xff97, 0,
187 "move", 1,
188 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_UP);
189 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Down0xff54, 0,
190 "move", 1,
191 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_DOWN);
192 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Down0xff99, 0,
193 "move", 1,
194 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_DOWN);
195 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Right0xff53, 0,
196 "move", 1,
197 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_RIGHT);
198 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Right0xff98, 0,
199 "move", 1,
200 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_RIGHT);
201 ctk_binding_entry_add_signal (binding_set, CDK_KEY_Left0xff51, 0,
202 "move", 1,
203 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_LEFT);
204 ctk_binding_entry_add_signal (binding_set, CDK_KEY_KP_Left0xff96, 0,
205 "move", 1,
206 G_TYPE_ENUM((GType) ((12) << (2))), CTK_DIR_LEFT);
207}
208
209static void
210ctk_hsv_init (CtkHSV *hsv)
211{
212 CtkHSVPrivate *priv;
213
214 priv = ctk_hsv_get_instance_private (hsv);
215 hsv->priv = priv;
216
217 ctk_widget_set_has_window (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
, FALSE(0));
218 ctk_widget_set_can_focus (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
, TRUE(!(0)));
219
220 priv->h = 0.0;
221 priv->s = 0.0;
222 priv->v = 0.0;
223
224 priv->size = DEFAULT_SIZE100;
225 priv->ring_width = DEFAULT_RING_WIDTH10;
226}
227
228static void
229ctk_hsv_destroy (CtkWidget *widget)
230{
231 CTK_WIDGET_CLASS (ctk_hsv_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_hsv_parent_class)), ((ctk_widget_get_type ()))))))
->destroy (widget);
232}
233
234static void
235ctk_hsv_realize (CtkWidget *widget)
236{
237 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
238 CtkHSVPrivate *priv = hsv->priv;
239 CtkAllocation allocation;
240 CdkWindow *parent_window;
241 CdkWindowAttr attr;
242 int attr_mask;
243
244 ctk_widget_set_realized (widget, TRUE(!(0)));
245
246 ctk_widget_get_allocation (widget, &allocation);
247
248 attr.window_type = CDK_WINDOW_CHILD;
249 attr.x = allocation.x;
250 attr.y = allocation.y;
251 attr.width = allocation.width;
252 attr.height = allocation.height;
253 attr.wclass = CDK_INPUT_ONLY;
254 attr.event_mask = ctk_widget_get_events (widget);
255 attr.event_mask |= (CDK_KEY_PRESS_MASK
256 | CDK_BUTTON_PRESS_MASK
257 | CDK_BUTTON_RELEASE_MASK
258 | CDK_POINTER_MOTION_MASK
259 | CDK_ENTER_NOTIFY_MASK
260 | CDK_LEAVE_NOTIFY_MASK);
261 attr_mask = CDK_WA_X | CDK_WA_Y;
262
263 parent_window = ctk_widget_get_parent_window (widget);
264 ctk_widget_set_window (widget, parent_window);
265 g_object_ref (parent_window)((__typeof__ (parent_window)) (g_object_ref) (parent_window));
266
267 priv->window = cdk_window_new (parent_window, &attr, attr_mask);
268 cdk_window_set_user_data (priv->window, hsv);
269 cdk_window_show (priv->window);
270}
271
272static void
273ctk_hsv_unrealize (CtkWidget *widget)
274{
275 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
276 CtkHSVPrivate *priv = hsv->priv;
277
278 cdk_window_set_user_data (priv->window, NULL((void*)0));
279 cdk_window_destroy (priv->window);
280 priv->window = NULL((void*)0);
281
282 CTK_WIDGET_CLASS (ctk_hsv_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((ctk_hsv_parent_class)), ((ctk_widget_get_type ()))))))
->unrealize (widget);
283}
284
285static void
286ctk_hsv_get_preferred_width (CtkWidget *widget,
287 gint *minimum,
288 gint *natural)
289{
290 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
291 CtkHSVPrivate *priv = hsv->priv;
292 gint focus_width;
293 gint focus_pad;
294
295 ctk_widget_style_get (widget,
296 "focus-line-width", &focus_width,
297 "focus-padding", &focus_pad,
298 NULL((void*)0));
299
300 *minimum = priv->size + 2 * (focus_width + focus_pad);
301 *natural = priv->size + 2 * (focus_width + focus_pad);
302}
303
304static void
305ctk_hsv_get_preferred_height (CtkWidget *widget,
306 gint *minimum,
307 gint *natural)
308{
309 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
310 CtkHSVPrivate *priv = hsv->priv;
311 gint focus_width;
312 gint focus_pad;
313
314 ctk_widget_style_get (widget,
315 "focus-line-width", &focus_width,
316 "focus-padding", &focus_pad,
317 NULL((void*)0));
318
319 *minimum = priv->size + 2 * (focus_width + focus_pad);
320 *natural = priv->size + 2 * (focus_width + focus_pad);
321}
322
323static void
324ctk_hsv_size_allocate (CtkWidget *widget,
325 CtkAllocation *allocation)
326{
327 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
328 CtkHSVPrivate *priv = hsv->priv;
329
330 ctk_widget_set_allocation (widget, allocation);
331
332 if (ctk_widget_get_realized (widget))
333 cdk_window_move_resize (priv->window,
334 allocation->x,
335 allocation->y,
336 allocation->width,
337 allocation->height);
338}
339
340
341/* Utility functions */
342
343#define INTENSITY(r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
344
345/* Converts from HSV to RGB */
346static void
347hsv_to_rgb (gdouble *h,
348 gdouble *s,
349 gdouble *v)
350{
351 gdouble hue, saturation, value;
352 gdouble f, p, q, t;
353
354 if (*s == 0.0)
355 {
356 *h = *v;
357 *s = *v;
358 *v = *v; /* heh */
359 }
360 else
361 {
362 hue = *h * 6.0;
363 saturation = *s;
364 value = *v;
365
366 if (hue == 6.0)
367 hue = 0.0;
368
369 f = hue - (int) hue;
370 p = value * (1.0 - saturation);
371 q = value * (1.0 - saturation * f);
372 t = value * (1.0 - saturation * (1.0 - f));
373
374 switch ((int) hue)
375 {
376 case 0:
377 *h = value;
378 *s = t;
379 *v = p;
380 break;
381
382 case 1:
383 *h = q;
384 *s = value;
385 *v = p;
386 break;
387
388 case 2:
389 *h = p;
390 *s = value;
391 *v = t;
392 break;
393
394 case 3:
395 *h = p;
396 *s = q;
397 *v = value;
398 break;
399
400 case 4:
401 *h = t;
402 *s = p;
403 *v = value;
404 break;
405
406 case 5:
407 *h = value;
408 *s = p;
409 *v = q;
410 break;
411
412 default:
413 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkhsv.c", 413, ((const
char*) (__func__)), ((void*)0)); } while (0)
;
414 }
415 }
416}
417
418/* Computes the vertices of the saturation/value triangle */
419static void
420compute_triangle (CtkHSV *hsv,
421 gint *hx,
422 gint *hy,
423 gint *sx,
424 gint *sy,
425 gint *vx,
426 gint *vy)
427{
428 CtkHSVPrivate *priv = hsv->priv;
429 CtkWidget *widget = CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
;
430 gdouble center_x;
431 gdouble center_y;
432 gdouble inner, outer;
433 gdouble angle;
434
435 center_x = ctk_widget_get_allocated_width (widget) / 2.0;
436 center_y = ctk_widget_get_allocated_height (widget) / 2.0;
437 outer = priv->size / 2.0;
438 inner = outer - priv->ring_width;
439 angle = priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
440
441 *hx = floor (center_x + cos (angle) * inner + 0.5);
442 *hy = floor (center_y - sin (angle) * inner + 0.5);
443 *sx = floor (center_x + cos (angle + 2.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
444 *sy = floor (center_y - sin (angle + 2.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
445 *vx = floor (center_x + cos (angle + 4.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
446 *vy = floor (center_y - sin (angle + 4.0 * G_PI3.1415926535897932384626433832795028841971693993751 / 3.0) * inner + 0.5);
447}
448
449/* Computes whether a point is inside the hue ring */
450static gboolean
451is_in_ring (CtkHSV *hsv,
452 gdouble x,
453 gdouble y)
454{
455 CtkHSVPrivate *priv = hsv->priv;
456 CtkWidget *widget = CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
;
457 gdouble dx, dy, dist;
458 gdouble center_x;
459 gdouble center_y;
460 gdouble inner, outer;
461
462 center_x = ctk_widget_get_allocated_width (widget) / 2.0;
463 center_y = ctk_widget_get_allocated_height (widget) / 2.0;
464 outer = priv->size / 2.0;
465 inner = outer - priv->ring_width;
466
467 dx = x - center_x;
468 dy = center_y - y;
469 dist = dx * dx + dy * dy;
470
471 return (dist >= inner * inner && dist <= outer * outer);
472}
473
474/* Computes a saturation/value pair based on the mouse coordinates */
475static void
476compute_sv (CtkHSV *hsv,
477 gdouble x,
478 gdouble y,
479 gdouble *s,
480 gdouble *v)
481{
482 CtkWidget *widget = CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
;
483 int ihx, ihy, isx, isy, ivx, ivy;
484 double hx, hy, sx, sy, vx, vy;
485 double center_x;
486 double center_y;
487
488 compute_triangle (hsv, &ihx, &ihy, &isx, &isy, &ivx, &ivy);
489 center_x = ctk_widget_get_allocated_width (widget) / 2.0;
490 center_y = ctk_widget_get_allocated_height (widget) / 2.0;
491 hx = ihx - center_x;
492 hy = center_y - ihy;
493 sx = isx - center_x;
494 sy = center_y - isy;
495 vx = ivx - center_x;
496 vy = center_y - ivy;
497 x -= center_x;
498 y = center_y - y;
499
500 if (vx * (x - sx) + vy * (y - sy) < 0.0)
501 {
502 *s = 1.0;
503 *v = (((x - sx) * (hx - sx) + (y - sy) * (hy-sy))
504 / ((hx - sx) * (hx - sx) + (hy - sy) * (hy - sy)));
505
506 if (*v < 0.0)
507 *v = 0.0;
508 else if (*v > 1.0)
509 *v = 1.0;
510 }
511 else if (hx * (x - sx) + hy * (y - sy) < 0.0)
512 {
513 *s = 0.0;
514 *v = (((x - sx) * (vx - sx) + (y - sy) * (vy - sy))
515 / ((vx - sx) * (vx - sx) + (vy - sy) * (vy - sy)));
516
517 if (*v < 0.0)
518 *v = 0.0;
519 else if (*v > 1.0)
520 *v = 1.0;
521 }
522 else if (sx * (x - hx) + sy * (y - hy) < 0.0)
523 {
524 *v = 1.0;
525 *s = (((x - vx) * (hx - vx) + (y - vy) * (hy - vy)) /
526 ((hx - vx) * (hx - vx) + (hy - vy) * (hy - vy)));
527
528 if (*s < 0.0)
529 *s = 0.0;
530 else if (*s > 1.0)
531 *s = 1.0;
532 }
533 else
534 {
535 *v = (((x - sx) * (hy - vy) - (y - sy) * (hx - vx))
536 / ((vx - sx) * (hy - vy) - (vy - sy) * (hx - vx)));
537
538 if (*v<= 0.0)
539 {
540 *v = 0.0;
541 *s = 0.0;
542 }
543 else
544 {
545 if (*v > 1.0)
546 *v = 1.0;
547
548 if (fabs (hy - vy) < fabs (hx - vx))
549 *s = (x - sx - *v * (vx - sx)) / (*v * (hx - vx));
550 else
551 *s = (y - sy - *v * (vy - sy)) / (*v * (hy - vy));
552
553 if (*s < 0.0)
554 *s = 0.0;
555 else if (*s > 1.0)
556 *s = 1.0;
557 }
558 }
559}
560
561/* Computes whether a point is inside the saturation/value triangle */
562static gboolean
563is_in_triangle (CtkHSV *hsv,
564 gdouble x,
565 gdouble y)
566{
567 int hx, hy, sx, sy, vx, vy;
568 double det, s, v;
569
570 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
571
572 det = (vx - sx) * (hy - sy) - (vy - sy) * (hx - sx);
573
574 s = ((x - sx) * (hy - sy) - (y - sy) * (hx - sx)) / det;
575 v = ((vx - sx) * (y - sy) - (vy - sy) * (x - sx)) / det;
576
577 return (s >= 0.0 && v >= 0.0 && s + v <= 1.0);
578}
579
580/* Computes a value based on the mouse coordinates */
581static double
582compute_v (CtkHSV *hsv,
583 gdouble x,
584 gdouble y)
585{
586 CtkWidget *widget = CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
;
587 double center_x;
588 double center_y;
589 double dx, dy;
590 double angle;
591
592 center_x = ctk_widget_get_allocated_width (widget) / 2.0;
593 center_y = ctk_widget_get_allocated_height (widget) / 2.0;
594 dx = x - center_x;
595 dy = center_y - y;
596
597 angle = atan2 (dy, dx);
598 if (angle < 0.0)
599 angle += 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
600
601 return angle / (2.0 * G_PI3.1415926535897932384626433832795028841971693993751);
602}
603
604/* Event handlers */
605
606static void
607set_cross_grab (CtkHSV *hsv,
608 CdkDevice *device,
609 guint32 time G_GNUC_UNUSED__attribute__ ((__unused__)))
610{
611 CtkHSVPrivate *priv = hsv->priv;
612 CdkCursor *cursor;
613
614 cursor = cdk_cursor_new_for_display (ctk_widget_get_display (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
),
615 CDK_CROSSHAIR);
616 cdk_seat_grab (cdk_device_get_seat (device),
617 priv->window,
618 CDK_SEAT_CAPABILITY_ALL_POINTING,
619 FALSE(0),
620 cursor,
621 NULL((void*)0),
622 NULL((void*)0),
623 NULL((void*)0));
624 g_object_unref (cursor);
625}
626
627static gboolean
628ctk_hsv_grab_broken (CtkWidget *widget,
629 CdkEventGrabBroken *event G_GNUC_UNUSED__attribute__ ((__unused__)))
630{
631 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
632 CtkHSVPrivate *priv = hsv->priv;
633
634 priv->mode = DRAG_NONE;
635
636 return TRUE(!(0));
637}
638
639static gint
640ctk_hsv_button_press (CtkWidget *widget,
641 CdkEventButton *event)
642{
643 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
644 CtkHSVPrivate *priv = hsv->priv;
645 double x, y;
646
647 if (priv->mode != DRAG_NONE || event->button != CDK_BUTTON_PRIMARY(1))
648 return FALSE(0);
649
650 x = event->x;
651 y = event->y;
652
653 if (is_in_ring (hsv, x, y))
654 {
655 priv->mode = DRAG_H;
This statement is never executed
656 set_cross_grab (hsv, cdk_event_get_device ((CdkEvent *) event), event->time);
657
658 ctk_hsv_set_color (hsv,
659 compute_v (hsv, x, y),
660 priv->s,
661 priv->v);
662
663 ctk_widget_grab_focus (widget);
664 priv->focus_on_ring = TRUE(!(0));
665
666 return TRUE(!(0));
667 }
668
669 if (is_in_triangle (hsv, x, y))
670 {
671 gdouble s, v;
672
673 priv->mode = DRAG_SV;
674 set_cross_grab (hsv, cdk_event_get_device ((CdkEvent *) event), event->time);
675
676 compute_sv (hsv, x, y, &s, &v);
677 ctk_hsv_set_color (hsv, priv->h, s, v);
678
679 ctk_widget_grab_focus (widget);
680 priv->focus_on_ring = FALSE(0);
681
682 return TRUE(!(0));
683 }
684
685 return FALSE(0);
686}
687
688static gint
689ctk_hsv_button_release (CtkWidget *widget,
690 CdkEventButton *event)
691{
692 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
693 CtkHSVPrivate *priv = hsv->priv;
694 DragMode mode;
695 gdouble x, y;
696
697 if (priv->mode == DRAG_NONE || event->button != CDK_BUTTON_PRIMARY(1))
698 return FALSE(0);
699
700 /* Set the drag mode to DRAG_NONE so that signal handlers for "catched"
701 * can see that this is the final color state.
702 */
703 mode = priv->mode;
704 priv->mode = DRAG_NONE;
705
706 x = event->x;
707 y = event->y;
708
709 if (mode == DRAG_H)
710 {
711 ctk_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v);
712 }
713 else if (mode == DRAG_SV)
714 {
715 gdouble s, v;
716
717 compute_sv (hsv, x, y, &s, &v);
718 ctk_hsv_set_color (hsv, priv->h, s, v);
719 }
720 else
721 {
722 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkhsv.c", 722, ((const
char*) (__func__)), ((void*)0)); } while (0)
;
723 }
724
725 cdk_seat_ungrab (cdk_device_get_seat (cdk_event_get_device ((CdkEvent *) event)));
726
727 return TRUE(!(0));
728}
729
730static gint
731ctk_hsv_motion (CtkWidget *widget,
732 CdkEventMotion *event)
733{
734 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
735 CtkHSVPrivate *priv = hsv->priv;
736 gdouble x, y;
737
738 if (priv->mode == DRAG_NONE)
739 return FALSE(0);
740
741 cdk_event_request_motions (event);
742 x = event->x;
743 y = event->y;
744
745 if (priv->mode == DRAG_H)
746 {
747 ctk_hsv_set_color (hsv, compute_v (hsv, x, y), priv->s, priv->v);
748 return TRUE(!(0));
749 }
750 else if (priv->mode == DRAG_SV)
751 {
752 gdouble s, v;
753
754 compute_sv (hsv, x, y, &s, &v);
755 ctk_hsv_set_color (hsv, priv->h, s, v);
756 return TRUE(!(0));
757 }
758
759 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkhsv.c", 759, ((const
char*) (__func__)), ((void*)0)); } while (0)
;
760
761 return FALSE(0);
762}
763
764
765/* Redrawing */
766
767/* Paints the hue ring */
768static void
769paint_ring (CtkHSV *hsv,
770 cairo_t *cr)
771{
772 CtkHSVPrivate *priv = hsv->priv;
773 CtkWidget *widget = CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
;
774 int xx, yy, width, height;
775 gdouble dx, dy, dist;
776 gdouble center_x;
777 gdouble center_y;
778 gdouble inner, outer;
779 guint32 *buf;
780 gdouble angle;
781 gdouble hue;
782 gdouble r, g, b;
783 cairo_surface_t *source;
784 cairo_t *source_cr;
785 gint stride;
786
787 width = ctk_widget_get_allocated_width (widget);
788 height = ctk_widget_get_allocated_height (widget);
789
790 center_x = width / 2.0;
791 center_y = height / 2.0;
792
793 outer = priv->size / 2.0;
794 inner = outer - priv->ring_width;
795
796 /* Create an image initialized with the ring colors */
797
798 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
799 buf = g_new (guint32, height * stride / 4)((guint32 *) g_malloc_n ((height * stride / 4), sizeof (guint32
)))
;
800
801 for (yy = 0; yy < height; yy++)
802 {
803 guint32 *p;
804
805 p = buf + yy * width;
806
807 dy = -(yy - center_y);
808
809 for (xx = 0; xx < width; xx++)
810 {
811 dx = xx - center_x;
812
813 dist = dx * dx + dy * dy;
814 if (dist < ((inner-1) * (inner-1)) || dist > ((outer+1) * (outer+1)))
815 {
816 *p++ = 0;
817 continue;
818 }
819
820 angle = atan2 (dy, dx);
821 if (angle < 0.0)
822 angle += 2.0 * G_PI3.1415926535897932384626433832795028841971693993751;
823
824 hue = angle / (2.0 * G_PI3.1415926535897932384626433832795028841971693993751);
825
826 r = hue;
827 g = 1.0;
828 b = 1.0;
829 hsv_to_rgb (&r, &g, &b);
830
831 *p++ = (((int)floor (r * 255 + 0.5) << 16) |
832 ((int)floor (g * 255 + 0.5) << 8) |
833 (int)floor (b * 255 + 0.5));
834 }
835 }
836
837 source = cairo_image_surface_create_for_data ((unsigned char *)buf,
838 CAIRO_FORMAT_RGB24,
839 width, height, stride);
840
841 /* Now draw the value marker onto the source image, so that it
842 * will get properly clipped at the edges of the ring
843 */
844 source_cr = cairo_create (source);
845
846 r = priv->h;
847 g = 1.0;
848 b = 1.0;
849 hsv_to_rgb (&r, &g, &b);
850
851 if (INTENSITY (r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) > 0.5)
852 cairo_set_source_rgb (source_cr, 0., 0., 0.);
853 else
854 cairo_set_source_rgb (source_cr, 1., 1., 1.);
855
856 cairo_move_to (source_cr, center_x, center_y);
857 cairo_line_to (source_cr,
858 center_x + cos (priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751) * priv->size / 2,
859 center_y - sin (priv->h * 2.0 * G_PI3.1415926535897932384626433832795028841971693993751) * priv->size / 2);
860 cairo_stroke (source_cr);
861 cairo_destroy (source_cr);
862
863 /* Draw the ring using the source image */
864
865 cairo_save (cr);
866
867 cairo_set_source_surface (cr, source, 0, 0);
868 cairo_surface_destroy (source);
869
870 cairo_set_line_width (cr, priv->ring_width);
871 cairo_new_path (cr);
872 cairo_arc (cr,
873 center_x, center_y,
874 priv->size / 2. - priv->ring_width / 2.,
875 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751);
876 cairo_stroke (cr);
877
878 cairo_restore (cr);
879
880 g_free (buf);
881}
882
883/* Converts an HSV triplet to an integer RGB triplet */
884static void
885get_color (gdouble h,
886 gdouble s,
887 gdouble v,
888 gint *r,
889 gint *g,
890 gint *b)
891{
892 hsv_to_rgb (&h, &s, &v);
893
894 *r = floor (h * 255 + 0.5);
895 *g = floor (s * 255 + 0.5);
896 *b = floor (v * 255 + 0.5);
897}
898
899#define SWAP(a, b, t)((t) = (a), (a) = (b), (b) = (t)) ((t) = (a), (a) = (b), (b) = (t))
900
901#define LERP(a, b, v1, v2, i)(((v2) - (v1) != 0) ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2
) - (v1))) : (a))
(((v2) - (v1) != 0) \
902 ? ((a) + ((b) - (a)) * ((i) - (v1)) / ((v2) - (v1))) \
903 : (a))
904
905/* Number of pixels we extend out from the edges when creating
906 * color source to avoid artifacts
907 */
908#define PAD3 3
909
910/* Paints the HSV triangle */
911static void
912paint_triangle (CtkHSV *hsv,
913 cairo_t *cr,
914 gboolean draw_focus)
915{
916 CtkHSVPrivate *priv = hsv->priv;
917 CtkWidget *widget = CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
;
918 gint hx, hy, sx, sy, vx, vy; /* HSV vertices */
919 gint x1, y1, r1, g1, b1; /* First vertex in scanline order */
920 gint x2, y2, r2, g2, b2; /* Second vertex */
921 gint x3, y3, r3, g3, b3; /* Third vertex */
922 gint t;
923 guint32 *buf, c;
924 gint xl, xr, rl, rr, gl, gr, bl, br; /* Scanline data */
925 gint xx, yy;
926 gint x_interp, y_interp;
927 gint x_start, x_end;
928 cairo_surface_t *source;
929 gdouble r, g, b;
930 gint stride;
931 int width, height;
932 CtkStyleContext *context;
933
934 width = ctk_widget_get_allocated_width (widget);
935 height = ctk_widget_get_allocated_height (widget);
936 /* Compute triangle's vertices */
937
938 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
939
940 x1 = hx;
941 y1 = hy;
942 get_color (priv->h, 1.0, 1.0, &r1, &g1, &b1);
943
944 x2 = sx;
945 y2 = sy;
946 get_color (priv->h, 1.0, 0.0, &r2, &g2, &b2);
947
948 x3 = vx;
949 y3 = vy;
950 get_color (priv->h, 0.0, 1.0, &r3, &g3, &b3);
951
952 if (y2 > y3)
953 {
954 SWAP (x2, x3, t)((t) = (x2), (x2) = (x3), (x3) = (t));
955 SWAP (y2, y3, t)((t) = (y2), (y2) = (y3), (y3) = (t));
956 SWAP (r2, r3, t)((t) = (r2), (r2) = (r3), (r3) = (t));
957 SWAP (g2, g3, t)((t) = (g2), (g2) = (g3), (g3) = (t));
958 SWAP (b2, b3, t)((t) = (b2), (b2) = (b3), (b3) = (t));
959 }
960
961 if (y1 > y3)
962 {
963 SWAP (x1, x3, t)((t) = (x1), (x1) = (x3), (x3) = (t));
964 SWAP (y1, y3, t)((t) = (y1), (y1) = (y3), (y3) = (t));
965 SWAP (r1, r3, t)((t) = (r1), (r1) = (r3), (r3) = (t));
966 SWAP (g1, g3, t)((t) = (g1), (g1) = (g3), (g3) = (t));
967 SWAP (b1, b3, t)((t) = (b1), (b1) = (b3), (b3) = (t));
968 }
969
970 if (y1 > y2)
971 {
972 SWAP (x1, x2, t)((t) = (x1), (x1) = (x2), (x2) = (t));
973 SWAP (y1, y2, t)((t) = (y1), (y1) = (y2), (y2) = (t));
974 SWAP (r1, r2, t)((t) = (r1), (r1) = (r2), (r2) = (t));
975 SWAP (g1, g2, t)((t) = (g1), (g1) = (g2), (g2) = (t));
976 SWAP (b1, b2, t)((t) = (b1), (b1) = (b2), (b2) = (t));
977 }
978
979 /* Shade the triangle */
980
981 stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
982 buf = g_new (guint32, height * stride / 4)((guint32 *) g_malloc_n ((height * stride / 4), sizeof (guint32
)))
;
983
984 for (yy = 0; yy < height; yy++)
985 {
986 guint32 *p;
987
988 p = buf + yy * width;
989
990 if (yy >= y1 - PAD3 && yy < y3 + PAD3) {
991 y_interp = CLAMP (yy, y1, y3)(((yy) > (y3)) ? (y3) : (((yy) < (y1)) ? (y1) : (yy)));
992
993 if (y_interp < y2)
994 {
995 xl = LERP (x1, x2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((x1) + ((x2) - (x1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (x1))
;
996
997 rl = LERP (r1, r2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((r1) + ((r2) - (r1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (r1))
;
998 gl = LERP (g1, g2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((g1) + ((g2) - (g1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (g1))
;
999 bl = LERP (b1, b2, y1, y2, y_interp)(((y2) - (y1) != 0) ? ((b1) + ((b2) - (b1)) * ((y_interp) - (
y1)) / ((y2) - (y1))) : (b1))
;
1000 }
1001 else
1002 {
1003 xl = LERP (x2, x3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((x2) + ((x3) - (x2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (x2))
;
1004
1005 rl = LERP (r2, r3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((r2) + ((r3) - (r2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (r2))
;
1006 gl = LERP (g2, g3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((g2) + ((g3) - (g2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (g2))
;
1007 bl = LERP (b2, b3, y2, y3, y_interp)(((y3) - (y2) != 0) ? ((b2) + ((b3) - (b2)) * ((y_interp) - (
y2)) / ((y3) - (y2))) : (b2))
;
1008 }
1009
1010 xr = LERP (x1, x3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((x1) + ((x3) - (x1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (x1))
;
1011
1012 rr = LERP (r1, r3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((r1) + ((r3) - (r1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (r1))
;
1013 gr = LERP (g1, g3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((g1) + ((g3) - (g1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (g1))
;
1014 br = LERP (b1, b3, y1, y3, y_interp)(((y3) - (y1) != 0) ? ((b1) + ((b3) - (b1)) * ((y_interp) - (
y1)) / ((y3) - (y1))) : (b1))
;
1015
1016 if (xl > xr)
1017 {
1018 SWAP (xl, xr, t)((t) = (xl), (xl) = (xr), (xr) = (t));
1019 SWAP (rl, rr, t)((t) = (rl), (rl) = (rr), (rr) = (t));
1020 SWAP (gl, gr, t)((t) = (gl), (gl) = (gr), (gr) = (t));
1021 SWAP (bl, br, t)((t) = (bl), (bl) = (br), (br) = (t));
1022 }
1023
1024 x_start = MAX (xl - PAD, 0)(((xl - 3) > (0)) ? (xl - 3) : (0));
1025 x_end = MIN (xr + PAD, width)(((xr + 3) < (width)) ? (xr + 3) : (width));
1026 x_start = MIN (x_start, x_end)(((x_start) < (x_end)) ? (x_start) : (x_end));
1027
1028 c = (rl << 16) | (gl << 8) | bl;
1029
1030 for (xx = 0; xx < x_start; xx++)
1031 *p++ = c;
1032
1033 for (; xx < x_end; xx++)
1034 {
1035 x_interp = CLAMP (xx, xl, xr)(((xx) > (xr)) ? (xr) : (((xx) < (xl)) ? (xl) : (xx)));
1036
1037 *p++ = ((LERP (rl, rr, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((rl) + ((rr) - (rl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (rl))
<< 16) |
1038 (LERP (gl, gr, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((gl) + ((gr) - (gl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (gl))
<< 8) |
1039 LERP (bl, br, xl, xr, x_interp)(((xr) - (xl) != 0) ? ((bl) + ((br) - (bl)) * ((x_interp) - (
xl)) / ((xr) - (xl))) : (bl))
);
1040 }
1041
1042 c = (rr << 16) | (gr << 8) | br;
1043
1044 for (; xx < width; xx++)
1045 *p++ = c;
1046 }
1047 }
1048
1049 source = cairo_image_surface_create_for_data ((unsigned char *)buf,
1050 CAIRO_FORMAT_RGB24,
1051 width, height, stride);
1052
1053 /* Draw a triangle with the image as a source */
1054
1055 cairo_set_source_surface (cr, source, 0, 0);
1056 cairo_surface_destroy (source);
1057
1058 cairo_move_to (cr, x1, y1);
1059 cairo_line_to (cr, x2, y2);
1060 cairo_line_to (cr, x3, y3);
1061 cairo_close_path (cr);
1062 cairo_fill (cr);
1063
1064 g_free (buf);
1065
1066 /* Draw value marker */
1067
1068 xx = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
1069 yy = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5);
1070
1071 r = priv->h;
1072 g = priv->s;
1073 b = priv->v;
1074 hsv_to_rgb (&r, &g, &b);
1075
1076 context = ctk_widget_get_style_context (widget);
1077
1078 ctk_style_context_save (context);
1079
1080 if (INTENSITY (r, g, b)((r) * 0.30 + (g) * 0.59 + (b) * 0.11) > 0.5)
1081 {
1082 ctk_style_context_add_class (context, "light-area-focus");
1083 cairo_set_source_rgb (cr, 0., 0., 0.);
1084 }
1085 else
1086 {
1087 ctk_style_context_add_class (context, "dark-area-focus");
1088 cairo_set_source_rgb (cr, 1., 1., 1.);
1089 }
1090
1091#define RADIUS4 4
1092#define FOCUS_RADIUS6 6
1093
1094 cairo_new_path (cr);
1095 cairo_arc (cr, xx, yy, RADIUS4, 0, 2 * G_PI3.1415926535897932384626433832795028841971693993751);
1096 cairo_stroke (cr);
1097
1098 /* Draw focus outline */
1099
1100 if (draw_focus && !priv->focus_on_ring)
1101 {
1102 gint focus_width;
1103 gint focus_pad;
1104
1105 ctk_widget_style_get (widget,
1106 "focus-line-width", &focus_width,
1107 "focus-padding", &focus_pad,
1108 NULL((void*)0));
1109
1110 ctk_render_focus (context, cr,
1111 xx - FOCUS_RADIUS6 - focus_width - focus_pad,
1112 yy - FOCUS_RADIUS6 - focus_width - focus_pad,
1113 2 * (FOCUS_RADIUS6 + focus_width + focus_pad),
1114 2 * (FOCUS_RADIUS6 + focus_width + focus_pad));
1115 }
1116
1117 ctk_style_context_restore (context);
1118}
1119
1120/* Paints the contents of the HSV color selector */
1121static gboolean
1122ctk_hsv_draw (CtkWidget *widget,
1123 cairo_t *cr)
1124{
1125 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
1126 CtkHSVPrivate *priv = hsv->priv;
1127 gboolean draw_focus;
1128
1129 draw_focus = ctk_widget_has_visible_focus (widget);
1130
1131 paint_ring (hsv, cr);
1132 paint_triangle (hsv, cr, draw_focus);
1133
1134
1135 if (draw_focus && priv->focus_on_ring)
1136 {
1137 CtkStyleContext *context;
1138
1139 context = ctk_widget_get_style_context (widget);
1140
1141 ctk_render_focus (context, cr, 0, 0,
1142 ctk_widget_get_allocated_width (widget),
1143 ctk_widget_get_allocated_height (widget));
1144 }
1145
1146 return FALSE(0);
1147}
1148
1149static gboolean
1150ctk_hsv_focus (CtkWidget *widget,
1151 CtkDirectionType dir)
1152{
1153 CtkHSV *hsv = CTK_HSV (widget)((((CtkHSV*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((ctk_hsv_get_type ()))))))
;
1154 CtkHSVPrivate *priv = hsv->priv;
1155
1156 if (!ctk_widget_has_focus (widget))
1157 {
1158 if (dir == CTK_DIR_TAB_BACKWARD)
1159 priv->focus_on_ring = FALSE(0);
1160 else
1161 priv->focus_on_ring = TRUE(!(0));
1162
1163 ctk_widget_grab_focus (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
);
1164 return TRUE(!(0));
1165 }
1166
1167 switch (dir)
1168 {
1169 case CTK_DIR_UP:
1170 if (priv->focus_on_ring)
1171 return FALSE(0);
1172 else
1173 priv->focus_on_ring = TRUE(!(0));
1174 break;
1175
1176 case CTK_DIR_DOWN:
1177 if (priv->focus_on_ring)
1178 priv->focus_on_ring = FALSE(0);
1179 else
1180 return FALSE(0);
1181 break;
1182
1183 case CTK_DIR_LEFT:
1184 case CTK_DIR_TAB_BACKWARD:
1185 if (priv->focus_on_ring)
1186 return FALSE(0);
1187 else
1188 priv->focus_on_ring = TRUE(!(0));
1189 break;
1190
1191 case CTK_DIR_RIGHT:
1192 case CTK_DIR_TAB_FORWARD:
1193 if (priv->focus_on_ring)
1194 priv->focus_on_ring = FALSE(0);
1195 else
1196 return FALSE(0);
1197 break;
1198 }
1199
1200 ctk_widget_queue_draw (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
);
1201
1202 return TRUE(!(0));
1203}
1204
1205/**
1206 * ctk_hsv_new:
1207 *
1208 * Creates a new HSV color selector.
1209 *
1210 * Returns: A newly-created HSV color selector.
1211 *
1212 * Since: 2.14
1213 */
1214CtkWidget*
1215ctk_hsv_new (void)
1216{
1217 return g_object_new (CTK_TYPE_HSV(ctk_hsv_get_type ()), NULL((void*)0));
1218}
1219
1220/**
1221 * ctk_hsv_set_color:
1222 * @hsv: An HSV color selector
1223 * @h: Hue
1224 * @s: Saturation
1225 * @v: Value
1226 *
1227 * Sets the current color in an HSV color selector.
1228 * Color component values must be in the [0.0, 1.0] range.
1229 *
1230 * Since: 2.14
1231 */
1232void
1233ctk_hsv_set_color (CtkHSV *hsv,
1234 gdouble h,
1235 gdouble s,
1236 gdouble v)
1237{
1238 CtkHSVPrivate *priv;
1239
1240 g_return_if_fail (CTK_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((ctk_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_HSV (hsv)"); return; } } while (0)
;
1241 g_return_if_fail (h >= 0.0 && h <= 1.0)do { if ((h >= 0.0 && h <= 1.0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "h >= 0.0 && h <= 1.0"
); return; } } while (0)
;
1242 g_return_if_fail (s >= 0.0 && s <= 1.0)do { if ((s >= 0.0 && s <= 1.0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "s >= 0.0 && s <= 1.0"
); return; } } while (0)
;
1243 g_return_if_fail (v >= 0.0 && v <= 1.0)do { if ((v >= 0.0 && v <= 1.0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "v >= 0.0 && v <= 1.0"
); return; } } while (0)
;
1244
1245 priv = hsv->priv;
1246
1247 priv->h = h;
1248 priv->s = s;
1249 priv->v = v;
1250
1251 g_signal_emit (hsv, hsv_signals[CHANGED], 0);
1252
1253 ctk_widget_queue_draw (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
);
1254}
1255
1256/**
1257 * ctk_hsv_get_color:
1258 * @hsv: An HSV color selector
1259 * @h: (out): Return value for the hue
1260 * @s: (out): Return value for the saturation
1261 * @v: (out): Return value for the value
1262 *
1263 * Queries the current color in an HSV color selector.
1264 * Returned values will be in the [0.0, 1.0] range.
1265 *
1266 * Since: 2.14
1267 */
1268void
1269ctk_hsv_get_color (CtkHSV *hsv,
1270 double *h,
1271 double *s,
1272 double *v)
1273{
1274 CtkHSVPrivate *priv;
1275
1276 g_return_if_fail (CTK_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((ctk_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_HSV (hsv)"); return; } } while (0)
;
1277
1278 priv = hsv->priv;
1279
1280 if (h)
1281 *h = priv->h;
1282
1283 if (s)
1284 *s = priv->s;
1285
1286 if (v)
1287 *v = priv->v;
1288}
1289
1290/**
1291 * ctk_hsv_set_metrics:
1292 * @hsv: An HSV color selector
1293 * @size: Diameter for the hue ring
1294 * @ring_width: Width of the hue ring
1295 *
1296 * Sets the size and ring width of an HSV color selector.
1297 *
1298 * Since: 2.14
1299 */
1300void
1301ctk_hsv_set_metrics (CtkHSV *hsv,
1302 gint size,
1303 gint ring_width)
1304{
1305 CtkHSVPrivate *priv;
1306 int same_size;
1307
1308 g_return_if_fail (CTK_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((ctk_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_HSV (hsv)"); return; } } while (0)
;
1309 g_return_if_fail (size > 0)do { if ((size > 0)) { } else { g_return_if_fail_warning (
"Ctk", ((const char*) (__func__)), "size > 0"); return; } }
while (0)
;
1310 g_return_if_fail (ring_width > 0)do { if ((ring_width > 0)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "ring_width > 0"); return
; } } while (0)
;
1311 g_return_if_fail (2 * ring_width + 1 <= size)do { if ((2 * ring_width + 1 <= size)) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "2 * ring_width + 1 <= size"
); return; } } while (0)
;
1312
1313 priv = hsv->priv;
1314
1315 same_size = (priv->size == size);
1316
1317 priv->size = size;
1318 priv->ring_width = ring_width;
1319
1320 if (same_size)
1321 ctk_widget_queue_draw (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
);
1322 else
1323 ctk_widget_queue_resize (CTK_WIDGET (hsv)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((hsv)), ((ctk_widget_get_type ()))))))
);
1324}
1325
1326/**
1327 * ctk_hsv_get_metrics:
1328 * @hsv: An HSV color selector
1329 * @size: (out): Return value for the diameter of the hue ring
1330 * @ring_width: (out): Return value for the width of the hue ring
1331 *
1332 * Queries the size and ring width of an HSV color selector.
1333 *
1334 * Since: 2.14
1335 */
1336void
1337ctk_hsv_get_metrics (CtkHSV *hsv,
1338 gint *size,
1339 gint *ring_width)
1340{
1341 CtkHSVPrivate *priv;
1342
1343 g_return_if_fail (CTK_IS_HSV (hsv))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((ctk_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_HSV (hsv)"); return; } } while (0)
;
1344
1345 priv = hsv->priv;
1346
1347 if (size)
1348 *size = priv->size;
1349
1350 if (ring_width)
1351 *ring_width = priv->ring_width;
1352}
1353
1354/**
1355 * ctk_hsv_is_adjusting:
1356 * @hsv: A #CtkHSV
1357 *
1358 * An HSV color selector can be said to be adjusting if multiple rapid
1359 * changes are being made to its value, for example, when the user is
1360 * adjusting the value with the mouse. This function queries whether
1361 * the HSV color selector is being adjusted or not.
1362 *
1363 * Returns: %TRUE if clients can ignore changes to the color value,
1364 * since they may be transitory, or %FALSE if they should consider
1365 * the color value status to be final.
1366 *
1367 * Since: 2.14
1368 */
1369gboolean
1370ctk_hsv_is_adjusting (CtkHSV *hsv)
1371{
1372 CtkHSVPrivate *priv;
1373
1374 g_return_val_if_fail (CTK_IS_HSV (hsv), FALSE)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((hsv)); GType __t = ((ctk_hsv_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_HSV (hsv)"); return ((0)); } } while (0)
;
1375
1376 priv = hsv->priv;
1377
1378 return priv->mode != DRAG_NONE;
1379}
1380
1381static void
1382ctk_hsv_move (CtkHSV *hsv,
1383 CtkDirectionType dir)
1384{
1385 CtkHSVPrivate *priv = hsv->priv;
1386 gdouble hue, sat, val;
1387 gint hx, hy, sx, sy, vx, vy; /* HSV vertices */
1388 gint x, y; /* position in triangle */
1389
1390 hue = priv->h;
1391 sat = priv->s;
1392 val = priv->v;
1393
1394 compute_triangle (hsv, &hx, &hy, &sx, &sy, &vx, &vy);
1395
1396 x = floor (sx + (vx - sx) * priv->v + (hx - vx) * priv->s * priv->v + 0.5);
1397 y = floor (sy + (vy - sy) * priv->v + (hy - vy) * priv->s * priv->v + 0.5);
1398
1399#define HUE_DELTA0.002 0.002
1400 switch (dir)
1401 {
1402 case CTK_DIR_UP:
1403 if (priv->focus_on_ring)
1404 hue += HUE_DELTA0.002;
1405 else
1406 {
1407 y -= 1;
1408 compute_sv (hsv, x, y, &sat, &val);
1409 }
1410 break;
1411
1412 case CTK_DIR_DOWN:
1413 if (priv->focus_on_ring)
1414 hue -= HUE_DELTA0.002;
1415 else
1416 {
1417 y += 1;
1418 compute_sv (hsv, x, y, &sat, &val);
1419 }
1420 break;
1421
1422 case CTK_DIR_LEFT:
1423 if (priv->focus_on_ring)
1424 hue += HUE_DELTA0.002;
1425 else
1426 {
1427 x -= 1;
1428 compute_sv (hsv, x, y, &sat, &val);
1429 }
1430 break;
1431
1432 case CTK_DIR_RIGHT:
1433 if (priv->focus_on_ring)
1434 hue -= HUE_DELTA0.002
1435 ;
1436 else
1437 {
1438 x += 1;
1439 compute_sv (hsv, x, y, &sat, &val);
1440 }
1441 break;
1442
1443 default:
1444 /* we don't care about the tab directions */
1445 break;
1446 }
1447
1448 /* Wrap */
1449 if (hue < 0.0)
1450 hue = 1.0;
1451 else if (hue > 1.0)
1452 hue = 0.0;
1453
1454 ctk_hsv_set_color (hsv, hue, sat, val);
1455}
1456