gtkcellrendererprogress.c 21.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* gtkcellrendererprogress.c
 * Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net>
 * heavily modified by Jörgen Scheibengruber <mfcn@gmx.de>
 * heavily modified by Marco Pesenti Gritti <marco@gnome.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 19
 */
/*
20
 * Modified by the GTK+ Team and others 1997-2007.  See the AUTHORS
21 22 23 24 25 26 27
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

#include "config.h"
#include <stdlib.h>
28

29
#include "gtkcellrendererprogress.h"
30
#include "gtkintl.h"
31
#include "gtkorientable.h"
32
#include "gtkprivate.h"
33
#include "gtkrender.h"
34 35


36 37 38 39 40 41 42 43 44 45 46 47
/**
 * SECTION:gtkcellrendererprogress
 * @Short_description: Renders numbers as progress bars
 * @Title: GtkCellRendererProgress
 *
 * #GtkCellRendererProgress renders a numeric value as a progress par in a cell.
 * Additionally, it can display a text on top of the progress bar.
 *
 * The #GtkCellRendererProgress cell renderer was added in GTK+ 2.6.
 */


48 49
enum
{
Kristian Rietveld's avatar
Kristian Rietveld committed
50 51
  PROP_0,
  PROP_VALUE,
52
  PROP_TEXT,
53 54
  PROP_PULSE,
  PROP_TEXT_XALIGN,
55
  PROP_TEXT_YALIGN,
56 57 58
  PROP_ORIENTATION,
  PROP_INVERTED
};
59 60 61 62 63 64 65 66

struct _GtkCellRendererProgressPrivate
{
  gint value;
  gchar *text;
  gchar *label;
  gint min_h;
  gint min_w;
67 68
  gint pulse;
  gint offset;
69 70
  gfloat text_xalign;
  gfloat text_yalign;
71 72
  GtkOrientation orientation;
  gboolean inverted;
73 74 75 76 77 78 79 80 81 82 83 84 85 86
};

static void gtk_cell_renderer_progress_finalize     (GObject                 *object);
static void gtk_cell_renderer_progress_get_property (GObject                 *object,
						     guint                    param_id,
						     GValue                  *value,
						     GParamSpec              *pspec);
static void gtk_cell_renderer_progress_set_property (GObject                 *object,
						     guint                    param_id,
						     const GValue            *value,
						     GParamSpec              *pspec);
static void gtk_cell_renderer_progress_set_value    (GtkCellRendererProgress *cellprogress,
						     gint                     value);
static void gtk_cell_renderer_progress_set_text     (GtkCellRendererProgress *cellprogress,
Matthias Clasen's avatar
Matthias Clasen committed
87
						     const gchar             *text);
88 89
static void gtk_cell_renderer_progress_set_pulse    (GtkCellRendererProgress *cellprogress,
						     gint                     pulse);
Matthias Clasen's avatar
Matthias Clasen committed
90 91
static void compute_dimensions                      (GtkCellRenderer         *cell,
						     GtkWidget               *widget,
92 93 94 95 96
						     const gchar             *text,
						     gint                    *width,
						     gint                    *height);
static void gtk_cell_renderer_progress_get_size     (GtkCellRenderer         *cell,
						     GtkWidget               *widget,
97
						     const GdkRectangle      *cell_area,
98 99 100 101 102
						     gint                    *x_offset,
						     gint                    *y_offset,
						     gint                    *width,
						     gint                    *height);
static void gtk_cell_renderer_progress_render       (GtkCellRenderer         *cell,
103
						     cairo_t                 *cr,
104
						     GtkWidget               *widget,
105 106
						     const GdkRectangle      *background_area,
						     const GdkRectangle      *cell_area,
Brian Cameron's avatar
Brian Cameron committed
107
				                     GtkCellRendererState    flags);
