hythmbox-2.98/widgets/rb-segmented-bar.c

Location Tool Test ID Function Issue
rb-segmented-bar.c:635:0 cppcheck uninitvar Uninitialized variable: x
rb-segmented-bar.c:635:11 clang-analyzer The left operand of '<=' is a garbage value
rb-segmented-bar.c:635:11 clang-analyzer The left operand of '<=' is a garbage value
rb-segmented-bar.c:635:0 cppcheck uninitvar Uninitialized variable: x
   1 /*
   2  * Initial Author:
   3  *   Aaron Bockover <abockover@novell.com>
   4  *
   5  * Ported to C from Banshee's SegmentedBar.cs widget
   6  *
   7  * Copyright (C) 2008 Novell, Inc.
   8  * Copyright (C) 2008 Christophe Fergeau <teuf@gnome.org>
   9  *
  10  * Permission is hereby granted, free of charge, to any person obtaining
  11  * a copy of this software and associated documentation files (the
  12  * "Software"), to deal in the Software without restriction, including
  13  * without limitation the rights to use, copy, modify, merge, publish,
  14  * distribute, sublicense, and/or sell copies of the Software, and to
  15  * permit persons to whom the Software is furnished to do so, subject to
  16  * the following conditions:
  17  *
  18  * The above copyright notice and this permission notice shall be
  19  * included in all copies or substantial portions of the Software.
  20  *
  21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28  */
  29 
  30 #ifdef HAVE_CONFIG_H
  31 #include "config.h"
  32 #endif
  33 #include <math.h>
  34 #include <locale.h>
  35 #include <cairo/cairo.h>
  36 #include <gtk/gtk.h>
  37 #include "rb-segmented-bar.h"
  38 
  39 #define MINIMUM_HEIGHT 26
  40 
  41 static void rb_segmented_bar_finalize (GObject *object);
  42 static void rb_segmented_bar_size_allocate(GtkWidget *widget,
  43 					   GtkAllocation *allocation);
  44 static gboolean rb_segmented_bar_draw (GtkWidget *widget, cairo_t *context);
  45 static void rb_segmented_bar_get_property (GObject *object, guint param_id,
  46 					   GValue *value, GParamSpec *pspec);
  47 static void rb_segmented_bar_set_property (GObject *object, guint param_id,
  48 					   const GValue *value, GParamSpec *pspec);
  49 
  50 static gchar *rb_segmented_bar_default_value_formatter (gdouble percent,
  51 						       	gpointer data);
  52 static void rb_segmented_bar_get_preferred_height (GtkWidget *widget,
  53 						   int *minimum_height,
  54 						   int *natural_height);
  55 static void rb_segmented_bar_get_preferred_width (GtkWidget *widget,
  56 						  int *minimum_width,
  57 						  int *natural_width);
  58 
  59 static void compute_layout_size (RBSegmentedBar *bar);
  60 
  61 static AtkObject * rb_segmented_bar_get_accessible (GtkWidget *widget);
  62 enum
  63 {
  64 	PROP_0,
  65 	PROP_SHOW_REFLECTION,
  66 	PROP_SHOW_LABELS,
  67 	PROP_BAR_HEIGHT
  68 };
  69 
  70 struct _RBSegmentedBarPrivate {
  71 	GList *segments;
  72 	guint layout_width;
  73 	guint layout_height;
  74 
  75 	guint bar_height;
  76 	guint bar_label_spacing;
  77 	guint segment_label_spacing;
  78 	guint segment_box_size;
  79 	guint segment_box_spacing;
  80 	guint h_padding;
  81 	
  82 	gboolean show_labels;
  83 	gboolean reflect;
  84 
  85 	RBSegmentedBarValueFormatter value_formatter;
  86 	gpointer value_formatter_data;
  87 
  88 	char *a11y_description;
  89 	char *a11y_locale;
  90 };
  91 
  92 G_DEFINE_TYPE (RBSegmentedBar, rb_segmented_bar, GTK_TYPE_WIDGET)
  93 #define RB_SEGMENTED_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_SEGMENTED_BAR, RBSegmentedBarPrivate))
  94 
  95 struct _Color {
  96 	gdouble red;
  97 	gdouble green;
  98 	gdouble blue;
  99 	gdouble alpha;
 100 };
 101 typedef struct _Color Color;
 102 
 103 struct _Segment {
 104 	gchar *label;
 105 	gdouble percent;
 106 	Color color;
 107 
 108 	gint layout_width;
 109 	gint layout_height;
 110 };
 111 typedef struct _Segment Segment;
 112 
 113 static Segment *rb_segment_new (const gchar *label, gdouble percent, Color *color)
 114 {
 115 	Segment *segment;
 116 
 117 	segment = g_new0 (Segment, 1);
 118 	segment->label = g_strdup (label);
 119 	segment->percent = percent;
 120 	segment->color.red = color->red;
 121 	segment->color.green = color->green;
 122 	segment->color.blue = color->blue;
 123 	segment->color.alpha = color->alpha;
 124 	
 125 	return segment;
 126 }
 127 
 128 static void rb_segment_free (Segment *segment)
 129 {
 130 	g_return_if_fail (segment != NULL);
 131 	g_free (segment->label);
 132 	g_free (segment);
 133 }
 134 
 135 static void
 136 rb_segmented_bar_init (RBSegmentedBar *bar)
 137 {
 138 	RBSegmentedBarPrivate *priv;
 139 
 140 	priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (bar));
 141 	priv->bar_label_spacing = 8;
 142 	priv->segment_label_spacing = 16;
 143 	priv->segment_box_size = 12;
 144 	priv->segment_box_spacing = 6;
 145 	priv->value_formatter = rb_segmented_bar_default_value_formatter;
 146 	gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
 147 }
 148 
 149 static void
 150 rb_segmented_bar_class_init (RBSegmentedBarClass *klass)
 151 {
 152 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 153 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 154 
 155 	object_class->finalize = rb_segmented_bar_finalize;
 156 	object_class->get_property = rb_segmented_bar_get_property;
 157 	object_class->set_property = rb_segmented_bar_set_property;
 158 
 159 	widget_class->draw = rb_segmented_bar_draw;
 160 	widget_class->get_preferred_height = rb_segmented_bar_get_preferred_height;
 161 	widget_class->get_preferred_width = rb_segmented_bar_get_preferred_width;
 162 	widget_class->size_allocate = rb_segmented_bar_size_allocate;
 163 	widget_class->get_accessible = rb_segmented_bar_get_accessible;
 164 
 165         /**
 166          * RBSegmentedBar:show-reflection:
 167          *
 168          * Set to TRUE if you want a reflection to be shown below the segmented
 169 	 * bar.
 170          */
 171         g_object_class_install_property (object_class,
 172                                          PROP_SHOW_REFLECTION,
 173                                          g_param_spec_boolean ("show-reflection",
 174                                                                "show-reflection",
 175                                                                "Whether there will be a reflection below the segmented bar",
 176                                                                TRUE,
 177                                                                G_PARAM_READWRITE));
 178 
 179         /**
 180          * RBSegmentedBar:show-labels:
 181          *
 182          * Set to TRUE if you want labels describing the various segments
 183 	 * to be shown.
 184          */
 185         g_object_class_install_property (object_class,
 186                                          PROP_SHOW_LABELS,
 187                                          g_param_spec_boolean ("show-labels",
 188                                                                "show-labels",
 189                                                                "Whether the labels describing the various segments should be shown",
 190                                                                TRUE,
 191                                                                G_PARAM_READWRITE));
 192         /**
 193          * RBSegmentedBar:bar-height:
 194          *
 195          * Height of the segmented bar
 196          */
 197 	g_object_class_install_property (object_class,
 198 					 PROP_BAR_HEIGHT,
 199 					 g_param_spec_uint ("bar-height",
 200 							    "bar-height",
 201 							    "height of the segmented bar",
 202 							    MINIMUM_HEIGHT, G_MAXUINT, MINIMUM_HEIGHT,
 203 							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 204 
 205 	g_type_class_add_private (klass, sizeof (RBSegmentedBarPrivate));
 206 }
 207 
 208 static void
 209 rb_segmented_bar_finalize (GObject *object)
 210 {
 211 	RBSegmentedBarPrivate *priv;
 212 	priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (object));
 213 	g_list_foreach (priv->segments, (GFunc)rb_segment_free, NULL);
 214 	g_list_free (priv->segments);
 215 	g_free (priv->a11y_description);
 216 	g_free (priv->a11y_locale);
 217 	G_OBJECT_CLASS (rb_segmented_bar_parent_class)->finalize (object);
 218 } 
 219 
 220 static void
 221 rb_segmented_bar_get_property (GObject *object,
 222 			       guint param_id,
 223 			       GValue *value,
 224 			       GParamSpec *pspec)
 225 {
 226 	RBSegmentedBarPrivate *priv;
 227 	priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (object));
 228 
 229 	switch (param_id) {
 230 	    case PROP_SHOW_REFLECTION:
 231 		g_value_set_boolean (value, priv->reflect);
 232 		break;
 233 	    case PROP_SHOW_LABELS:
 234 		g_value_set_boolean (value, priv->show_labels);
 235 		break;
 236 	    case PROP_BAR_HEIGHT:	
 237 		g_value_set_uint (value, priv->bar_height);
 238 		break;
 239 	    default:
 240 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 241 		break;
 242 	}
 243 }
 244 
 245 static void
 246 rb_segmented_bar_set_property (GObject *object,
 247 			       guint param_id,
 248 			       const GValue *value,
 249 			       GParamSpec *pspec)
 250 {
 251 	RBSegmentedBarPrivate *priv;
 252 	priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (object));
 253 
 254 	switch (param_id) {
 255 	    case PROP_SHOW_REFLECTION:
 256 		priv->reflect = g_value_get_boolean (value);
 257 		break;
 258 	    case PROP_SHOW_LABELS:
 259 		priv->show_labels = g_value_get_boolean (value);
 260 		break;
 261 	    case PROP_BAR_HEIGHT:	
 262 		priv->bar_height = g_value_get_uint (value);
 263 		break;
 264 	    default:
 265 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
 266 		break;
 267 	}
 268 }
 269 
 270 static gchar *
 271 rb_segmented_bar_default_value_formatter (gdouble percent,
 272 					  G_GNUC_UNUSED gpointer data)
 273 {
 274 	return g_strdup_printf ("%.2f%%", percent*100.0);
 275 }
 276 
 277 static void
 278 rb_segmented_bar_get_preferred_height (GtkWidget *widget, int *minimum_height, int *natural_height)
 279 {
 280 	RBSegmentedBarPrivate *priv;
 281 	int height;
 282 
 283 
 284 	priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (widget));
 285 	if (priv->reflect) {
 286 		height = MINIMUM_HEIGHT * 1.75;
 287 	} else {
 288 		height = MINIMUM_HEIGHT;
 289 	}
 290 
 291 	if (priv->show_labels) {
 292 		compute_layout_size (RB_SEGMENTED_BAR (widget));
 293 		height = MAX (MINIMUM_HEIGHT + priv->bar_label_spacing + priv->layout_height, height);
 294 	}
 295 
 296 	if (minimum_height)
 297 		*minimum_height = height;
 298 	if (natural_height)
 299 		*natural_height = height;
 300 }
 301 
 302 static void
 303 rb_segmented_bar_get_preferred_width (GtkWidget *widget, int *minimum_width, int *natural_width)
 304 {
 305 	RBSegmentedBarPrivate *priv;
 306 	int width;
 307 
 308 	priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (widget));
 309 
 310 	compute_layout_size (RB_SEGMENTED_BAR (widget));
 311 	width = MAX (priv->layout_width, 200);
 312 
 313 	if (minimum_width)
 314 		*minimum_width = width;
 315 	if (natural_width)
 316 		*natural_width = width;
 317 }
 318 
 319 static PangoLayout *create_adapt_layout (GtkWidget *widget, PangoLayout *layout,
 320 					 gboolean small, gboolean bold)
 321 {
 322 	const PangoFontDescription *desc;
 323 	PangoFontDescription *new_desc;
 324 
 325 	int normal_font_size;
 326 	if (layout == NULL) {
 327 		layout = gtk_widget_create_pango_layout (GTK_WIDGET (widget), 
 328 							 NULL);
 329 	}
 330 	desc = pango_context_get_font_description (gtk_widget_get_pango_context (widget));
 331 	g_assert (desc != NULL);
 332 	normal_font_size = pango_font_description_get_size (desc);
 333 
 334 	desc = pango_context_get_font_description (pango_layout_get_context (layout));
 335 	g_assert (desc != NULL);
 336 	new_desc = pango_font_description_copy (desc);
 337 
 338 	if (small) {
 339 		pango_font_description_set_size (new_desc,
 340 						 normal_font_size * PANGO_SCALE_SMALL);
 341 	} else {
 342 		pango_font_description_set_size (new_desc, normal_font_size);
 343 	}
 344 
 345 	if (bold) {
 346 		pango_font_description_set_weight (new_desc,
 347 						   PANGO_WEIGHT_BOLD);
 348 	} else {
 349 		pango_font_description_set_weight (new_desc,
 350 						   PANGO_WEIGHT_NORMAL);
 351 	}
 352 	pango_layout_set_font_description (layout, new_desc);
 353 	pango_font_description_free (new_desc);
 354 	return layout;
 355 }
 356 
 357 static void 
 358 compute_layout_size (RBSegmentedBar *bar)
 359 {
 360 	RBSegmentedBarPrivate *priv = RB_SEGMENTED_BAR_GET_PRIVATE (bar);
 361 	PangoLayout *layout = NULL;
 362 	GList *it;
 363 
 364 	if (priv->segments == NULL) {
 365 		return;
 366 	}
 367 
 368 	priv->layout_width = 0;
 369 	priv->layout_height = 0;
 370 
 371 	for (it = priv->segments; it != NULL; it = it->next) {
 372 		Segment *segment = (Segment *)it->data;
 373 		gint label_width;
 374 		gint label_height;
 375 		gint value_width;
 376 		gint value_height;
 377 		gint width;
 378 		gint height;
 379 		gchar *value_str;
 380 
 381 		layout = create_adapt_layout (GTK_WIDGET (bar), layout,
 382 					      FALSE, TRUE);
 383 		pango_layout_set_text (layout, segment->label, -1);
 384 		pango_layout_get_pixel_size (layout, 
 385 					     &label_width,
 386 					     &label_height);
 387 
 388 		layout = create_adapt_layout (GTK_WIDGET (bar), layout,
 389 					      TRUE, FALSE);
 390 		g_assert (priv->value_formatter != NULL);
 391 		value_str = priv->value_formatter (segment->percent,
 392 						   priv->value_formatter_data);
 393 		pango_layout_set_text (layout, value_str, -1);
 394 		g_free (value_str);
 395 		pango_layout_get_pixel_size (layout, 
 396 					     &value_width,
 397 					     &value_height);
 398 
 399 		width = MAX (label_width, value_width);
 400 		height = label_height + value_height;
 401 
 402 		segment->layout_width = width;
 403 		segment->layout_height = MAX (height, priv->segment_box_size*2);
 404 
 405 		priv->layout_width += segment->layout_width + priv->segment_box_size + priv->segment_box_spacing;
 406 		if (it->next != NULL) {
 407 			priv->layout_width += priv->segment_label_spacing;
 408 		}
 409 		priv->layout_height = MAX (priv->layout_height, segment->layout_height);
 410 	}
 411 
 412 	g_object_unref (G_OBJECT (layout));
 413 }
 414 
 415 static void 
 416 rb_segmented_bar_size_allocate(GtkWidget *widget, GtkAllocation *allocation) 
 417 { 
 418 	gint real_height;
 419 	RBSegmentedBarPrivate *priv = RB_SEGMENTED_BAR_GET_PRIVATE (widget);
 420 	GtkAllocation new_allocation;
 421 
 422 	g_return_if_fail(RB_IS_SEGMENTED_BAR(widget)); 
 423 	g_return_if_fail(allocation != NULL); 
 424 
 425 	if (priv->reflect) {
 426 		real_height = priv->bar_height*1.75;
 427 	} else {
 428 		real_height = priv->bar_height;
 429 	}
 430 	gtk_widget_set_allocation (widget, allocation);
 431 	if (priv->show_labels) {
 432 		compute_layout_size (RB_SEGMENTED_BAR (widget));
 433 		new_allocation.height = MAX (priv->bar_height + priv->bar_label_spacing + priv->layout_height,
 434 		                         real_height);
 435 	} else {
 436 		new_allocation.height = real_height;
 437 	}
 438 	new_allocation.width = priv->layout_width + 2*(priv->h_padding);
 439 	gtk_widget_set_allocation (widget, &new_allocation);
 440 	GTK_WIDGET_CLASS(rb_segmented_bar_parent_class)->size_allocate(widget, allocation); 
 441 }
 442 
 443 
 444 guint rb_segmented_bar_add_segment (RBSegmentedBar *bar,
 445 				    const gchar *title, gdouble percent,
 446 				    gdouble red, gdouble green,
 447 				    gdouble blue, gdouble alpha)
 448 {
 449 	Color color = { red, green, blue, alpha };
 450 	RBSegmentedBarPrivate *priv = RB_SEGMENTED_BAR_GET_PRIVATE (bar);
 451 	guint index;
 452 	Segment *segment = rb_segment_new (title, percent, &color);
 453 	priv->segments = g_list_append (priv->segments, segment);
 454 	index = g_list_index (priv->segments, segment);
 455 
 456 	g_free (priv->a11y_description);
 457 	priv->a11y_description = NULL;
 458 
 459 	gtk_widget_queue_draw (GTK_WIDGET (bar));
 460 	gtk_widget_queue_resize (GTK_WIDGET (bar));
 461 
 462 	return index;
 463 }
 464 
 465 guint rb_segmented_bar_add_segment_default_color (RBSegmentedBar *bar,
 466 						  const gchar *title,
 467 						  gdouble percent)
 468 {
 469 	return rb_segmented_bar_add_segment (bar, title, percent, 0.9, 0.9, 0.9, 1.0);
 470 }
 471 
 472 void rb_segmented_bar_update_segment (RBSegmentedBar *bar,
 473 				      guint segment_index,
 474 				      gdouble percent)
 475 {
 476 	RBSegmentedBarPrivate *priv = RB_SEGMENTED_BAR_GET_PRIVATE (bar);
 477 	Segment *segment = g_list_nth_data (priv->segments, segment_index);
 478 	if (segment != NULL) {
 479 		segment->percent = percent;
 480 		g_free (priv->a11y_description);
 481 		priv->a11y_description = NULL;
 482 
 483 		gtk_widget_queue_draw (GTK_WIDGET (bar));
 484 	}
 485 }
 486 
 487 static void draw_rounded_rectangle (cairo_t *context,
 488 				    guint x, guint y,
 489 				    guint width, guint height,
 490 				    guint radius)
 491 {
 492 	if (radius < 0.0001) {
 493 		cairo_rectangle (context, x, y, width, height);
 494 		return;
 495 	}
 496 	cairo_move_to (context, x+radius, y);
 497 	cairo_arc (context, x+width-radius, y+radius, radius, G_PI*1.5, G_PI*2);
 498 	cairo_arc (context, x+width-radius, y+height-radius, radius, 0, G_PI*0.5);
 499 	cairo_arc (context, x+radius, y+height-radius, radius, G_PI*0.5, G_PI);
 500 	cairo_arc (context, x+radius, y+radius, radius, G_PI, G_PI*1.5);
 501 }
 502 
 503 static void rb_segmented_bar_render_segments (RBSegmentedBar *bar,
 504 					      cairo_t *context,
 505 					      guint width, guint height,
 506 					      guint radius)
 507 {
 508 	cairo_pattern_t *grad;
 509 	gdouble last;
 510 	GList *it;
 511 	RBSegmentedBarPrivate *priv;
 512 
 513 	last = 0.0;
 514 	priv = RB_SEGMENTED_BAR_GET_PRIVATE (bar);
 515 	grad = cairo_pattern_create_linear (0, 0, width, 0);
 516 	for (it = priv->segments; it != NULL; it = it->next) {
 517 		Segment *segment = (Segment *)it->data;
 518 		if (segment->percent > 0) {
 519 			cairo_pattern_add_color_stop_rgba (grad, last,
 520 							   segment->color.red,
 521 							   segment->color.green,
 522 							   segment->color.blue,
 523 							   segment->color.alpha);
 524 			last += segment->percent;
 525 			cairo_pattern_add_color_stop_rgba (grad, last,
 526 							   segment->color.red,
 527 							   segment->color.green,
 528 							   segment->color.blue,
 529 							   segment->color.alpha);
 530 		}
 531 	}
 532 
 533 	draw_rounded_rectangle (context, 0, 0, width, height, radius);
 534 	cairo_set_source (context, grad);
 535 	cairo_fill_preserve (context);
 536 	cairo_pattern_destroy (grad);
 537 
 538 	grad = cairo_pattern_create_linear (0, 0, 0, height);
 539 	cairo_pattern_add_color_stop_rgba (grad, 0.0, 1, 1, 1, 0.125);
 540 	cairo_pattern_add_color_stop_rgba (grad, 0.35, 1, 1, 1, 0.255);
 541 	cairo_pattern_add_color_stop_rgba (grad, 1, 0, 0, 0, 0.4);
 542 	cairo_set_source (context, grad);
 543 	cairo_fill (context);
 544 	cairo_pattern_destroy (grad);
 545 
 546 }
 547 
 548 static void hsb_from_color (Color *color, gdouble *hue,
 549 			    gdouble *saturation, gdouble *brightness)
 550 {
 551 	gtk_rgb_to_hsv (color->red, color->green, color->blue,
 552 			hue, saturation, brightness);
 553 }
 554 
 555 static Color *color_from_hsb (gdouble hue, gdouble saturation, gdouble brightness)
 556 {
 557 	Color *color;
 558 
 559 	color = g_new0 (Color, 1);
 560 	gtk_hsv_to_rgb (hue, saturation, brightness,
 561 			&color->red, &color->green, &color->blue);
 562 
 563 	return color;
 564 }
 565 
 566 static Color *color_shade (Color *base, gdouble ratio)
 567 {
 568 	gdouble h;
 569 	gdouble s;
 570 	gdouble b;
 571 	Color *color;
 572 
 573 	hsb_from_color (base, &h, &s, &b);
 574 
 575 	b = MAX (MIN (b*ratio, 1), 0);
 576 	s = MAX (MIN (s*ratio, 1), 0);
 577 
 578 	color = color_from_hsb (h, s, b);
 579 	color->alpha = base->alpha;
 580 
 581 	return color;
 582 }
 583 
 584 static cairo_pattern_t *make_segment_gradient (guint height,
 585 					       gdouble red, gdouble green, 
 586 					       gdouble blue, gdouble alpha)
 587 {
 588 	cairo_pattern_t *grad;
 589 	Color *shade;
 590 	Color color = { red, green, blue, alpha };
 591 
 592 	grad = cairo_pattern_create_linear (0, 0, 0, height);
 593 
 594 	shade = color_shade (&color, 1.1);
 595 	cairo_pattern_add_color_stop_rgba (grad, 0,
 596 					   shade->red, shade->green,
 597 					   shade->blue, shade->alpha);
 598 	g_free (shade);
 599 
 600 	shade = color_shade (&color, 1.2);
 601 	cairo_pattern_add_color_stop_rgba (grad, 0.35,
 602 					   shade->red, shade->green,
 603 					   shade->blue, shade->alpha);
 604 	g_free (shade);
 605 
 606 	shade = color_shade (&color, 0.8);
 607 	cairo_pattern_add_color_stop_rgba (grad, 1,
 608 					   shade->red, shade->green,
 609 					   shade->blue, shade->alpha);
 610 	g_free (shade);
 611 
 612 	return grad;
 613 }
 614 
 615 static void rb_segmented_bar_render_strokes (RBSegmentedBar *bar,
 616 					     cairo_t *context,
 617 					     guint width, guint height,
 618 					     guint radius)
 619 {
 620 	cairo_pattern_t *stroke = make_segment_gradient (height,
 621 							 0, 0, 0, 0.25);
 622 	cairo_pattern_t *seg_sep_light = make_segment_gradient (height,
 623 								1, 1, 1, 0.125);
 624 	cairo_pattern_t *seg_sep_dark = make_segment_gradient (height,
 625 							       0, 0, 0, 0.125);
 626 	gdouble seg_w = 20;
 627 	gdouble x;
 628 	if (seg_w > radius) {
 629 		x = seg_w;
 630 	} else {
 631 		seg_w = radius;
 632 	}
 633 	cairo_set_line_width (context, 1);
 634 
 635 	while (x <= width-radius) {
Uninitialized variable: x
(emitted by cppcheck)
The left operand of '<=' is a garbage value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

The left operand of '<=' is a garbage value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Uninitialized variable: x
(emitted by cppcheck)
636 cairo_move_to (context, x - 0.5, 1); 637 cairo_line_to (context, x - 0.5, height - 1); 638 cairo_set_source (context, seg_sep_light); 639 cairo_stroke (context); 640 641 cairo_move_to (context, x + 0.5, 1); 642 cairo_line_to (context, x + 0.5, height - 1); 643 cairo_set_source (context, seg_sep_dark); 644 cairo_stroke (context); 645 646 x += seg_w; 647 } 648 649 draw_rounded_rectangle (context, 0.5, 0.5, 650 width - 1, height - 1, radius); 651 cairo_set_source (context, stroke); 652 cairo_stroke (context); 653 654 cairo_pattern_destroy (stroke); 655 cairo_pattern_destroy (seg_sep_light); 656 cairo_pattern_destroy (seg_sep_dark); 657 } 658 659 static cairo_pattern_t *rb_segmented_bar_render (RBSegmentedBar *bar, 660 guint width, guint height) 661 { 662 cairo_surface_t *surface; 663 cairo_t *context; 664 cairo_pattern_t *pattern; 665 666 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 667 width, height); 668 context = cairo_create (surface); 669 rb_segmented_bar_render_segments (bar, context, 670 width, height, height/2); 671 rb_segmented_bar_render_strokes (bar, context, width, height, height/2); 672 pattern = cairo_pattern_create_for_surface (surface); 673 cairo_surface_destroy (surface); 674 cairo_destroy (context); 675 676 return pattern; 677 } 678 679 static void rb_segmented_bar_render_labels (RBSegmentedBar *bar, 680 cairo_t *context) 681 { 682 RBSegmentedBarPrivate *priv; 683 PangoLayout *layout; 684 Color text_color; 685 GdkRGBA gdk_color; 686 gboolean ltr = TRUE; 687 int x = 0; 688 GList *it; 689 690 priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (bar)); 691 692 if (priv->segments == NULL) { 693 return; 694 } 695 gtk_style_context_get_color (gtk_widget_get_style_context (GTK_WIDGET (bar)), 696 gtk_widget_get_state (GTK_WIDGET (bar)), 697 &gdk_color); 698 699 if (gtk_widget_get_direction (GTK_WIDGET (bar)) == GTK_TEXT_DIR_RTL) { 700 ltr = FALSE; 701 x = priv->layout_width; 702 } 703 704 text_color.red = gdk_color.red; 705 text_color.green = gdk_color.green; 706 text_color.blue = gdk_color.blue; 707 text_color.alpha = 1.0; 708 layout = NULL; 709 for (it = priv->segments; it != NULL; it = it->next) { 710 cairo_pattern_t *grad; 711 int layout_width; 712 int layout_height; 713 gchar *value_str; 714 Segment *segment; 715 716 if (ltr == FALSE) { 717 x -= priv->segment_box_size + priv->segment_box_spacing; 718 } 719 720 segment = (Segment *)it->data; 721 cairo_set_line_width (context, 1); 722 cairo_rectangle (context, x + 0.5, 2 + 0.5, 723 priv->segment_box_size - 1, 724 priv->segment_box_size - 1); 725 grad = make_segment_gradient (priv->segment_box_size, 726 segment->color.red, 727 segment->color.green, 728 segment->color.blue, 729 segment->color.alpha); 730 cairo_set_source (context, grad); 731 cairo_fill_preserve (context); 732 cairo_set_source_rgba (context, 0, 0, 0, 0.6); 733 cairo_stroke (context); 734 cairo_pattern_destroy (grad); 735 736 if (ltr) { 737 x += priv->segment_box_size + priv->segment_box_spacing; 738 } 739 740 layout = create_adapt_layout (GTK_WIDGET (bar), layout, 741 FALSE, TRUE); 742 pango_layout_set_text (layout, segment->label, -1); 743 pango_layout_get_pixel_size (layout, 744 &layout_width, &layout_height); 745 if (ltr == FALSE) { 746 x -= priv->segment_box_spacing + layout_width; 747 } 748 749 cairo_move_to (context, x, 0); 750 cairo_set_source_rgba (context, 751 text_color.red, text_color.green, 752 text_color.blue, 0.9); 753 pango_cairo_show_layout (context, layout); 754 cairo_fill (context); 755 756 layout = create_adapt_layout (GTK_WIDGET (bar), layout, 757 TRUE, FALSE); 758 g_assert (priv->value_formatter != NULL); 759 value_str = priv->value_formatter (segment->percent, 760 priv->value_formatter_data); 761 pango_layout_set_text (layout, value_str, -1); 762 g_free (value_str); 763 764 cairo_move_to (context, x, layout_height); 765 cairo_set_source_rgba (context, 766 text_color.red, text_color.green, 767 text_color.blue, 0.75); 768 pango_cairo_show_layout (context, layout); 769 cairo_fill (context); 770 771 if (ltr) { 772 x += segment->layout_width + priv->segment_label_spacing; 773 } else { 774 x -= segment->layout_width - layout_width; 775 } 776 } 777 g_object_unref (G_OBJECT (layout)); 778 } 779 780 static gboolean 781 rb_segmented_bar_draw (GtkWidget *widget, cairo_t *context_) 782 { 783 RBSegmentedBar *bar; 784 RBSegmentedBarPrivate *priv; 785 GtkAllocation allocation; 786 cairo_pattern_t *bar_pattern; 787 cairo_t *context; 788 789 g_return_val_if_fail (RB_IS_SEGMENTED_BAR (widget), FALSE); 790 791 bar = RB_SEGMENTED_BAR (widget); 792 priv = RB_SEGMENTED_BAR_GET_PRIVATE (bar); 793 794 /* XXX should use the context passed in, but this currently 795 * doesn't work properly with pre-existing translation 796 */ 797 context = gdk_cairo_create (gtk_widget_get_window (widget)); 798 if (priv->reflect) { 799 cairo_push_group (context); 800 } 801 802 cairo_set_operator (context, CAIRO_OPERATOR_OVER); 803 gtk_widget_get_allocation (widget, &allocation); 804 if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_LTR) { 805 cairo_translate (context, allocation.x + priv->h_padding, allocation.y); 806 } else { 807 cairo_translate (context, 808 allocation.x + allocation.width - priv->h_padding, 809 allocation.y); 810 cairo_scale (context, -1.0, 1.0); 811 } 812 cairo_rectangle (context, 0, 0, 813 allocation.width - priv->h_padding, 814 MAX (2*priv->bar_height, priv->bar_height + priv->bar_label_spacing + priv->layout_height)); 815 cairo_clip (context); 816 817 bar_pattern = rb_segmented_bar_render (bar, 818 allocation.width - 2*priv->h_padding, 819 priv->bar_height); 820 821 cairo_save (context); 822 cairo_set_source (context, bar_pattern); 823 cairo_paint (context); 824 cairo_restore (context); 825 826 if (priv->reflect) { 827 cairo_matrix_t matrix; 828 cairo_pattern_t *mask; 829 830 cairo_save (context); 831 832 cairo_rectangle (context, 0, priv->bar_height, 833 allocation.width - priv->h_padding, 834 priv->bar_height); 835 cairo_clip (context); 836 cairo_matrix_init_scale (&matrix, 1, -1); 837 cairo_matrix_translate (&matrix, 0, -(2*priv->bar_height) + 1); 838 cairo_transform (context, &matrix); 839 840 cairo_set_source (context, bar_pattern); 841 842 mask = cairo_pattern_create_linear (0, 0, 0, priv->bar_height); 843 cairo_pattern_add_color_stop_rgba (mask, 0.25, 0, 0, 0, 0); 844 cairo_pattern_add_color_stop_rgba (mask, 0.5, 0, 0, 0, 0.125); 845 cairo_pattern_add_color_stop_rgba (mask, 0.75, 0, 0, 0, 0.4); 846 cairo_pattern_add_color_stop_rgba (mask, 1.0, 0, 0, 0, 0.7); 847 848 cairo_mask (context, mask); 849 cairo_pattern_destroy (mask); 850 851 cairo_restore (context); 852 853 cairo_pop_group_to_source (context); 854 cairo_paint (context); 855 } 856 857 if (priv->show_labels) { 858 if (priv->reflect) { 859 cairo_translate (context, 860 allocation.x + (allocation.width - priv->layout_width)/2, 861 allocation.y + priv->bar_height + priv->bar_label_spacing); 862 } else { 863 cairo_translate (context, 864 -priv->h_padding + (allocation.width - priv->layout_width)/2, 865 priv->bar_height + priv->bar_label_spacing); 866 } 867 rb_segmented_bar_render_labels (bar, context); 868 } 869 cairo_pattern_destroy (bar_pattern); 870 cairo_destroy (context); 871 872 return TRUE; 873 } 874 875 GtkWidget *rb_segmented_bar_new (void) 876 { 877 return g_object_new (RB_TYPE_SEGMENTED_BAR, NULL); 878 } 879 880 /** 881 * rb_segmented_bar_set_value_formatter: 882 * @bar: a #RBSegmentedBar 883 * @formatter: (scope async): the formatter function to use 884 * @data: data to pass to the formatter 885 * 886 * Sets a value formatter function to use for the bar. 887 */ 888 void rb_segmented_bar_set_value_formatter (RBSegmentedBar *bar, 889 RBSegmentedBarValueFormatter formatter, 890 gpointer data) 891 { 892 RBSegmentedBarPrivate *priv; 893 894 priv = RB_SEGMENTED_BAR_GET_PRIVATE (RB_SEGMENTED_BAR (bar)); 895 896 priv->value_formatter = formatter; 897 priv->value_formatter_data = data; 898 } 899 900 static const char * 901 get_a11y_description (RBSegmentedBar *bar) 902 { 903 RBSegmentedBarPrivate *priv; 904 905 priv = RB_SEGMENTED_BAR_GET_PRIVATE (bar); 906 if (priv->a11y_description == NULL) { 907 GList *i; 908 GString *desc = g_string_new (""); 909 910 for (i = priv->segments; i != NULL; i = i->next) { 911 Segment *segment; 912 char *value_str; 913 914 segment = (Segment *)i->data; 915 916 g_assert (priv->value_formatter != NULL); 917 value_str = priv->value_formatter (segment->percent, 918 priv->value_formatter_data); 919 920 g_string_append_printf (desc, "%s: %s\n", segment->label, value_str); 921 g_free (value_str); 922 } 923 924 priv->a11y_description = g_string_free (desc, FALSE); 925 } 926 return priv->a11y_description; 927 } 928 929 static const char * 930 get_a11y_locale (RBSegmentedBar *bar) 931 { 932 RBSegmentedBarPrivate *priv; 933 934 priv = RB_SEGMENTED_BAR_GET_PRIVATE (bar); 935 if (priv->a11y_locale == NULL) { 936 priv->a11y_locale = setlocale (LC_MESSAGES, ""); 937 } 938 return priv->a11y_locale; 939 } 940 941 /* A11y type hack copied from nautilus/eel/eel-accessibility.c */ 942 943 static GType 944 create_a11y_derived_type (const char *type_name, GType existing_type, GClassInitFunc class_init) 945 { 946 GType type; 947 GType parent_atk_type; 948 GTypeQuery query; 949 AtkObjectFactory *factory; 950 GTypeInfo typeinfo = {0,}; 951 952 type = g_type_from_name (type_name); 953 if (type != G_TYPE_INVALID) { 954 return type; 955 } 956 957 factory = atk_registry_get_factory (atk_get_default_registry (), existing_type); 958 parent_atk_type = atk_object_factory_get_accessible_type (factory); 959 if (parent_atk_type == G_TYPE_INVALID) { 960 return G_TYPE_INVALID; 961 } 962 963 g_type_query (parent_atk_type, &query); 964 if (class_init) { 965 typeinfo.class_init = class_init; 966 } 967 typeinfo.class_size = query.class_size; 968 typeinfo.instance_size = query.instance_size; 969 970 type = g_type_register_static (parent_atk_type, type_name, &typeinfo, 0); 971 return type; 972 } 973 974 /* AtkObject implementation */ 975 976 static gint 977 a11y_impl_get_n_children (AtkObject *obj) 978 { 979 return 0; 980 } 981 982 static AtkObject * 983 a11y_impl_ref_child (AtkObject *obj, gint i) 984 { 985 return NULL; 986 } 987 988 /* AtkImage */ 989 990 static void 991 a11y_impl_get_image_position (AtkImage *image, gint *x, gint *y, AtkCoordType coord_type) 992 { 993 atk_component_get_position (ATK_COMPONENT (image), x, y, coord_type); 994 } 995 996 static const char * 997 a11y_impl_get_image_description (AtkImage *image) 998 { 999 RBSegmentedBar *bar; 1000 bar = RB_SEGMENTED_BAR (g_object_get_data (G_OBJECT (image), "rb-atk-widget")); 1001 return get_a11y_description (bar); 1002 } 1003 1004 static void 1005 a11y_impl_get_image_size (AtkImage *image, gint *width, gint *height) 1006 { 1007 GtkAllocation alloc; 1008 GtkWidget *widget; 1009 1010 widget = GTK_WIDGET (g_object_get_data (G_OBJECT (image), "rb-atk-widget")); 1011 1012 gtk_widget_get_allocation (widget, &alloc); 1013 *width = alloc.width; 1014 *height = alloc.height; 1015 } 1016 1017 static const char * 1018 a11y_impl_get_image_locale (AtkImage *image) 1019 { 1020 RBSegmentedBar *bar; 1021 bar = RB_SEGMENTED_BAR (g_object_get_data (G_OBJECT (image), "rb-atk-widget")); 1022 return get_a11y_locale (bar); 1023 } 1024 1025 static void 1026 rb_segmented_bar_a11y_class_init (AtkObjectClass *klass) 1027 { 1028 AtkObjectClass *atkobject_class = ATK_OBJECT_CLASS (klass); 1029 1030 atkobject_class->get_n_children = a11y_impl_get_n_children; 1031 atkobject_class->ref_child = a11y_impl_ref_child; 1032 } 1033 1034 static void 1035 rb_segmented_bar_a11y_image_init (AtkImageIface *iface) 1036 { 1037 iface->get_image_position = a11y_impl_get_image_position; 1038 iface->get_image_description = a11y_impl_get_image_description; 1039 iface->get_image_size = a11y_impl_get_image_size; 1040 iface->get_image_locale = a11y_impl_get_image_locale; 1041 /* don't need set_image_description, do we? */ 1042 } 1043 1044 static void 1045 destroy_accessible (gpointer data, GObject *obj) 1046 { 1047 atk_object_notify_state_change (ATK_OBJECT (data), ATK_STATE_DEFUNCT, TRUE); 1048 } 1049 1050 static AtkObject * 1051 rb_segmented_bar_get_accessible (GtkWidget *widget) 1052 { 1053 static GType a11ytype = G_TYPE_INVALID; 1054 AtkObject *accessible; 1055 accessible = g_object_get_data (G_OBJECT (widget), "rb-atk-object"); 1056 if (accessible != NULL) { 1057 return accessible; 1058 } 1059 1060 if (a11ytype == G_TYPE_INVALID) { 1061 const GInterfaceInfo atk_image_info = { 1062 (GInterfaceInitFunc) rb_segmented_bar_a11y_image_init, 1063 (GInterfaceFinalizeFunc) NULL, 1064 NULL 1065 }; 1066 1067 a11ytype = create_a11y_derived_type ("RBSegmentedBarA11y", 1068 GTK_TYPE_WIDGET, 1069 (GClassInitFunc) rb_segmented_bar_a11y_class_init); 1070 if (a11ytype == G_TYPE_INVALID) { 1071 g_warning ("unable to create a11y type for segmented bar"); 1072 return NULL; 1073 } 1074 1075 g_type_add_interface_static (a11ytype, ATK_TYPE_IMAGE, &atk_image_info); 1076 } 1077 1078 accessible = g_object_new (a11ytype, NULL); 1079 atk_object_set_role (accessible, ATK_ROLE_IMAGE); 1080 atk_object_initialize (accessible, widget); 1081 1082 g_object_set_data_full (G_OBJECT (widget), "rb-atk-object", accessible, (GDestroyNotify) destroy_accessible); 1083 g_object_set_data (G_OBJECT (accessible), "rb-atk-widget", widget); 1084 1085 return accessible; 1086 }