1 /*
2  * scrollbar: A scroll bar
3  *
4  * Copyright 2012-2020 Stephan Haller <nomad@froevel.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  *
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <libxfdashboard/scrollbar.h>
29 
30 #include <glib/gi18n-lib.h>
31 
32 #include <libxfdashboard/stylable.h>
33 #include <libxfdashboard/compat.h>
34 #include <libxfdashboard/debug.h>
35 
36 
37 /* Define this class in GObject system */
38 struct _XfdashboardScrollbarPrivate
39 {
40 	/* Properties related */
41 	ClutterOrientation		orientation;
42 	gfloat					value;
43 	gfloat					valueRange;
44 	gfloat					range;
45 	gfloat					pageSizeFactor;
46 	gfloat					spacing;
47 	gfloat					sliderWidth;
48 	gfloat					sliderRadius;
49 	ClutterColor			*sliderColor;
50 
51 	/* Instance related */
52 	ClutterContent			*slider;
53 	ClutterSize				lastViewportSize;
54 	ClutterSize				lastSliderSize;
55 	gfloat					sliderPosition, sliderSize;
56 	gfloat					dragAlignment;
57 	ClutterInputDevice		*dragDevice;
58 	guint					signalButtonReleasedID;
59 	guint					signalMotionEventID;
60 };
61 
62 G_DEFINE_TYPE_WITH_PRIVATE(XfdashboardScrollbar,
63 							xfdashboard_scrollbar,
64 							XFDASHBOARD_TYPE_BACKGROUND)
65 
66 /* Properties */
67 enum
68 {
69 	PROP_0,
70 
71 	PROP_ORIENTATION,
72 	PROP_VALUE,
73 	PROP_VALUE_RANGE,
74 	PROP_RANGE,
75 	PROP_PAGE_SIZE_FACTOR,
76 	PROP_SPACING,
77 	PROP_SLIDER_WIDTH,
78 	PROP_SLIDER_RADIUS,
79 	PROP_SLIDER_COLOR,
80 
81 	PROP_LAST
82 };
83 
84 static GParamSpec* XfdashboardScrollbarProperties[PROP_LAST]={ 0, };
85 
86 /* Signals */
87 enum
88 {
89 	SIGNAL_VALUE_CHANGED,
90 
91 	SIGNAL_LAST
92 };
93 
94 static guint XfdashboardScrollbarSignals[SIGNAL_LAST]={ 0, };
95 
96 /* IMPLEMENTATION: Private variables and methods */
97 
98 /* Get value from coord */
_xfdashboard_scrollbar_get_value_from_coord(XfdashboardScrollbar * self,gfloat inX,gfloat inY,gfloat inAlignment)99 static gfloat _xfdashboard_scrollbar_get_value_from_coord(XfdashboardScrollbar *self,
100 															gfloat inX,
101 															gfloat inY,
102 															gfloat inAlignment)
103 {
104 	XfdashboardScrollbarPrivate		*priv;
105 	gfloat							coord;
106 	gfloat							width;
107 	gfloat							value;
108 
109 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
110 	g_return_val_if_fail(inAlignment>=0.0f && inAlignment<=1.0f, 0.0f);
111 
112 	priv=self->priv;
113 
114 	/* Get coordinate for calculation depending on orientation and
115 	 * subtract spacing
116 	 */
117 	if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL)
118 	{
119 		coord=inX;
120 		width=priv->lastSliderSize.width;
121 	}
122 		else
123 		{
124 			coord=inY;
125 			width=priv->lastSliderSize.height;
126 		}
127 
128 	coord-=priv->spacing;
129 
130 	/* Apply alignment */
131 	coord-=(priv->sliderSize*inAlignment);
132 
133 	/* Calculate new value to set by coordinate */
134 	value=(coord/width)*priv->range;
135 	value=MAX(0.0f, value);
136 	value=MIN(value, priv->range-priv->valueRange);
137 
138 	/* Return calculated value */
139 	return(value);
140 }
141 
142 /* Pointer moved inside scroll bar (usually called after button-pressed event) */
_xfdashboard_scrollbar_on_motion_event(ClutterActor * inActor,ClutterEvent * inEvent,gpointer inUserData)143 static gboolean _xfdashboard_scrollbar_on_motion_event(ClutterActor *inActor,
144 														ClutterEvent *inEvent,
145 														gpointer inUserData)
146 {
147 	XfdashboardScrollbar			*self;
148 	XfdashboardScrollbarPrivate		*priv;
149 	gfloat							eventX, eventY;
150 	gfloat							x, y;
151 	gfloat							value;
152 
153 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(inActor), FALSE);
154 	g_return_val_if_fail(inEvent, FALSE);
155 
156 	self=XFDASHBOARD_SCROLLBAR(inActor);
157 	priv=self->priv;
158 
159 	/* Get coords where event happened */
160 	clutter_event_get_coords(inEvent, &eventX, &eventY);
161 	if(!clutter_actor_transform_stage_point(inActor, eventX, eventY, &x, &y)) return(FALSE);
162 
163 	/* Set value from motion */
164 	value=_xfdashboard_scrollbar_get_value_from_coord(self, x, y, priv->dragAlignment);
165 	xfdashboard_scrollbar_set_value(self, value);
166 
167 	return(CLUTTER_EVENT_STOP);
168 }
169 
170 /* User released button in scroll bar */
_xfdashboard_scrollbar_on_button_released(ClutterActor * inActor,ClutterEvent * inEvent,gpointer inUserData)171 static gboolean _xfdashboard_scrollbar_on_button_released(ClutterActor *inActor,
172 															ClutterEvent *inEvent,
173 															gpointer inUserData)
174 {
175 	XfdashboardScrollbar			*self;
176 	XfdashboardScrollbarPrivate		*priv;
177 	gfloat							eventX, eventY;
178 	gfloat							x, y;
179 	gfloat							value;
180 
181 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(inActor), FALSE);
182 	g_return_val_if_fail(inEvent, FALSE);
183 
184 	self=XFDASHBOARD_SCROLLBAR(inActor);
185 	priv=self->priv;
186 
187 	/* If user did not release a left-click do nothing */
188 	if(clutter_event_get_button(inEvent)!=1) return(FALSE);
189 
190 	/* Release exclusive handling of pointer events and
191 	 * disconnect motion and button-release events
192 	 */
193 	if(priv->dragDevice)
194 	{
195 		clutter_input_device_ungrab(priv->dragDevice);
196 		priv->dragDevice=NULL;
197 	}
198 
199 	if(priv->signalMotionEventID)
200 	{
201 		g_signal_handler_disconnect(inActor, priv->signalMotionEventID);
202 		priv->signalMotionEventID=0L;
203 	}
204 
205 	if(priv->signalButtonReleasedID)
206 	{
207 		g_signal_handler_disconnect(inActor, priv->signalButtonReleasedID);
208 		priv->signalButtonReleasedID=0L;
209 	}
210 
211 	/* Remove style */
212 	xfdashboard_stylable_remove_pseudo_class(XFDASHBOARD_STYLABLE(self), "pressed");
213 
214 	/* Get coords where event happened */
215 	clutter_event_get_coords(inEvent, &eventX, &eventY);
216 	if(!clutter_actor_transform_stage_point(inActor, eventX, eventY, &x, &y)) return(FALSE);
217 
218 	/* Set new value */
219 	value=_xfdashboard_scrollbar_get_value_from_coord(self, x, y, priv->dragAlignment);
220 	xfdashboard_scrollbar_set_value(self, value);
221 
222 	return(CLUTTER_EVENT_STOP);
223 }
224 
225 /* User pressed button in scroll bar */
_xfdashboard_scrollbar_on_button_pressed(ClutterActor * inActor,ClutterEvent * inEvent,gpointer inUserData)226 static gboolean _xfdashboard_scrollbar_on_button_pressed(ClutterActor *inActor,
227 															ClutterEvent *inEvent,
228 															gpointer inUserData)
229 {
230 	XfdashboardScrollbar			*self;
231 	XfdashboardScrollbarPrivate		*priv;
232 	gfloat							eventX, eventY;
233 	gfloat							x, y;
234 	gfloat							value;
235 	gfloat							dragOffset;
236 
237 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(inActor), FALSE);
238 	g_return_val_if_fail(inEvent, FALSE);
239 
240 	self=XFDASHBOARD_SCROLLBAR(inActor);
241 	priv=self->priv;
242 
243 	/* If user left-clicked into scroll bar adjust value to point
244 	 * where the click happened
245 	 */
246 	if(clutter_event_get_button(inEvent)!=1) return(FALSE);
247 
248 	/* Get coords where event happened. If coords are not in bar handle set value
249 	 * otherwise only determine offset used in event handlers and do not adjust
250 	 * value as this would cause a movement of bar handle */
251 	clutter_event_get_coords(inEvent, &eventX, &eventY);
252 	if(!clutter_actor_transform_stage_point(inActor, eventX, eventY, &x, &y)) return(FALSE);
253 
254 	value=_xfdashboard_scrollbar_get_value_from_coord(self, x, y, 0.0f);
255 	if(value<priv->value || value>=(priv->value+priv->valueRange))
256 	{
257 		/* Set new value */
258 		value=_xfdashboard_scrollbar_get_value_from_coord(self, x, y, 0.5f);
259 		xfdashboard_scrollbar_set_value(self, value);
260 		return(FALSE);
261 	}
262 
263 	/* Remember event values for drag'n'drop of slider */
264 	dragOffset=-(priv->spacing+priv->sliderPosition);
265 	if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) dragOffset+=x;
266 		else dragOffset+=y;
267 
268 	priv->dragAlignment=dragOffset/priv->sliderSize;
269 
270 	/* Connect signals for motion and button-release events */
271 	priv->signalMotionEventID=g_signal_connect_after(inActor,
272 														"motion-event",
273 														G_CALLBACK(_xfdashboard_scrollbar_on_motion_event),
274 														NULL);
275 	priv->signalButtonReleasedID=g_signal_connect_after(inActor,
276 															"button-release-event",
277 															G_CALLBACK(_xfdashboard_scrollbar_on_button_released),
278 															NULL);
279 
280 	/* Add style */
281 	xfdashboard_stylable_add_pseudo_class(XFDASHBOARD_STYLABLE(self), "pressed");
282 
283 	/* Handle pointer events exclusively */
284 	priv->dragDevice=clutter_event_get_device(inEvent);
285 	clutter_input_device_grab(priv->dragDevice, inActor);
286 
287 	return(CLUTTER_EVENT_STOP);
288 }
289 
290 /* A scroll event occured in scroll bar (e.g. by mouse-wheel) */
_xfdashboard_scrollbar_on_scroll_event(ClutterActor * inActor,ClutterEvent * inEvent,gpointer inUserData)291 static gboolean _xfdashboard_scrollbar_on_scroll_event(ClutterActor *inActor,
292 														ClutterEvent *inEvent,
293 														gpointer inUserData)
294 {
295 	XfdashboardScrollbar			*self;
296 	XfdashboardScrollbarPrivate		*priv;
297 	gfloat							value;
298 	gfloat							directionFactor;
299 
300 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(inActor), FALSE);
301 	g_return_val_if_fail(inEvent, FALSE);
302 
303 	self=XFDASHBOARD_SCROLLBAR(inActor);
304 	priv=self->priv;
305 
306 	/* Get direction of scroll event */
307 	switch(clutter_event_get_scroll_direction(inEvent))
308 	{
309 		case CLUTTER_SCROLL_UP:
310 		case CLUTTER_SCROLL_LEFT:
311 			directionFactor=-priv->pageSizeFactor;
312 			break;
313 
314 		case CLUTTER_SCROLL_DOWN:
315 		case CLUTTER_SCROLL_RIGHT:
316 			directionFactor=priv->pageSizeFactor;
317 			break;
318 
319 		/* Unhandled directions */
320 		default:
321 			XFDASHBOARD_DEBUG(self, ACTOR,
322 								"Cannot handle scroll direction %d in %s",
323 								clutter_event_get_scroll_direction(inEvent),
324 								G_OBJECT_TYPE_NAME(self));
325 			return(CLUTTER_EVENT_PROPAGATE);
326 	}
327 
328 	/* Calculate new value by increasing or decreasing value by value-range
329 	 * of slider and adjust new value to fit into range (respecting value-range)
330 	 */
331 	value=priv->value+(priv->valueRange*directionFactor);
332 	value=MAX(value, 0);
333 	value=MIN(priv->range-priv->valueRange, value);
334 
335 	/* Set new value */
336 	xfdashboard_scrollbar_set_value(self, value);
337 
338 	return(CLUTTER_EVENT_STOP);
339 }
340 
341 /* Rectangle canvas should be redrawn */
_xfdashboard_scrollbar_on_draw_slider(XfdashboardScrollbar * self,cairo_t * inContext,int inWidth,int inHeight,gpointer inUserData)342 static gboolean _xfdashboard_scrollbar_on_draw_slider(XfdashboardScrollbar *self,
343 														cairo_t *inContext,
344 														int inWidth,
345 														int inHeight,
346 														gpointer inUserData)
347 {
348 	XfdashboardScrollbarPrivate		*priv;
349 	gdouble							radius;
350 	gdouble							top, left, bottom, right;
351 	gdouble							barValueRange;
352 
353 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), TRUE);
354 	g_return_val_if_fail(CLUTTER_IS_CANVAS(inUserData), TRUE);
355 
356 	priv=self->priv;
357 
358 	/* Clear current contents of the canvas */
359 	cairo_save(inContext);
360 	cairo_set_operator(inContext, CAIRO_OPERATOR_CLEAR);
361 	cairo_paint(inContext);
362 	cairo_restore(inContext);
363 
364 	cairo_set_operator(inContext, CAIRO_OPERATOR_OVER);
365 
366 	/* Set color for slider */
367 	if(priv->sliderColor) clutter_cairo_set_source_color(inContext, priv->sliderColor);
368 
369 	/* Determine radius for rounded corners */
370 	radius=MIN(priv->sliderRadius, inWidth/2.0f);
371 	radius=MIN(radius, inHeight/2.0f);
372 
373 	/* Calculate bounding coordinates for slider and viewport */
374 	priv->lastViewportSize.width=inWidth;
375 	priv->lastViewportSize.height=inHeight;
376 	priv->lastSliderSize.width=MAX(0, inWidth-(2*priv->spacing));
377 	priv->lastSliderSize.height=MAX(0, inHeight-(2*priv->spacing));
378 
379 	if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL)
380 	{
381 		if(priv->range > priv->lastViewportSize.width)
382 		{
383 			priv->sliderSize=(priv->lastViewportSize.width/priv->range)*priv->lastSliderSize.width;
384 		}
385 			else priv->sliderSize=priv->lastSliderSize.width;
386 
387 		barValueRange=(priv->sliderSize/priv->lastSliderSize.width)*priv->range;
388 
389 		priv->sliderPosition=MAX(0, (priv->value/priv->range)*priv->lastSliderSize.width);
390 		priv->sliderPosition=MIN(priv->sliderPosition, priv->lastSliderSize.width);
391 		if(priv->sliderPosition+priv->sliderSize>priv->lastSliderSize.width) priv->sliderPosition=priv->lastSliderSize.width-priv->sliderSize;
392 
393 		top=priv->spacing;
394 		bottom=priv->lastSliderSize.height;
395 		left=priv->sliderPosition;
396 		right=priv->sliderPosition+priv->sliderSize;
397 	}
398 		else
399 		{
400 			if(priv->range > priv->lastViewportSize.height)
401 			{
402 				priv->sliderSize=(priv->lastViewportSize.height/priv->range)*priv->lastSliderSize.height;
403 			}
404 				else priv->sliderSize=priv->lastSliderSize.height;
405 
406 			barValueRange=(priv->sliderSize/priv->lastSliderSize.height)*priv->range;
407 
408 			priv->sliderPosition=MAX(0, (priv->value/priv->range)*priv->lastSliderSize.height);
409 			priv->sliderPosition=MIN(priv->sliderPosition, priv->lastSliderSize.height);
410 			if(priv->sliderPosition+priv->sliderSize>priv->lastSliderSize.height) priv->sliderPosition=priv->lastSliderSize.height-priv->sliderSize;
411 
412 			left=priv->spacing;
413 			right=priv->lastSliderSize.width;
414 			top=priv->sliderPosition;
415 			bottom=priv->sliderPosition+priv->sliderSize;
416 		}
417 
418 	/* Draw slider */
419 	if(radius>0.0f)
420 	{
421 		cairo_move_to(inContext, left, top+radius);
422 		cairo_arc(inContext, left+radius, top+radius, radius, G_PI, G_PI*1.5);
423 
424 		cairo_line_to(inContext, right-radius, top);
425 		cairo_arc(inContext, right-radius, top+radius, radius, G_PI*1.5, 0);
426 
427 		cairo_line_to(inContext, right, bottom-radius);
428 		cairo_arc(inContext, right-radius, bottom-radius, radius, 0, G_PI/2.0);
429 
430 		cairo_line_to(inContext, left+radius, bottom);
431 		cairo_arc(inContext, left+radius, bottom-radius, radius, G_PI/2.0, G_PI);
432 
433 		cairo_line_to(inContext, left, radius);
434 	}
435 		else
436 		{
437 			cairo_rectangle(inContext, left, top, right, bottom);
438 		}
439 
440 	cairo_fill(inContext);
441 
442 	/* Set value if changed */
443 	if(barValueRange!=priv->valueRange)
444 	{
445 		/* Set value */
446 		priv->valueRange=barValueRange;
447 
448 		/* Notify about property change */
449 		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_VALUE_RANGE]);
450 
451 		/* Adjust value to fit into range (respecting value-range) if needed */
452 		if(priv->value+priv->valueRange>priv->range)
453 		{
454 			xfdashboard_scrollbar_set_value(self, priv->range-priv->valueRange);
455 		}
456 	}
457 
458 	/* Done drawing */
459 	return(CLUTTER_EVENT_STOP);
460 }
461 
462 /* IMPLEMENTATION: ClutterActor */
463 
464 /* Get preferred width/height */
_xfdashboard_scrollbar_get_preferred_height(ClutterActor * self,gfloat inForWidth,gfloat * outMinHeight,gfloat * outNaturalHeight)465 static void _xfdashboard_scrollbar_get_preferred_height(ClutterActor *self,
466 														gfloat inForWidth,
467 														gfloat *outMinHeight,
468 														gfloat *outNaturalHeight)
469 {
470 	XfdashboardScrollbarPrivate		*priv=XFDASHBOARD_SCROLLBAR(self)->priv;
471 	gfloat							minHeight, naturalHeight;
472 
473 	minHeight=naturalHeight=0.0f;
474 
475 	/* Determine sizes */
476 	if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL)
477 	{
478 		minHeight=naturalHeight=(2*priv->spacing)+priv->sliderWidth;
479 	}
480 		else
481 		{
482 			/* Call parent's class method to determine sizes */
483 			ClutterActorClass		*actorClass=CLUTTER_ACTOR_CLASS(xfdashboard_scrollbar_parent_class);
484 
485 			if(actorClass->get_preferred_height)
486 			{
487 				actorClass->get_preferred_height(self,
488 												inForWidth,
489 												&minHeight,
490 												&naturalHeight);
491 			}
492 		}
493 
494 	/* Store sizes computed */
495 	if(outMinHeight) *outMinHeight=minHeight;
496 	if(outNaturalHeight) *outNaturalHeight=naturalHeight;
497 }
498 
_xfdashboard_scrollbar_get_preferred_width(ClutterActor * self,gfloat inForHeight,gfloat * outMinWidth,gfloat * outNaturalWidth)499 static void _xfdashboard_scrollbar_get_preferred_width(ClutterActor *self,
500 														gfloat inForHeight,
501 														gfloat *outMinWidth,
502 														gfloat *outNaturalWidth)
503 {
504 	XfdashboardScrollbarPrivate		*priv=XFDASHBOARD_SCROLLBAR(self)->priv;
505 	gfloat							minWidth, naturalWidth;
506 
507 	minWidth=naturalWidth=0.0f;
508 
509 	/* Determine sizes */
510 	if(priv->orientation==CLUTTER_ORIENTATION_VERTICAL)
511 	{
512 		minWidth=naturalWidth=(2*priv->spacing)+priv->sliderWidth;
513 	}
514 		else
515 		{
516 			/* Call parent's class method to determine sizes */
517 			ClutterActorClass		*actorClass=CLUTTER_ACTOR_CLASS(xfdashboard_scrollbar_parent_class);
518 
519 			if(actorClass->get_preferred_width)
520 			{
521 				actorClass->get_preferred_width(self,
522 												inForHeight,
523 												&minWidth,
524 												&naturalWidth);
525 			}
526 		}
527 
528 	/* Store sizes computed */
529 	if(outMinWidth) *outMinWidth=minWidth;
530 	if(outNaturalWidth) *outNaturalWidth=naturalWidth;
531 }
532 
533 /* Allocate position and size of actor and its children */
_xfdashboard_scrollbar_allocate(ClutterActor * self,const ClutterActorBox * inBox,ClutterAllocationFlags inFlags)534 static void _xfdashboard_scrollbar_allocate(ClutterActor *self,
535 												const ClutterActorBox *inBox,
536 												ClutterAllocationFlags inFlags)
537 {
538 	XfdashboardScrollbarPrivate		*priv=XFDASHBOARD_SCROLLBAR(self)->priv;
539 
540 	/* Chain up to store the allocation of the actor */
541 	CLUTTER_ACTOR_CLASS(xfdashboard_scrollbar_parent_class)->allocate(self, inBox, inFlags);
542 
543 	/* Set size of slider canvas */
544 	clutter_canvas_set_size(CLUTTER_CANVAS(priv->slider),
545 								clutter_actor_box_get_width(inBox),
546 								clutter_actor_box_get_height(inBox));
547 }
548 
549 /* IMPLEMENTATION: GObject */
550 
551 /* Dispose this object */
_xfdashboard_scrollbar_dispose(GObject * inObject)552 static void _xfdashboard_scrollbar_dispose(GObject *inObject)
553 {
554 	XfdashboardScrollbar			*self=XFDASHBOARD_SCROLLBAR(inObject);
555 	XfdashboardScrollbarPrivate		*priv=self->priv;
556 
557 	/* Release allocated resources */
558 	if(priv->sliderColor)
559 	{
560 		clutter_color_free(priv->sliderColor);
561 		priv->sliderColor=NULL;
562 	}
563 
564 	if(priv->slider)
565 	{
566 		g_object_unref(priv->slider);
567 		priv->slider=NULL;
568 	}
569 
570 	if(priv->dragDevice)
571 	{
572 		clutter_input_device_ungrab(priv->dragDevice);
573 		priv->dragDevice=NULL;
574 	}
575 
576 	if(priv->signalMotionEventID)
577 	{
578 		g_signal_handler_disconnect(self, priv->signalMotionEventID);
579 		priv->signalMotionEventID=0L;
580 	}
581 
582 	if(priv->signalButtonReleasedID)
583 	{
584 		g_signal_handler_disconnect(self, priv->signalButtonReleasedID);
585 		priv->signalButtonReleasedID=0L;
586 	}
587 
588 	/* Call parent's class dispose method */
589 	G_OBJECT_CLASS(xfdashboard_scrollbar_parent_class)->dispose(inObject);
590 }
591 
592 /* Set/get properties */
_xfdashboard_scrollbar_set_property(GObject * inObject,guint inPropID,const GValue * inValue,GParamSpec * inSpec)593 static void _xfdashboard_scrollbar_set_property(GObject *inObject,
594 												guint inPropID,
595 												const GValue *inValue,
596 												GParamSpec *inSpec)
597 {
598 	XfdashboardScrollbar		*self=XFDASHBOARD_SCROLLBAR(inObject);
599 
600 	switch(inPropID)
601 	{
602 		case PROP_ORIENTATION:
603 			xfdashboard_scrollbar_set_orientation(self, g_value_get_enum(inValue));
604 			break;
605 
606 		case PROP_VALUE:
607 			xfdashboard_scrollbar_set_value(self, g_value_get_float(inValue));
608 			break;
609 
610 		case PROP_RANGE:
611 			xfdashboard_scrollbar_set_range(self, g_value_get_float(inValue));
612 			break;
613 
614 		case PROP_PAGE_SIZE_FACTOR:
615 			xfdashboard_scrollbar_set_page_size_factor(self, g_value_get_float(inValue));
616 			break;
617 
618 		case PROP_SPACING:
619 			xfdashboard_scrollbar_set_spacing(self, g_value_get_float(inValue));
620 			break;
621 
622 		case PROP_SLIDER_WIDTH:
623 			xfdashboard_scrollbar_set_slider_width(self, g_value_get_float(inValue));
624 			break;
625 
626 		case PROP_SLIDER_RADIUS:
627 			xfdashboard_scrollbar_set_slider_radius(self, g_value_get_float(inValue));
628 			break;
629 
630 		case PROP_SLIDER_COLOR:
631 			xfdashboard_scrollbar_set_slider_color(self, clutter_value_get_color(inValue));
632 			break;
633 
634 		default:
635 			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
636 			break;
637 	}
638 }
639 
_xfdashboard_scrollbar_get_property(GObject * inObject,guint inPropID,GValue * outValue,GParamSpec * inSpec)640 static void _xfdashboard_scrollbar_get_property(GObject *inObject,
641 												guint inPropID,
642 												GValue *outValue,
643 												GParamSpec *inSpec)
644 {
645 	XfdashboardScrollbar		*self=XFDASHBOARD_SCROLLBAR(inObject);
646 
647 	switch(inPropID)
648 	{
649 		case PROP_ORIENTATION:
650 			g_value_set_enum(outValue, self->priv->orientation);
651 			break;
652 
653 		case PROP_VALUE:
654 			g_value_set_float(outValue, self->priv->value);
655 			break;
656 
657 		case PROP_VALUE_RANGE:
658 			g_value_set_float(outValue, self->priv->valueRange);
659 			break;
660 
661 		case PROP_RANGE:
662 			g_value_set_float(outValue, self->priv->range);
663 			break;
664 
665 		case PROP_PAGE_SIZE_FACTOR:
666 			g_value_set_float(outValue, self->priv->pageSizeFactor);
667 			break;
668 
669 		case PROP_SPACING:
670 			g_value_set_float(outValue, self->priv->spacing);
671 			break;
672 
673 		case PROP_SLIDER_WIDTH:
674 			g_value_set_float(outValue, self->priv->sliderWidth);
675 			break;
676 
677 		case PROP_SLIDER_RADIUS:
678 			g_value_set_float(outValue, self->priv->sliderRadius);
679 			break;
680 
681 		case PROP_SLIDER_COLOR:
682 			clutter_value_set_color(outValue, self->priv->sliderColor);
683 			break;
684 
685 		default:
686 			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
687 			break;
688 	}
689 }
690 
691 /* Class initialization
692  * Override functions in parent classes and define properties
693  * and signals
694  */
xfdashboard_scrollbar_class_init(XfdashboardScrollbarClass * klass)695 static void xfdashboard_scrollbar_class_init(XfdashboardScrollbarClass *klass)
696 {
697 	XfdashboardActorClass	*actorClass=XFDASHBOARD_ACTOR_CLASS(klass);
698 	ClutterActorClass		*clutterActorClass=CLUTTER_ACTOR_CLASS(klass);
699 	GObjectClass			*gobjectClass=G_OBJECT_CLASS(klass);
700 
701 	/* Override functions */
702 	gobjectClass->set_property=_xfdashboard_scrollbar_set_property;
703 	gobjectClass->get_property=_xfdashboard_scrollbar_get_property;
704 	gobjectClass->dispose=_xfdashboard_scrollbar_dispose;
705 
706 	clutterActorClass->get_preferred_width=_xfdashboard_scrollbar_get_preferred_width;
707 	clutterActorClass->get_preferred_height=_xfdashboard_scrollbar_get_preferred_height;
708 	clutterActorClass->allocate=_xfdashboard_scrollbar_allocate;
709 
710 	/* Define properties */
711 	XfdashboardScrollbarProperties[PROP_ORIENTATION]=
712 		g_param_spec_enum("orientation",
713 							"Orientation",
714 							"Defines if scrollbar is horizontal or vertical",
715 							CLUTTER_TYPE_ORIENTATION,
716 							CLUTTER_ORIENTATION_HORIZONTAL,
717 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
718 
719 	XfdashboardScrollbarProperties[PROP_VALUE]=
720 		g_param_spec_float("value",
721 							"Value",
722 							"Current value of scroll bar within range",
723 							0.0f, G_MAXFLOAT,
724 							0.0f,
725 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
726 
727 	XfdashboardScrollbarProperties[PROP_VALUE_RANGE]=
728 		g_param_spec_float("value-range",
729 							"Value range",
730 							"The range the slider of scroll bar covers",
731 							0.0f, G_MAXFLOAT,
732 							0.0f,
733 							G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
734 
735 	XfdashboardScrollbarProperties[PROP_RANGE]=
736 		g_param_spec_float("range",
737 							"Range",
738 							"Range to scroll within",
739 							0.0f, G_MAXFLOAT,
740 							1.0f,
741 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
742 
743 	XfdashboardScrollbarProperties[PROP_PAGE_SIZE_FACTOR]=
744 		g_param_spec_float("page-size-factor",
745 							"Page size factor",
746 							"The factor of value range to increase or decrease value by on pointer scroll events.",
747 							0.1f, 1.0f,
748 							0.5f,
749 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
750 
751 	XfdashboardScrollbarProperties[PROP_SPACING]=
752 		g_param_spec_float("spacing",
753 							"Spacing",
754 							"The spacing between scrollbar and background",
755 							0.0f, G_MAXFLOAT,
756 							0.0f,
757 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
758 
759 	XfdashboardScrollbarProperties[PROP_SLIDER_WIDTH]=
760 		g_param_spec_float("slider-width",
761 							"Slider width",
762 							"The width of slider",
763 							1.0f, G_MAXFLOAT,
764 							1.0f,
765 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
766 
767 	XfdashboardScrollbarProperties[PROP_SLIDER_RADIUS]=
768 		g_param_spec_float("slider-radius",
769 							"Slider radius",
770 							"The radius of slider's rounded corners",
771 							0.0f, G_MAXFLOAT,
772 							0.0f,
773 							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
774 
775 	XfdashboardScrollbarProperties[PROP_SLIDER_COLOR]=
776 		clutter_param_spec_color("slider-color",
777 									"Slider color",
778 									"Color of slider",
779 									CLUTTER_COLOR_White,
780 									G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
781 
782 	g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardScrollbarProperties);
783 
784 	/* Define stylable properties */
785 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardScrollbarProperties[PROP_ORIENTATION]);
786 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardScrollbarProperties[PROP_PAGE_SIZE_FACTOR]);
787 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardScrollbarProperties[PROP_SPACING]);
788 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardScrollbarProperties[PROP_SLIDER_WIDTH]);
789 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardScrollbarProperties[PROP_SLIDER_RADIUS]);
790 	xfdashboard_actor_install_stylable_property(actorClass, XfdashboardScrollbarProperties[PROP_SLIDER_COLOR]);
791 
792 	/* Define signals */
793 	XfdashboardScrollbarSignals[SIGNAL_VALUE_CHANGED]=
794 		g_signal_new("value-changed",
795 						G_TYPE_FROM_CLASS(klass),
796 						G_SIGNAL_RUN_LAST,
797 						G_STRUCT_OFFSET(XfdashboardScrollbarClass, value_changed),
798 						NULL,
799 						NULL,
800 						g_cclosure_marshal_VOID__FLOAT,
801 						G_TYPE_NONE,
802 						1,
803 						G_TYPE_FLOAT);
804 }
805 
806 /* Object initialization
807  * Create private structure and set up default values
808  */
xfdashboard_scrollbar_init(XfdashboardScrollbar * self)809 static void xfdashboard_scrollbar_init(XfdashboardScrollbar *self)
810 {
811 	XfdashboardScrollbarPrivate		*priv;
812 
813 	priv=self->priv=xfdashboard_scrollbar_get_instance_private(self);
814 
815 	/* Set up default values */
816 	priv->orientation=CLUTTER_ORIENTATION_HORIZONTAL;
817 	priv->value=0.0f;
818 	priv->valueRange=0.0f;
819 	priv->range=1.0f;
820 	priv->pageSizeFactor=0.5f;
821 	priv->spacing=0.0f;
822 	priv->sliderWidth=1.0f;
823 	priv->sliderRadius=0.0f;
824 	priv->sliderColor=NULL;
825 	priv->slider=clutter_canvas_new();
826 	priv->signalButtonReleasedID=0;
827 	priv->signalMotionEventID=0;
828 	priv->dragDevice=NULL;
829 
830 	/* Set up actor */
831 	clutter_actor_set_reactive(CLUTTER_ACTOR(self), TRUE);
832 	clutter_actor_set_content(CLUTTER_ACTOR(self), priv->slider);
833 	if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) clutter_actor_set_request_mode(CLUTTER_ACTOR(self), CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
834 		else clutter_actor_set_request_mode(CLUTTER_ACTOR(self), CLUTTER_REQUEST_WIDTH_FOR_HEIGHT);
835 
836 	/* Connect signals */
837 	g_signal_connect_swapped(priv->slider, "draw", G_CALLBACK(_xfdashboard_scrollbar_on_draw_slider), self);
838 	g_signal_connect(self, "button-press-event", G_CALLBACK(_xfdashboard_scrollbar_on_button_pressed), NULL);
839 	g_signal_connect(self, "scroll-event", G_CALLBACK(_xfdashboard_scrollbar_on_scroll_event), NULL);
840 }
841 
842 /* IMPLEMENTATION: Public API */
843 
844 /* Create new actor */
xfdashboard_scrollbar_new(ClutterOrientation inOrientation)845 ClutterActor* xfdashboard_scrollbar_new(ClutterOrientation inOrientation)
846 {
847 	return(g_object_new(XFDASHBOARD_TYPE_SCROLLBAR,
848 							"orientation", inOrientation,
849 							NULL));
850 }
851 
852 /* Get/set orientation */
xfdashboard_scrollbar_get_orientation(XfdashboardScrollbar * self)853 gfloat xfdashboard_scrollbar_get_orientation(XfdashboardScrollbar *self)
854 {
855 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), CLUTTER_ORIENTATION_HORIZONTAL);
856 
857 	return(self->priv->spacing);
858 }
859 
xfdashboard_scrollbar_set_orientation(XfdashboardScrollbar * self,ClutterOrientation inOrientation)860 void xfdashboard_scrollbar_set_orientation(XfdashboardScrollbar *self, ClutterOrientation inOrientation)
861 {
862 	XfdashboardScrollbarPrivate		*priv;
863 
864 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
865 	g_return_if_fail(inOrientation==CLUTTER_ORIENTATION_HORIZONTAL || inOrientation==CLUTTER_ORIENTATION_VERTICAL);
866 
867 	priv=self->priv;
868 
869 	/* Only set value if it changes */
870 	if(inOrientation==priv->orientation) return;
871 
872 	/* Set new value */
873 	priv->orientation=inOrientation;
874 
875 	if(priv->orientation==CLUTTER_ORIENTATION_HORIZONTAL) clutter_actor_set_request_mode(CLUTTER_ACTOR(self), CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
876 		else clutter_actor_set_request_mode(CLUTTER_ACTOR(self), CLUTTER_REQUEST_WIDTH_FOR_HEIGHT);
877 
878 	if(priv->slider) clutter_content_invalidate(priv->slider);
879 	clutter_actor_queue_relayout(CLUTTER_ACTOR(self));
880 
881 	/* Notify about property change */
882 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_ORIENTATION]);
883 }
884 
885 /* Get/set value */
xfdashboard_scrollbar_get_value(XfdashboardScrollbar * self)886 gfloat xfdashboard_scrollbar_get_value(XfdashboardScrollbar *self)
887 {
888 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
889 
890 	return(self->priv->value);
891 }
892 
xfdashboard_scrollbar_set_value(XfdashboardScrollbar * self,gfloat inValue)893 void xfdashboard_scrollbar_set_value(XfdashboardScrollbar *self, gfloat inValue)
894 {
895 	XfdashboardScrollbarPrivate		*priv;
896 	gboolean						enforceNewValue;
897 
898 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
899 	g_return_if_fail(inValue>=0.0f);
900 
901 	priv=self->priv;
902 
903 	/* Check if value is within range */
904 	enforceNewValue=FALSE;
905 	if(inValue+priv->valueRange>priv->range)
906 	{
907 		gfloat						oldValue;
908 
909 		oldValue=inValue;
910 		inValue=MAX(0.0f, priv->range-priv->valueRange);
911 		XFDASHBOARD_DEBUG(self, ACTOR,
912 							"Adjusting value %.2f to %.2f in scrollbar to fit into range [0-%.2f]",
913 							oldValue,
914 							inValue,
915 							priv->range);
916 		enforceNewValue=TRUE;
917 	}
918 
919 	/* Only set value if it changes */
920 	if(inValue==priv->value && enforceNewValue==FALSE) return;
921 
922 	/* Set new value */
923 	priv->value=inValue;
924 	if(priv->slider) clutter_content_invalidate(priv->slider);
925 	clutter_actor_queue_redraw(CLUTTER_ACTOR(self));
926 
927 	/* Notify about property change */
928 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_VALUE]);
929 	g_signal_emit(self, XfdashboardScrollbarSignals[SIGNAL_VALUE_CHANGED], 0, priv->value);
930 }
931 
932 /* Get value range */
xfdashboard_scrollbar_get_value_range(XfdashboardScrollbar * self)933 gfloat xfdashboard_scrollbar_get_value_range(XfdashboardScrollbar *self)
934 {
935 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
936 
937 	return(self->priv->valueRange);
938 }
939 
940 /* Get/set range */
xfdashboard_scrollbar_get_range(XfdashboardScrollbar * self)941 gfloat xfdashboard_scrollbar_get_range(XfdashboardScrollbar *self)
942 {
943 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
944 
945 	return(self->priv->range);
946 }
947 
xfdashboard_scrollbar_set_range(XfdashboardScrollbar * self,gfloat inRange)948 void xfdashboard_scrollbar_set_range(XfdashboardScrollbar *self, gfloat inRange)
949 {
950 	XfdashboardScrollbarPrivate		*priv;
951 
952 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
953 	g_return_if_fail(inRange>=0.0f);
954 
955 	priv=self->priv;
956 
957 	/* Only set value if it changes */
958 	if(inRange==priv->range) return;
959 
960 	/* Freeze notification */
961 	g_object_freeze_notify(G_OBJECT(self));
962 
963 	/* Set new value */
964 	priv->range=inRange;
965 	if(priv->slider) clutter_content_invalidate(priv->slider);
966 	clutter_actor_queue_redraw(CLUTTER_ACTOR(self));
967 
968 	/* Notify about property change */
969 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_RANGE]);
970 
971 	/* Check if value is still within new range otherwise adjust value */
972 	if(priv->value>priv->range)
973 	{
974 		gfloat						oldValue;
975 
976 		XFDASHBOARD_DEBUG(self, ACTOR,
977 							"Adjusting value %.2f in scrollbar to fit into new range %.2f",
978 							priv->value,
979 							priv->range);
980 		oldValue=priv->value;
981 		xfdashboard_scrollbar_set_value(self, priv->range);
982 		XFDASHBOARD_DEBUG(self, ACTOR,
983 							"Adjusted value %.2f to %.2f in scrollbar to fit into new range %.2f",
984 							oldValue,
985 							priv->value,
986 							priv->range);
987 	}
988 
989 	/* Thaw notification */
990 	g_object_thaw_notify(G_OBJECT(self));
991 }
992 
993 /* Get/set page-size factor */
xfdashboard_scrollbar_get_page_size_factor(XfdashboardScrollbar * self)994 gfloat xfdashboard_scrollbar_get_page_size_factor(XfdashboardScrollbar *self)
995 {
996 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
997 
998 	return(self->priv->pageSizeFactor);
999 }
1000 
xfdashboard_scrollbar_set_page_size_factor(XfdashboardScrollbar * self,gfloat inFactor)1001 void xfdashboard_scrollbar_set_page_size_factor(XfdashboardScrollbar *self, gfloat inFactor)
1002 {
1003 	XfdashboardScrollbarPrivate		*priv;
1004 
1005 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
1006 	g_return_if_fail(inFactor>=0.1f && inFactor<=1.0f);
1007 
1008 	priv=self->priv;
1009 
1010 	/* Only set value if it changes */
1011 	if(inFactor==priv->pageSizeFactor) return;
1012 
1013 	/* Set new value */
1014 	priv->pageSizeFactor=inFactor;
1015 
1016 	/* Notify about property change */
1017 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_PAGE_SIZE_FACTOR]);
1018 }
1019 
1020 /* Get/set spacing */
xfdashboard_scrollbar_get_spacing(XfdashboardScrollbar * self)1021 gfloat xfdashboard_scrollbar_get_spacing(XfdashboardScrollbar *self)
1022 {
1023 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
1024 
1025 	return(self->priv->spacing);
1026 }
1027 
xfdashboard_scrollbar_set_spacing(XfdashboardScrollbar * self,gfloat inSpacing)1028 void xfdashboard_scrollbar_set_spacing(XfdashboardScrollbar *self, gfloat inSpacing)
1029 {
1030 	XfdashboardScrollbarPrivate		*priv;
1031 
1032 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
1033 	g_return_if_fail(inSpacing>=0.0f);
1034 
1035 	priv=self->priv;
1036 
1037 	/* Only set value if it changes */
1038 	if(inSpacing==priv->spacing) return;
1039 
1040 	/* Set new value */
1041 	priv->spacing=inSpacing;
1042 	clutter_actor_queue_relayout(CLUTTER_ACTOR(self));
1043 
1044 	/* Notify about property change */
1045 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_SPACING]);
1046 }
1047 
1048 /* Get/set slider width (thickness) */
xfdashboard_scrollbar_get_slider_width(XfdashboardScrollbar * self)1049 gfloat xfdashboard_scrollbar_get_slider_width(XfdashboardScrollbar *self)
1050 {
1051 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
1052 
1053 	return(self->priv->sliderWidth);
1054 }
1055 
xfdashboard_scrollbar_set_slider_width(XfdashboardScrollbar * self,gfloat inWidth)1056 void xfdashboard_scrollbar_set_slider_width(XfdashboardScrollbar *self, gfloat inWidth)
1057 {
1058 	XfdashboardScrollbarPrivate		*priv;
1059 
1060 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
1061 	g_return_if_fail(inWidth>=1.0f);
1062 
1063 	priv=self->priv;
1064 
1065 	/* Only set value if it changes */
1066 	if(inWidth==priv->sliderWidth) return;
1067 
1068 	/* Set new value */
1069 	priv->sliderWidth=inWidth;
1070 	clutter_actor_queue_relayout(CLUTTER_ACTOR(self));
1071 
1072 	/* Notify about property change */
1073 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_SLIDER_WIDTH]);
1074 }
1075 
1076 /* Get/set radius of rounded corners of slider */
xfdashboard_scrollbar_get_slider_radius(XfdashboardScrollbar * self)1077 gfloat xfdashboard_scrollbar_get_slider_radius(XfdashboardScrollbar *self)
1078 {
1079 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), 0.0f);
1080 
1081 	return(self->priv->sliderWidth);
1082 }
1083 
xfdashboard_scrollbar_set_slider_radius(XfdashboardScrollbar * self,gfloat inRadius)1084 void xfdashboard_scrollbar_set_slider_radius(XfdashboardScrollbar *self, gfloat inRadius)
1085 {
1086 	XfdashboardScrollbarPrivate		*priv;
1087 
1088 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
1089 	g_return_if_fail(inRadius>=0.0f);
1090 
1091 	priv=self->priv;
1092 
1093 	/* Only set value if it changes */
1094 	if(inRadius==priv->sliderRadius) return;
1095 
1096 	/* Set new value */
1097 	priv->sliderRadius=inRadius;
1098 	if(priv->slider) clutter_content_invalidate(priv->slider);
1099 
1100 	/* Notify about property change */
1101 	g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_SLIDER_RADIUS]);
1102 }
1103 
1104 /* Get/set color of slider */
xfdashboard_scrollbar_get_slider_color(XfdashboardScrollbar * self)1105 const ClutterColor* xfdashboard_scrollbar_get_slider_color(XfdashboardScrollbar *self)
1106 {
1107 	g_return_val_if_fail(XFDASHBOARD_IS_SCROLLBAR(self), NULL);
1108 
1109 	return(self->priv->sliderColor);
1110 }
1111 
xfdashboard_scrollbar_set_slider_color(XfdashboardScrollbar * self,const ClutterColor * inColor)1112 void xfdashboard_scrollbar_set_slider_color(XfdashboardScrollbar *self, const ClutterColor *inColor)
1113 {
1114 	XfdashboardScrollbarPrivate		*priv;
1115 
1116 	g_return_if_fail(XFDASHBOARD_IS_SCROLLBAR(self));
1117 	g_return_if_fail(inColor);
1118 
1119 	priv=self->priv;
1120 
1121 	/* Set value if changed */
1122 	if(priv->sliderColor==NULL || clutter_color_equal(inColor, priv->sliderColor)==FALSE)
1123 	{
1124 		/* Set value */
1125 		if(priv->sliderColor) clutter_color_free(priv->sliderColor);
1126 		priv->sliderColor=clutter_color_copy(inColor);
1127 
1128 		/* Invalidate canvas to get it redrawn */
1129 		if(priv->slider) clutter_content_invalidate(priv->slider);
1130 
1131 		/* Notify about property change */
1132 		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardScrollbarProperties[PROP_SLIDER_COLOR]);
1133 	}
1134 }
1135