108 109

     
110
G_DEFINE_TYPE_WITH_CODE (GtkCellRendererProgress, gtk_cell_renderer_progress, GTK_TYPE_CELL_RENDERER,
111
                         G_ADD_PRIVATE (GtkCellRendererProgress)
112
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

static void
gtk_cell_renderer_progress_class_init (GtkCellRendererProgressClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
  
  object_class->finalize = gtk_cell_renderer_progress_finalize;
  object_class->get_property = gtk_cell_renderer_progress_get_property;
  object_class->set_property = gtk_cell_renderer_progress_set_property;
  
  cell_class->get_size = gtk_cell_renderer_progress_get_size;
  cell_class->render = gtk_cell_renderer_progress_render;
  
  /**
   * GtkCellRendererProgress:value:
129
   *
130
   * The "value" property determines the percentage to which the
131
   * progress bar will be "filled in".
132 133 134 135 136 137 138 139
   *
   * Since: 2.6
   **/
  g_object_class_install_property (object_class,
				   PROP_VALUE,
				   g_param_spec_int ("value",
						     P_("Value"),
						     P_("Value of the progress bar"),
Matthias Clasen's avatar
Matthias Clasen committed
140
						     0, 100, 0,
141
						     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

  /**
   * GtkCellRendererProgress:text:
   * 
   * The "text" property determines the label which will be drawn
   * over the progress bar. Setting this property to %NULL causes the default 
   * label to be displayed. Setting this property to an empty string causes 
   * no label to be displayed.
   *
   * Since: 2.6
   **/
  g_object_class_install_property (object_class,
				   PROP_TEXT,
				   g_param_spec_string ("text",
							P_("Text"),
							P_("Text on the progress bar"),
							NULL,
159
							GTK_PARAM_READWRITE));
160

161 162 163 164 165
  /**
   * GtkCellRendererProgress:pulse:
   * 
   * Setting this to a non-negative value causes the cell renderer to
   * enter "activity mode", where a block bounces back and forth to 
Kristian Rietveld's avatar
Kristian Rietveld committed
166
   * indicate that some progress is made, without specifying exactly how
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
   * much.
   *
   * Each increment of the property causes the block to move by a little 
   * bit.
   *
   * To indicate that the activity has not started yet, set the property
   * to zero. To indicate completion, set the property to %G_MAXINT.
   *
   * Since: 2.12
   */
  g_object_class_install_property (object_class,
                                   PROP_PULSE,
                                   g_param_spec_int ("pulse",
                                                     P_("Pulse"),
                                                     P_("Set this to positive values to indicate that some progress is made, but you don't know how much."),
                                                     -1, G_MAXINT, -1,
183
                                                     GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
  /**
   * GtkCellRendererProgress:text-xalign:
   *
   * The "text-xalign" property controls the horizontal alignment of the
   * text in the progress bar.  Valid values range from 0 (left) to 1
   * (right).  Reserved for RTL layouts.
   *
   * Since: 2.12
   */
  g_object_class_install_property (object_class,
                                   PROP_TEXT_XALIGN,
                                   g_param_spec_float ("text-xalign",
                                                       P_("Text x alignment"),
                                                       P_("The horizontal text alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."),
                                                       0.0, 1.0, 0.5,
                                                       GTK_PARAM_READWRITE));

  /**
   * GtkCellRendererProgress:text-yalign:
   *
   * The "text-yalign" property controls the vertical alignment of the
   * text in the progress bar.  Valid values range from 0 (top) to 1
   * (bottom).
   *
   * Since: 2.12
   */
  g_object_class_install_property (object_class,
                                   PROP_TEXT_YALIGN,
                                   g_param_spec_float ("text-yalign",
                                                       P_("Text y alignment"),
                                                       P_("The vertical text alignment, from 0 (top) to 1 (bottom)."),
                                                       0.0, 1.0, 0.5,
                                                       GTK_PARAM_READWRITE));

219 220 221
  g_object_class_override_property (object_class,
                                    PROP_ORIENTATION,
                                    "orientation");
222

223 224 225 226 227 228
  g_object_class_install_property (object_class,
                                   PROP_INVERTED,
                                   g_param_spec_boolean ("inverted",
                                                         P_("Inverted"),
                                                         P_("Invert the direction in which the progress bar grows"),
                                                         FALSE,
229
                                                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
230 231 232 233 234
}

static void
gtk_cell_renderer_progress_init (GtkCellRendererProgress *cellprogress)
{
235 236
  GtkCellRendererProgressPrivate *priv;

237
  cellprogress->priv = gtk_cell_renderer_progress_get_instance_private (cellprogress);
238
  priv = cellprogress->priv;
239 240 241 242 243 244 245 246 247

  priv->value = 0;
  priv->text = NULL;
  priv->label = NULL;
  priv->min_w = -1;
  priv->min_h = -1;
  priv->pulse = -1;
  priv->offset = 0;

248 249 250
  priv->text_xalign = 0.5;
  priv->text_yalign = 0.5;

251 252
  priv->orientation = GTK_ORIENTATION_HORIZONTAL,
  priv->inverted = FALSE;
253 254 255 256 257 258 259 260
}


/**
 * gtk_cell_renderer_progress_new:
 * 
 * Creates a new #GtkCellRendererProgress. 
 *
261
 * Returns: the new cell renderer
262 263 264 265 266 267
 *
 * Since: 2.6
 **/
GtkCellRenderer*
gtk_cell_renderer_progress_new (void)
{
268
  return g_object_new (GTK_TYPE_CELL_RENDERER_PROGRESS, NULL);
269 270 271 272 273 274
}

static void
gtk_cell_renderer_progress_finalize (GObject *object)
{
  GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
275
  GtkCellRendererProgressPrivate *priv = cellprogress->priv;
276
  
277 278
  g_free (priv->text);
  g_free (priv->label);
279 280 281 282 283
  
  G_OBJECT_CLASS (gtk_cell_renderer_progress_parent_class)->finalize (object);
}

static void
284 285 286
gtk_cell_renderer_progress_get_property (GObject    *object,
					 guint       param_id,
					 GValue     *value,
287 288 289
					 GParamSpec *pspec)
{
  GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
290
  GtkCellRendererProgressPrivate *priv = cellprogress->priv;
291 292 293 294
  
  switch (param_id)
    {
    case PROP_VALUE:
295
      g_value_set_int (value, priv->value);
296 297
      break;
    case PROP_TEXT:
298 299 300 301
      g_value_set_string (value, priv->text);
      break;
    case PROP_PULSE:
      g_value_set_int (value, priv->pulse);
302
      break;
303 304 305 306 307 308
    case PROP_TEXT_XALIGN:
      g_value_set_float (value, priv->text_xalign);
      break;
    case PROP_TEXT_YALIGN:
      g_value_set_float (value, priv->text_yalign);
      break;
309 310 311
    case PROP_ORIENTATION:
      g_value_set_enum (value, priv->orientation);
      break;
312 313 314
    case PROP_INVERTED:
      g_value_set_boolean (value, priv->inverted);
      break;
315 316 317 318 319 320
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
    }
}

static void
321 322
gtk_cell_renderer_progress_set_property (GObject      *object,
					 guint         param_id,
323 324 325 326
					 const GValue *value,
					 GParamSpec   *pspec)
{
  GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
327
  GtkCellRendererProgressPrivate *priv = cellprogress->priv;
328 329 330 331 332 333 334 335 336 337 338
  
  switch (param_id)
    {
    case PROP_VALUE:
      gtk_cell_renderer_progress_set_value (cellprogress, 
					    g_value_get_int (value));
      break;
    case PROP_TEXT:
      gtk_cell_renderer_progress_set_text (cellprogress,
					   g_value_get_string (value));
      break;
339 340 341 342
    case PROP_PULSE:
      gtk_cell_renderer_progress_set_pulse (cellprogress, 
					    g_value_get_int (value));
      break;
343 344 345 346 347 348
    case PROP_TEXT_XALIGN:
      priv->text_xalign = g_value_get_float (value);
      break;
    case PROP_TEXT_YALIGN:
      priv->text_yalign = g_value_get_float (value);
      break;
349
    case PROP_ORIENTATION:
350 351 352 353 354
      if (priv->orientation != g_value_get_enum (value))
        {
          priv->orientation = g_value_get_enum (value);
          g_object_notify_by_pspec (object, pspec);
        }
355
      break;
356
    case PROP_INVERTED:
357 358 359 360 361
      if (priv->inverted != g_value_get_boolean (value))
        {
          priv->inverted = g_value_get_boolean (value);
          g_object_notify_by_pspec (object, pspec);
        }
362
      break;
363 364 365 366 367
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
    }
}

368 369 370 371 372 373 374 375 376
static void
recompute_label (GtkCellRendererProgress *cellprogress)
{
  GtkCellRendererProgressPrivate *priv = cellprogress->priv;
  gchar *label;

  if (priv->text)
    label = g_strdup (priv->text);
  else if (priv->pulse < 0)
377
    label = g_strdup_printf (C_("progress bar label", "%d %%"), priv->value);
378 379 380 381 382 383 384
  else
    label = NULL;
 
  g_free (priv->label);
  priv->label = label;
}

385 386 387 388
static void
gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress, 
				      gint                     value)
{
389 390 391 392 393 394
  if (cellprogress->priv->value != value)
    {
      cellprogress->priv->value = value;
      recompute_label (cellprogress);
      g_object_notify (G_OBJECT (cellprogress), "value");
    }
395 396 397 398
}

static void
gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress, 
Matthias Clasen's avatar
Matthias Clasen committed
399
				     const gchar             *text)
400 401 402 403 404 405
{
  gchar *new_text;

  new_text = g_strdup (text);
  g_free (cellprogress->priv->text);
  cellprogress->priv->text = new_text;
406
  recompute_label (cellprogress);
407
  g_object_notify (G_OBJECT (cellprogress), "text");
408 409 410 411 412 413
}

static void
gtk_cell_renderer_progress_set_pulse (GtkCellRendererProgress *cellprogress, 
				      gint                     pulse)
{
414
  GtkCellRendererProgressPrivate *priv = cellprogress->priv;
415

416 417 418 419 420 421 422 423
  if (pulse != priv->pulse)
    {
      if (pulse <= 0)
        priv->offset = 0;
      else
        priv->offset = pulse;
      g_object_notify (G_OBJECT (cellprogress), "pulse");
    }
424

425 426
  priv->pulse = pulse;
  recompute_label (cellprogress);
427 428 429
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
430 431 432 433 434
compute_dimensions (GtkCellRenderer *cell,
		    GtkWidget       *widget, 
		    const gchar     *text, 
		    gint            *width, 
		    gint            *height)
435 436 437
{
  PangoRectangle logical_rect;
  PangoLayout *layout;
438
  gint xpad, ypad;
439 440 441
  
  layout = gtk_widget_create_pango_layout (widget, text);
  pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
442 443

  gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
444 445
  
  if (width)
446
    *width = logical_rect.width + xpad * 2;
447 448
  
  if (height)
449
    *height = logical_rect.height + ypad * 2;
450

451
  g_object_unref (layout);
452 453 454
}

static void
455 456 457 458 459 460 461
gtk_cell_renderer_progress_get_size (GtkCellRenderer    *cell,
				     GtkWidget          *widget,
				     const GdkRectangle *cell_area,
				     gint               *x_offset,
				     gint               *y_offset,
				     gint               *width,
				     gint               *height)
462 463
{
  GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell);
464
  GtkCellRendererProgressPrivate *priv = cellprogress->priv;
465
  gint w, h;
Matthias Clasen's avatar
Matthias Clasen committed
466 467
  gchar *text;

468
  if (priv->min_w < 0)
Matthias Clasen's avatar
Matthias Clasen committed
469
    {
470
      text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
Matthias Clasen's avatar
Matthias Clasen committed
471
      compute_dimensions (cell, widget, text,
472 473
			  &priv->min_w,
			  &priv->min_h);
Matthias Clasen's avatar
Matthias Clasen committed
474 475
      g_free (text);
    }
476
  
477
  compute_dimensions (cell, widget, priv->label, &w, &h);
478 479
  
  if (width)
480
    *width = MAX (priv->min_w, w);
481 482
  
  if (height)
483
    *height = MIN (priv->min_h, h);
484 485 486 487 488 489 490 491 492 493 494 495 496

  /* FIXME: at the moment cell_area is only set when we are requesting
   * the size for drawing the focus rectangle. We now just return
   * the last size we used for drawing the progress bar, which will
   * work for now. Not a really nice solution though.
   */
  if (cell_area)
    {
      if (width)
        *width = cell_area->width;
      if (height)
        *height = cell_area->height;
    }
497 498 499

  if (x_offset) *x_offset = 0;
  if (y_offset) *y_offset = 0;
500 501
}

502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
static inline gint
get_bar_size (gint pulse,
	      gint value,
	      gint full_size)
{
  gint bar_size;

  if (pulse < 0)
    bar_size = full_size * MAX (0, value) / 100;
  else if (pulse == 0)
    bar_size = 0;
  else if (pulse == G_MAXINT)
    bar_size = full_size;
  else
    bar_size = MAX (2, full_size / 5);

  return bar_size;
}

static inline gint
get_bar_position (gint     start,
		  gint     full_size,
		  gint     bar_size,
		  gint     pulse,
		  gint     offset,
		  gboolean is_rtl)
{
  gint position;

  if (pulse < 0 || pulse == 0 || pulse == G_MAXINT)
    {
      position = is_rtl ? (start + full_size - bar_size) : start;
    }
  else
    {
      position = (is_rtl ? offset + 12 : offset) % 24;
      if (position > 12)
	position = 24 - position;
      position = start + full_size * position / 15;
    }

  return position;
}

546
static void
547 548 549 550 551 552
gtk_cell_renderer_progress_render (GtkCellRenderer      *cell,
                                   cairo_t              *cr,
				   GtkWidget            *widget,
				   const GdkRectangle   *background_area,
				   const GdkRectangle   *cell_area,
				   GtkCellRendererState  flags)
553 554
{
  GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell);
555 556
  GtkCellRendererProgressPrivate *priv= cellprogress->priv;
  GtkStyleContext *context;
557
  GtkBorder padding;
558 559
  PangoLayout *layout;
  PangoRectangle logical_rect;
560
  gint x, y, w, h, x_pos, y_pos, bar_position, bar_size, start, full_size;
561
  gint xpad, ypad;
562 563 564
  GdkRectangle clip;
  gboolean is_rtl;

565
  context = gtk_widget_get_style_context (widget);
566
  is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
567 568 569 570 571 572

  gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
  x = cell_area->x + xpad;
  y = cell_area->y + ypad;
  w = cell_area->width - xpad * 2;
  h = cell_area->height - ypad * 2;
573

574 575 576 577 578 579 580 581
  gtk_style_context_save (context);
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH);

  gtk_render_background (context, cr, x, y, w, h);
  gtk_render_frame (context, cr, x, y, w, h);

  gtk_style_context_get_padding (context, GTK_STATE_FLAG_NORMAL, &padding);

582 583 584 585
  x += padding.left;
  y += padding.top;
  w -= padding.left + padding.right;
  h -= padding.top + padding.bottom;
586 587

  gtk_style_context_restore (context);
Kristian Rietveld's avatar
Kristian Rietveld committed
588

589
  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
590
    {
591 592 593 594 595 596 597 598
      clip.y = y;
      clip.height = h;

      start = x;
      full_size = w;

      bar_size = get_bar_size (priv->pulse, priv->value, full_size);

599
      if (!priv->inverted)
600 601 602 603 604 605 606 607
	bar_position = get_bar_position (start, full_size, bar_size,
					 priv->pulse, priv->offset, is_rtl);
      else
	bar_position = get_bar_position (start, full_size, bar_size,
					 priv->pulse, priv->offset, !is_rtl);

      clip.width = bar_size;
      clip.x = bar_position;
608
    }
609
  else
610 611 612
    {
      clip.x = x;
      clip.width = w;
613 614 615 616 617 618

      start = y;
      full_size = h;

      bar_size = get_bar_size (priv->pulse, priv->value, full_size);

619
      if (priv->inverted)
620 621 622 623 624 625 626 627
	bar_position = get_bar_position (start, full_size, bar_size,
					 priv->pulse, priv->offset, TRUE);
      else
	bar_position = get_bar_position (start, full_size, bar_size,
					 priv->pulse, priv->offset, FALSE);

      clip.height = bar_size;
      clip.y = bar_position;
628
    }
Kristian Rietveld's avatar
Kristian Rietveld committed
629

630
  if (bar_size > 0)
631 632 633
    {
      gtk_style_context_save (context);
      gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR);
634

635 636 637 638 639
      gtk_render_background (context, cr, clip.x, clip.y, clip.width, clip.height);
      gtk_render_frame (context, cr, clip.x, clip.y, clip.width, clip.height);

      gtk_style_context_restore (context);
    }
Kristian Rietveld's avatar
Kristian Rietveld committed
640

641 642
  if (priv->label)
    {
643 644
      gfloat text_xalign;

645 646
      layout = gtk_widget_create_pango_layout (widget, priv->label);
      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
647 648 649 650 651 652

      if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
	text_xalign = 1.0 - priv->text_xalign;
      else
	text_xalign = priv->text_xalign;

653 654
      x_pos = x + padding.left + text_xalign *
	(w - padding.left - padding.right - logical_rect.width);
655

656 657
      y_pos = y + padding.top + priv->text_yalign *
	(h - padding.top - padding.bottom - logical_rect.height);
658

659 660 661 662
      cairo_save (cr);
      gdk_cairo_rectangle (cr, &clip);
      cairo_clip (cr);

663 664 665 666 667 668
      gtk_style_context_save (context);
      gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR);

      gtk_render_layout (context, cr,
                         x_pos, y_pos,
                         layout);
669

670
      gtk_style_context_restore (context);
671
      cairo_restore (cr);
672

673 674 675
      gtk_style_context_save (context);
      gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH);

676
      if (bar_position > start)
677
        {
678
	  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
679 680 681 682 683 684 685 686 687
	    {
	      clip.x = x;
	      clip.width = bar_position - x;
	    }
	  else
	    {
	      clip.y = y;
	      clip.height = bar_position - y;
	    }
688

689 690 691 692
          cairo_save (cr);
          gdk_cairo_rectangle (cr, &clip);
          cairo_clip (cr);

693 694 695
          gtk_render_layout (context, cr,
                             x_pos, y_pos,
                             layout);
696 697

          cairo_restore (cr);
698 699
        }

700
      if (bar_position + bar_size < start + full_size)
701
        {
702
	  if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
703 704 705 706 707 708 709 710 711
	    {
	      clip.x = bar_position + bar_size;
	      clip.width = x + w - (bar_position + bar_size);
	    }
	  else
	    {
	      clip.y = bar_position + bar_size;
	      clip.height = y + h - (bar_position + bar_size);
	    }
712

713 714 715 716
          cairo_save (cr);
          gdk_cairo_rectangle (cr, &clip);
          cairo_clip (cr);

717 718 719 720
          gtk_render_layout (context, cr,
                             x_pos, y_pos,
                             layout);

721
          cairo_restore (cr);
722 723
        }

724
      gtk_style_context_restore (context);
725 726
      g_object_unref (layout);
    }
727
}