]> Pileus Git - ~andy/gtk/blob - gtk/gtkprogressbar.c
Remove some unused variables
[~andy/gtk] / gtk / gtkprogressbar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 #include "config.h"
28
29 #include <string.h>
30
31 #include "gtkprogressbar.h"
32 #include "gtkprivate.h"
33 #include "gtkintl.h"
34
35
36 #define MIN_HORIZONTAL_BAR_WIDTH   150
37 #define MIN_HORIZONTAL_BAR_HEIGHT  20
38 #define MIN_VERTICAL_BAR_WIDTH     22
39 #define MIN_VERTICAL_BAR_HEIGHT    80
40
41
42 struct _GtkProgressBarPriv
43 {
44   GtkProgressBarOrientation orientation;
45
46   gchar         *text;
47
48   gdouble        fraction;
49   gdouble        pulse_fraction;
50
51   guint          blocks;
52   gint           in_block;
53
54   gint           activity_pos;
55   guint          activity_blocks;
56   guint          activity_step;
57
58   guint          activity_dir  : 1;
59   guint          activity_mode : 1;
60   guint          ellipsize     : 3;
61   guint          show_text     : 1;
62 };
63
64 enum {
65   PROP_0,
66   PROP_FRACTION,
67   PROP_PULSE_STEP,
68   PROP_ORIENTATION,
69   PROP_TEXT,
70   PROP_SHOW_TEXT,
71   PROP_ELLIPSIZE
72 };
73
74 static void gtk_progress_bar_set_property  (GObject             *object,
75                                             guint                prop_id,
76                                             const GValue        *value,
77                                             GParamSpec          *pspec);
78 static void gtk_progress_bar_get_property  (GObject             *object,
79                                             guint                prop_id,
80                                             GValue              *value,
81                                             GParamSpec          *pspec);
82 static gboolean gtk_progress_bar_expose    (GtkWidget           *widget,
83                                             GdkEventExpose      *event);
84 static void gtk_progress_bar_size_request  (GtkWidget           *widget,
85                                             GtkRequisition      *requisition);
86 static void gtk_progress_bar_size_allocate (GtkWidget           *widget,
87                                             GtkAllocation       *allocation);
88 static void gtk_progress_bar_real_update   (GtkProgressBar      *progress);
89 static void gtk_progress_bar_paint         (GtkProgressBar      *progress);
90 static void gtk_progress_bar_act_mode_enter (GtkProgressBar     *progress);
91 static void gtk_progress_bar_realize       (GtkWidget           *widget);
92 static void gtk_progress_bar_finalize      (GObject             *object);
93
94
95 G_DEFINE_TYPE (GtkProgressBar, gtk_progress_bar, GTK_TYPE_WIDGET)
96
97 static void
98 gtk_progress_bar_class_init (GtkProgressBarClass *class)
99 {
100   GObjectClass *gobject_class;
101   GtkWidgetClass *widget_class;
102
103   gobject_class = G_OBJECT_CLASS (class);
104   widget_class = (GtkWidgetClass *) class;
105
106   gobject_class->set_property = gtk_progress_bar_set_property;
107   gobject_class->get_property = gtk_progress_bar_get_property;
108   gobject_class->finalize = gtk_progress_bar_finalize;
109
110   widget_class->realize = gtk_progress_bar_realize;
111   widget_class->expose_event = gtk_progress_bar_expose;
112   widget_class->size_request = gtk_progress_bar_size_request;
113   widget_class->size_allocate = gtk_progress_bar_size_allocate;
114
115   g_object_class_install_property (gobject_class,
116                                    PROP_ORIENTATION,
117                                    g_param_spec_enum ("orientation",
118                                                       P_("Orientation"),
119                                                       P_("Orientation and growth direction of the progress bar"),
120                                                       GTK_TYPE_PROGRESS_BAR_ORIENTATION,
121                                                       GTK_PROGRESS_LEFT_TO_RIGHT,
122                                                       GTK_PARAM_READWRITE));
123
124   g_object_class_install_property (gobject_class,
125                                    PROP_FRACTION,
126                                    g_param_spec_double ("fraction",
127                                                         P_("Fraction"),
128                                                         P_("The fraction of total work that has been completed"),
129                                                         0.0, 1.0, 0.0,
130                                                         GTK_PARAM_READWRITE));
131
132   g_object_class_install_property (gobject_class,
133                                    PROP_PULSE_STEP,
134                                    g_param_spec_double ("pulse-step",
135                                                         P_("Pulse Step"),
136                                                         P_("The fraction of total progress to move the bouncing block when pulsed"),
137                                                         0.0, 1.0, 0.1,
138                                                         GTK_PARAM_READWRITE));
139
140   g_object_class_install_property (gobject_class,
141                                    PROP_TEXT,
142                                    g_param_spec_string ("text",
143                                                         P_("Text"),
144                                                         P_("Text to be displayed in the progress bar"),
145                                                         NULL,
146                                                         GTK_PARAM_READWRITE));
147
148   g_object_class_install_property (gobject_class,
149                                    PROP_SHOW_TEXT,
150                                    g_param_spec_boolean ("show-text",
151                                                          P_("Show text"),
152                                                          P_("Whether the progress is shown as text."),
153                                                          FALSE,
154                                                          GTK_PARAM_READWRITE));
155
156   /**
157    * GtkProgressBar:ellipsize:
158    *
159    * The preferred place to ellipsize the string, if the progressbar does
160    * not have enough room to display the entire string, specified as a
161    * #PangoEllisizeMode.
162    *
163    * Note that setting this property to a value other than
164    * %PANGO_ELLIPSIZE_NONE has the side-effect that the progressbar requests
165    * only enough space to display the ellipsis "...". Another means to set a
166    * progressbar's width is gtk_widget_set_size_request().
167    *
168    * Since: 2.6
169    */
170   g_object_class_install_property (gobject_class,
171                                    PROP_ELLIPSIZE,
172                                    g_param_spec_enum ("ellipsize",
173                                                       P_("Ellipsize"),
174                                                       P_("The preferred place to ellipsize the string, if the progress bar "
175                                                          "does not have enough room to display the entire string, if at all."),
176                                                       PANGO_TYPE_ELLIPSIZE_MODE,
177                                                       PANGO_ELLIPSIZE_NONE,
178                                                       GTK_PARAM_READWRITE));
179   gtk_widget_class_install_style_property (widget_class,
180                                            g_param_spec_int ("xspacing",
181                                                              P_("XSpacing"),
182                                                              P_("Extra spacing applied to the width of a progress bar."),
183                                                              0, G_MAXINT, 7,
184                                                              G_PARAM_READWRITE));
185   gtk_widget_class_install_style_property (widget_class,
186                                            g_param_spec_int ("yspacing",
187                                                              P_("YSpacing"),
188                                                              P_("Extra spacing applied to the height of a progress bar."),
189                                                              0, G_MAXINT, 7,
190                                                              G_PARAM_READWRITE));
191
192   /**
193    * GtkProgressBar:min-horizontal-bar-width:
194    *
195    * The minimum horizontal width of the progress bar.
196    *
197    * Since: 2.14
198    */
199   gtk_widget_class_install_style_property (widget_class,
200                                            g_param_spec_int ("min-horizontal-bar-width",
201                                                              P_("Min horizontal bar width"),
202                                                              P_("The minimum horizontal width of the progress bar"),
203                                                              1, G_MAXINT, MIN_HORIZONTAL_BAR_WIDTH,
204                                                              G_PARAM_READWRITE));
205   /**
206    * GtkProgressBar:min-horizontal-bar-height:
207    *
208    * Minimum horizontal height of the progress bar.
209    *
210    * Since: 2.14
211    */
212   gtk_widget_class_install_style_property (widget_class,
213                                            g_param_spec_int ("min-horizontal-bar-height",
214                                                              P_("Min horizontal bar height"),
215                                                              P_("Minimum horizontal height of the progress bar"),
216                                                              1, G_MAXINT, MIN_HORIZONTAL_BAR_HEIGHT,
217                                                              G_PARAM_READWRITE));
218   /**
219    * GtkProgressBar:min-vertical-bar-width:
220    *
221    * The minimum vertical width of the progress bar.
222    *
223    * Since: 2.14
224    */
225   gtk_widget_class_install_style_property (widget_class,
226                                            g_param_spec_int ("min-vertical-bar-width",
227                                                              P_("Min vertical bar width"),
228                                                              P_("The minimum vertical width of the progress bar"),
229                                                              1, G_MAXINT, MIN_VERTICAL_BAR_WIDTH,
230                                                              G_PARAM_READWRITE));
231   /**
232    * GtkProgressBar:min-vertical-bar-height:
233    *
234    * The minimum vertical height of the progress bar.
235    *
236    * Since: 2.14
237    */
238   gtk_widget_class_install_style_property (widget_class,
239                                            g_param_spec_int ("min-vertical-bar-height",
240                                                              P_("Min vertical bar height"),
241                                                              P_("The minimum vertical height of the progress bar"),
242                                                              1, G_MAXINT, MIN_VERTICAL_BAR_HEIGHT,
243                                                              G_PARAM_READWRITE));
244
245   g_type_class_add_private (class, sizeof (GtkProgressBarPriv));
246 }
247
248 static void
249 gtk_progress_bar_init (GtkProgressBar *pbar)
250 {
251   GtkProgressBarPriv *priv;
252
253   pbar->priv = G_TYPE_INSTANCE_GET_PRIVATE (pbar,
254                                             GTK_TYPE_PROGRESS_BAR,
255                                             GtkProgressBarPriv);
256   priv = pbar->priv;
257
258   priv->blocks = 10;
259   priv->in_block = -1;
260   priv->orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
261   priv->pulse_fraction = 0.1;
262   priv->activity_pos = 0;
263   priv->activity_dir = 1;
264   priv->activity_step = 3;
265   priv->activity_blocks = 5;
266   priv->ellipsize = PANGO_ELLIPSIZE_NONE;
267   priv->show_text = FALSE;
268
269   priv->text = NULL;
270   priv->fraction = 0.0;
271 }
272
273 static void
274 gtk_progress_bar_realize (GtkWidget *widget)
275 {
276   GdkWindowAttr attributes;
277   gint attributes_mask;
278
279   gtk_widget_set_realized (widget, TRUE);
280
281   attributes.window_type = GDK_WINDOW_CHILD;
282   attributes.x = widget->allocation.x;
283   attributes.y = widget->allocation.y;
284   attributes.width = widget->allocation.width;
285   attributes.height = widget->allocation.height;
286   attributes.wclass = GDK_INPUT_OUTPUT;
287   attributes.visual = gtk_widget_get_visual (widget);
288   attributes.colormap = gtk_widget_get_colormap (widget);
289   attributes.event_mask = gtk_widget_get_events (widget);
290   attributes.event_mask |= GDK_EXPOSURE_MASK;
291
292   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
293   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
294                                    &attributes, attributes_mask);
295   gdk_window_set_user_data (widget->window, widget);
296
297   widget->style = gtk_style_attach (widget->style, widget->window);
298   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
299 }
300
301 static void
302 gtk_progress_bar_set_property (GObject      *object,
303                                guint         prop_id,
304                                const GValue *value,
305                                GParamSpec   *pspec)
306 {
307   GtkProgressBar *pbar;
308
309   pbar = GTK_PROGRESS_BAR (object);
310
311   switch (prop_id)
312     {
313     case PROP_ORIENTATION:
314       gtk_progress_bar_set_orientation (pbar, g_value_get_enum (value));
315       break;
316     case PROP_FRACTION:
317       gtk_progress_bar_set_fraction (pbar, g_value_get_double (value));
318       break;
319     case PROP_PULSE_STEP:
320       gtk_progress_bar_set_pulse_step (pbar, g_value_get_double (value));
321       break;
322     case PROP_TEXT:
323       gtk_progress_bar_set_text (pbar, g_value_get_string (value));
324       break;
325     case PROP_SHOW_TEXT:
326       gtk_progress_bar_set_show_text (pbar, g_value_get_boolean (value));
327       break;
328     case PROP_ELLIPSIZE:
329       gtk_progress_bar_set_ellipsize (pbar, g_value_get_enum (value));
330       break;
331     default:
332       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
333       break;
334     }
335 }
336
337 static void
338 gtk_progress_bar_get_property (GObject      *object,
339                                guint         prop_id,
340                                GValue       *value,
341                                GParamSpec   *pspec)
342 {
343   GtkProgressBar *pbar = GTK_PROGRESS_BAR (object);
344   GtkProgressBarPriv* priv = pbar->priv;
345
346   switch (prop_id)
347     {
348     case PROP_ORIENTATION:
349       g_value_set_enum (value, priv->orientation);
350       break;
351     case PROP_FRACTION:
352       g_value_set_double (value, priv->fraction);
353       break;
354     case PROP_PULSE_STEP:
355       g_value_set_double (value, priv->pulse_fraction);
356       break;
357     case PROP_TEXT:
358       g_value_set_string (value, priv->text);
359       break;
360     case PROP_SHOW_TEXT:
361       g_value_set_boolean (value, priv->show_text);
362       break;
363     case PROP_ELLIPSIZE:
364       g_value_set_enum (value, priv->ellipsize);
365       break;
366     default:
367       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
368       break;
369     }
370 }
371
372 GtkWidget*
373 gtk_progress_bar_new (void)
374 {
375   GtkWidget *pbar;
376
377   pbar = g_object_new (GTK_TYPE_PROGRESS_BAR, NULL);
378
379   return pbar;
380 }
381
382 static void
383 gtk_progress_bar_real_update (GtkProgressBar *pbar)
384 {
385   GtkProgressBarPriv *priv;
386   GtkWidget *widget;
387
388   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
389
390   priv = pbar->priv;
391   widget = GTK_WIDGET (pbar);
392
393   if (priv->activity_mode)
394     {
395       guint size;
396
397       /* advance the block */
398       if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
399           priv->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
400         {
401           /* Update our activity step. */
402           priv->activity_step = widget->allocation.width * priv->pulse_fraction;
403
404           size = MAX (2, widget->allocation.width / priv->activity_blocks);
405
406           if (priv->activity_dir == 0)
407             {
408               priv->activity_pos += priv->activity_step;
409               if (priv->activity_pos + size >= widget->allocation.width - widget->style->xthickness)
410                 {
411                   priv->activity_pos = widget->allocation.width -
412                     widget->style->xthickness - size;
413                   priv->activity_dir = 1;
414                 }
415             }
416           else
417             {
418               priv->activity_pos -= priv->activity_step;
419               if (priv->activity_pos <= widget->style->xthickness)
420                 {
421                   priv->activity_pos = widget->style->xthickness;
422                   priv->activity_dir = 0;
423                 }
424             }
425         }
426       else
427         {
428           /* Update our activity step. */
429           priv->activity_step = widget->allocation.height * priv->pulse_fraction;
430
431           size = MAX (2, widget->allocation.height / priv->activity_blocks);
432
433           if (priv->activity_dir == 0)
434             {
435               priv->activity_pos += priv->activity_step;
436               if (priv->activity_pos + size >= widget->allocation.height - widget->style->ythickness)
437                 {
438                   priv->activity_pos = widget->allocation.height -
439                     widget->style->ythickness - size;
440                   priv->activity_dir = 1;
441                 }
442             }
443           else
444             {
445               priv->activity_pos -= priv->activity_step;
446               if (priv->activity_pos <= widget->style->ythickness)
447                 {
448                   priv->activity_pos = widget->style->ythickness;
449                   priv->activity_dir = 0;
450                 }
451             }
452         }
453     }
454   gtk_widget_queue_draw (widget);
455 }
456
457 static void
458 gtk_progress_bar_finalize (GObject *object)
459 {
460   GtkProgressBar *pbar = GTK_PROGRESS_BAR (object);
461   GtkProgressBarPriv *priv = pbar->priv;
462
463   g_free (priv->text);
464
465   G_OBJECT_CLASS (gtk_progress_bar_parent_class)->finalize (object);
466 }
467
468 static gboolean
469 gtk_progress_bar_expose (GtkWidget      *widget,
470                          GdkEventExpose *event)
471 {
472   GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget);
473
474   if (gtk_widget_is_drawable (widget))
475     gtk_progress_bar_paint (pbar);
476
477   return FALSE;
478 }
479
480 static gchar *
481 get_current_text (GtkProgressBar *pbar)
482 {
483   GtkProgressBarPriv *priv = pbar->priv;
484
485   if (priv->text)
486     return g_strdup (priv->text);
487   else
488     return g_strdup_printf ("%.0f %%", priv->fraction * 100.0);
489 }
490
491 static void
492 gtk_progress_bar_size_request (GtkWidget      *widget,
493                                GtkRequisition *requisition)
494 {
495   GtkProgressBar *pbar;
496   GtkProgressBarPriv *priv;
497   gchar *buf;
498   PangoRectangle logical_rect;
499   PangoLayout *layout;
500   gint width, height;
501   gint xspacing, yspacing;
502   gint min_width, min_height;
503
504   g_return_if_fail (GTK_IS_PROGRESS_BAR (widget));
505   g_return_if_fail (requisition != NULL);
506
507   gtk_widget_style_get (widget,
508                         "xspacing", &xspacing,
509                         "yspacing", &yspacing,
510                         NULL);
511
512   pbar = GTK_PROGRESS_BAR (widget);
513   priv = pbar->priv;
514
515   width = 2 * widget->style->xthickness + xspacing;
516   height = 2 * widget->style->ythickness + yspacing;
517
518   if (priv->show_text)
519     {
520       buf = get_current_text (pbar);
521       layout = gtk_widget_create_pango_layout (widget, buf);
522
523       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
524
525       if (priv->ellipsize)
526         {
527           PangoContext *context;
528           PangoFontMetrics *metrics;
529           gint char_width;
530
531           /* The minimum size for ellipsized text is ~ 3 chars */
532           context = pango_layout_get_context (layout);
533           metrics = pango_context_get_metrics (context, widget->style->font_desc, pango_context_get_language (context));
534
535           char_width = pango_font_metrics_get_approximate_char_width (metrics);
536           pango_font_metrics_unref (metrics);
537
538           width += PANGO_PIXELS (char_width) * 3;
539         }
540       else
541         width += logical_rect.width;
542
543       height += logical_rect.height;
544
545       g_object_unref (layout);
546       g_free (buf);
547     }
548
549   if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
550       priv->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
551     gtk_widget_style_get (widget,
552                           "min-horizontal-bar-width", &min_width,
553                           "min-horizontal-bar-height", &min_height,
554                           NULL);
555   else
556     gtk_widget_style_get (widget,
557                           "min-vertical-bar-width", &min_width,
558                           "min-vertical-bar-height", &min_height,
559                           NULL);
560
561   requisition->width = MAX (min_width, width);
562   requisition->height = MAX (min_height, height);
563 }
564
565 static void
566 gtk_progress_bar_size_allocate (GtkWidget     *widget,
567                                 GtkAllocation *allocation)
568 {
569   widget->allocation = *allocation;
570
571   if (gtk_widget_get_realized (widget))
572     {
573       gdk_window_move_resize (widget->window,
574                               allocation->x, allocation->y,
575                               allocation->width, allocation->height);
576     }
577 }
578
579 static void
580 gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar)
581 {
582   GtkProgressBarPriv *priv = pbar->priv;
583   GtkWidget *widget = GTK_WIDGET (pbar);
584   GtkProgressBarOrientation orientation;
585
586   orientation = priv->orientation;
587   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
588     {
589       if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
590         orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
591       else if (priv->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
592         orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
593     }
594
595   /* calculate start pos */
596
597   if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
598       orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
599     {
600       if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
601         {
602           priv->activity_pos = widget->style->xthickness;
603           priv->activity_dir = 0;
604         }
605       else
606         {
607           priv->activity_pos = widget->allocation.width -
608             widget->style->xthickness - (widget->allocation.height -
609                 widget->style->ythickness * 2);
610           priv->activity_dir = 1;
611         }
612     }
613   else
614     {
615       if (orientation == GTK_PROGRESS_TOP_TO_BOTTOM)
616         {
617           priv->activity_pos = widget->style->ythickness;
618           priv->activity_dir = 0;
619         }
620       else
621         {
622           priv->activity_pos = widget->allocation.height -
623             widget->style->ythickness - (widget->allocation.width -
624                 widget->style->xthickness * 2);
625           priv->activity_dir = 1;
626         }
627     }
628 }
629
630 static void
631 gtk_progress_bar_get_activity (GtkProgressBar            *pbar,
632                                GtkProgressBarOrientation  orientation,
633                                gint                      *offset,
634                                gint                      *amount)
635 {
636   GtkProgressBarPriv *priv = pbar->priv;
637   GtkWidget *widget = GTK_WIDGET (pbar);
638
639   *offset = priv->activity_pos;
640
641   switch (orientation)
642     {
643     case GTK_PROGRESS_LEFT_TO_RIGHT:
644     case GTK_PROGRESS_RIGHT_TO_LEFT:
645       *amount = MAX (2, widget->allocation.width / priv->activity_blocks);
646       break;
647
648     case GTK_PROGRESS_TOP_TO_BOTTOM:
649     case GTK_PROGRESS_BOTTOM_TO_TOP:
650       *amount = MAX (2, widget->allocation.height / priv->activity_blocks);
651       break;
652     }
653 }
654
655 static void
656 gtk_progress_bar_paint_activity (GtkProgressBar            *pbar,
657                                  GtkProgressBarOrientation  orientation)
658 {
659   GtkWidget *widget = GTK_WIDGET (pbar);
660   GdkRectangle area;
661
662   switch (orientation)
663     {
664     case GTK_PROGRESS_LEFT_TO_RIGHT:
665     case GTK_PROGRESS_RIGHT_TO_LEFT:
666       gtk_progress_bar_get_activity (pbar, orientation, &area.x, &area.width);
667       area.y = widget->style->ythickness;
668       area.height = widget->allocation.height - 2 * widget->style->ythickness;
669       break;
670
671     case GTK_PROGRESS_TOP_TO_BOTTOM:
672     case GTK_PROGRESS_BOTTOM_TO_TOP:
673       gtk_progress_bar_get_activity (pbar, orientation, &area.y, &area.height);
674       area.x = widget->style->xthickness;
675       area.width = widget->allocation.width - 2 * widget->style->xthickness;
676       break;
677
678     default:
679       return;
680       break;
681     }
682
683   gtk_paint_box (widget->style,
684                  gtk_widget_get_window (widget),
685                  GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
686                  &area, widget, "bar",
687                  area.x, area.y, area.width, area.height);
688 }
689
690 static void
691 gtk_progress_bar_paint_continuous (GtkProgressBar            *pbar,
692                                    gint                       amount,
693                                    GtkProgressBarOrientation  orientation)
694 {
695   GtkWidget *widget = GTK_WIDGET (pbar);
696   GdkRectangle area;
697
698   if (amount <= 0)
699     return;
700
701   switch (orientation)
702     {
703     case GTK_PROGRESS_LEFT_TO_RIGHT:
704     case GTK_PROGRESS_RIGHT_TO_LEFT:
705       area.width = amount;
706       area.height = widget->allocation.height - widget->style->ythickness * 2;
707       area.y = widget->style->ythickness;
708
709       area.x = widget->style->xthickness;
710       if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
711         area.x = widget->allocation.width - amount - area.x;
712       break;
713
714     case GTK_PROGRESS_TOP_TO_BOTTOM:
715     case GTK_PROGRESS_BOTTOM_TO_TOP:
716       area.width = widget->allocation.width - widget->style->xthickness * 2;
717       area.height = amount;
718       area.x = widget->style->xthickness;
719
720       area.y = widget->style->ythickness;
721       if (orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
722         area.y = widget->allocation.height - amount - area.y;
723       break;
724
725     default:
726       return;
727       break;
728     }
729
730   gtk_paint_box (widget->style,
731                  gtk_widget_get_window (widget),
732                  GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
733                  &area, widget, "bar",
734                  area.x, area.y, area.width, area.height);
735 }
736
737 static void
738 gtk_progress_bar_paint_text (GtkProgressBar            *pbar,
739                              gint                       offset,
740                              gint                       amount,
741                              GtkProgressBarOrientation  orientation)
742 {
743   GtkProgressBarPriv *priv = pbar->priv;
744   GtkWidget *widget = GTK_WIDGET (pbar);
745   gint x;
746   gint y;
747   gchar *buf;
748   GdkRectangle rect;
749   PangoLayout *layout;
750   PangoRectangle logical_rect;
751   GdkRectangle prelight_clip, start_clip, end_clip;
752   gfloat text_xalign = 0.5;
753   gfloat text_yalign = 0.5;
754
755   if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
756     text_xalign = 1.0 - text_xalign;
757
758   buf = get_current_text (pbar);
759
760   layout = gtk_widget_create_pango_layout (widget, buf);
761   pango_layout_set_ellipsize (layout, priv->ellipsize);
762   if (priv->ellipsize)
763     pango_layout_set_width (layout, widget->allocation.width * PANGO_SCALE);
764
765   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
766
767   x = widget->style->xthickness + 1 + text_xalign *
768       (widget->allocation.width - 2 * widget->style->xthickness -
769        2 - logical_rect.width);
770
771   y = widget->style->ythickness + 1 + text_yalign *
772       (widget->allocation.height - 2 * widget->style->ythickness -
773        2 - logical_rect.height);
774
775   rect.x = widget->style->xthickness;
776   rect.y = widget->style->ythickness;
777   rect.width = widget->allocation.width - 2 * widget->style->xthickness;
778   rect.height = widget->allocation.height - 2 * widget->style->ythickness;
779
780   prelight_clip = start_clip = end_clip = rect;
781
782   switch (orientation)
783     {
784     case GTK_PROGRESS_LEFT_TO_RIGHT:
785       if (offset != -1)
786         prelight_clip.x = offset;
787       prelight_clip.width = amount;
788       start_clip.width = prelight_clip.x - start_clip.x;
789       end_clip.x = start_clip.x + start_clip.width + prelight_clip.width;
790       end_clip.width -= prelight_clip.width + start_clip.width;
791       break;
792
793     case GTK_PROGRESS_RIGHT_TO_LEFT:
794       if (offset != -1)
795         prelight_clip.x = offset;
796       else
797         prelight_clip.x = rect.x + rect.width - amount;
798       prelight_clip.width = amount;
799       start_clip.width = prelight_clip.x - start_clip.x;
800       end_clip.x = start_clip.x + start_clip.width + prelight_clip.width;
801       end_clip.width -= prelight_clip.width + start_clip.width;
802       break;
803
804     case GTK_PROGRESS_TOP_TO_BOTTOM:
805       if (offset != -1)
806         prelight_clip.y = offset;
807       prelight_clip.height = amount;
808       start_clip.height = prelight_clip.y - start_clip.y;
809       end_clip.y = start_clip.y + start_clip.height + prelight_clip.height;
810       end_clip.height -= prelight_clip.height + start_clip.height;
811       break;
812
813     case GTK_PROGRESS_BOTTOM_TO_TOP:
814       if (offset != -1)
815         prelight_clip.y = offset;
816       else
817         prelight_clip.y = rect.y + rect.height - amount;
818       prelight_clip.height = amount;
819       start_clip.height = prelight_clip.y - start_clip.y;
820       end_clip.y = start_clip.y + start_clip.height + prelight_clip.height;
821       end_clip.height -= prelight_clip.height + start_clip.height;
822       break;
823     }
824
825   if (start_clip.width > 0 && start_clip.height > 0)
826     gtk_paint_layout (widget->style,
827                       gtk_widget_get_window (widget),
828                       GTK_STATE_NORMAL,
829                       FALSE,
830                       &start_clip,
831                       widget,
832                       "progressbar",
833                       x, y,
834                       layout);
835
836   if (end_clip.width > 0 && end_clip.height > 0)
837     gtk_paint_layout (widget->style,
838                       gtk_widget_get_window (widget),
839                       GTK_STATE_NORMAL,
840                       FALSE,
841                       &end_clip,
842                       widget,
843                       "progressbar",
844                       x, y,
845                       layout);
846
847   gtk_paint_layout (widget->style,
848                     gtk_widget_get_window (widget),
849                     GTK_STATE_PRELIGHT,
850                     FALSE,
851                     &prelight_clip,
852                     widget,
853                     "progressbar",
854                     x, y,
855                     layout);
856
857   g_object_unref (layout);
858   g_free (buf);
859 }
860
861 static void
862 gtk_progress_bar_paint (GtkProgressBar *pbar)
863 {
864   GtkProgressBarPriv *priv = pbar->priv;
865   GtkWidget *widget = GTK_WIDGET (pbar);
866   GtkProgressBarOrientation orientation;
867
868   orientation = priv->orientation;
869   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
870     {
871       if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
872         orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
873       else if (priv->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
874         orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
875     }
876
877   gtk_paint_box (widget->style,
878                  gtk_widget_get_window (widget),
879                  GTK_STATE_NORMAL, GTK_SHADOW_IN,
880                  NULL, widget, "trough",
881                  0, 0,
882                  widget->allocation.width,
883                  widget->allocation.height);
884
885   if (priv->activity_mode)
886     {
887       gtk_progress_bar_paint_activity (pbar, orientation);
888
889       if (priv->show_text)
890         {
891           gint offset;
892           gint amount;
893
894           gtk_progress_bar_get_activity (pbar, orientation, &offset, &amount);
895           gtk_progress_bar_paint_text (pbar, offset, amount, orientation);
896         }
897     }
898   else
899     {
900       gint amount;
901       gint space;
902
903       if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
904           orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
905         space = widget->allocation.width - 2 * widget->style->xthickness;
906       else
907         space = widget->allocation.height - 2 * widget->style->ythickness;
908
909       amount = space * gtk_progress_bar_get_fraction (pbar);
910
911       gtk_progress_bar_paint_continuous (pbar, amount, orientation);
912
913       if (priv->show_text)
914         gtk_progress_bar_paint_text (pbar, -1, amount, orientation);
915         }
916 }
917
918 static void
919 gtk_progress_bar_set_activity_mode (GtkProgressBar *pbar,
920                                     gboolean        activity_mode)
921 {
922   GtkProgressBarPriv *priv = pbar->priv;
923
924   activity_mode = !!activity_mode;
925
926   if (priv->activity_mode != activity_mode)
927     {
928       priv->activity_mode = activity_mode;
929
930       if (priv->activity_mode)
931         gtk_progress_bar_act_mode_enter (pbar);
932
933       if (gtk_widget_is_drawable (GTK_WIDGET (pbar)))
934         gtk_widget_queue_resize (GTK_WIDGET (pbar));
935     }
936 }
937
938 /**
939  * gtk_progress_bar_set_fraction:
940  * @pbar: a #GtkProgressBar
941  * @fraction: fraction of the task that's been completed
942  *
943  * Causes the progress bar to "fill in" the given fraction
944  * of the bar. The fraction should be between 0.0 and 1.0,
945  * inclusive.
946  *
947  **/
948 void
949 gtk_progress_bar_set_fraction (GtkProgressBar *pbar,
950                                gdouble         fraction)
951 {
952   GtkProgressBarPriv* priv;
953
954   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
955
956   priv = pbar->priv;
957
958   priv->fraction = fraction;
959   gtk_progress_bar_set_activity_mode (pbar, FALSE);
960   gtk_progress_bar_real_update (pbar);
961
962   g_object_notify (G_OBJECT (pbar), "fraction");
963 }
964
965 /**
966  * gtk_progress_bar_pulse:
967  * @pbar: a #GtkProgressBar
968  *
969  * Indicates that some progress is made, but you don't know how much.
970  * Causes the progress bar to enter "activity mode," where a block
971  * bounces back and forth. Each call to gtk_progress_bar_pulse()
972  * causes the block to move by a little bit (the amount of movement
973  * per pulse is determined by gtk_progress_bar_set_pulse_step()).
974  **/
975 void
976 gtk_progress_bar_pulse (GtkProgressBar *pbar)
977 {
978   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
979
980   gtk_progress_bar_set_activity_mode (pbar, TRUE);
981   gtk_progress_bar_real_update (pbar);
982 }
983
984 /**
985  * gtk_progress_bar_set_text:
986  * @pbar: a #GtkProgressBar
987  * @text: (allow-none): a UTF-8 string, or %NULL
988  *
989  * Causes the given @text to appear superimposed on the progress bar.
990  **/
991 void
992 gtk_progress_bar_set_text (GtkProgressBar *pbar,
993                            const gchar    *text)
994 {
995   GtkProgressBarPriv *priv;
996
997   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
998
999   priv = pbar->priv;
1000
1001   g_free (priv->text);
1002   priv->text = text && *text ? g_strdup (text) : NULL;
1003
1004   if (gtk_widget_is_drawable (GTK_WIDGET (pbar)))
1005     gtk_widget_queue_resize (GTK_WIDGET (pbar));
1006
1007   g_object_notify (G_OBJECT (pbar), "text");
1008 }
1009
1010 /**
1011  * gtk_progress_bar_set_show_text:
1012  * @pbar: a #GtkProgressBar
1013  * @show_text: whether to show superimposed text
1014  *
1015  * Sets whether the progressbar will show text superimposed
1016  * over the bar. The shown text is either the value of
1017  * the #GtkProgressBar::text property or, if that is %NULL,
1018  * the #GtkProgressBar::fraction value, as a percentage.
1019  *
1020  * Since: 3.0
1021  */
1022 void
1023 gtk_progress_bar_set_show_text (GtkProgressBar *pbar,
1024                                 gboolean        show_text)
1025 {
1026   GtkProgressBarPriv *priv;
1027
1028   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1029
1030   priv = pbar->priv;
1031
1032   show_text = !!show_text;
1033
1034   if (priv->show_text != show_text)
1035     {
1036       priv->show_text = show_text;
1037
1038       if (gtk_widget_is_drawable (GTK_WIDGET (pbar)))
1039         gtk_widget_queue_resize (GTK_WIDGET (pbar));
1040
1041       g_object_notify (G_OBJECT (pbar), "show-text");
1042     }
1043 }
1044
1045 /**
1046  * gtk_progress_bar_get_show_text:
1047  * @pbar: a #GtkProgressBar
1048  *
1049  * Gets the value of the #GtkProgressBar::show-text property.
1050  * See gtk_progress_bar_set_show_text().
1051  *
1052  * Returns: %TRUE if text is shown in the progress bar
1053  *
1054  * Since: 3.0
1055  */
1056 gboolean
1057 gtk_progress_bar_get_show_text (GtkProgressBar *pbar)
1058 {
1059   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), FALSE);
1060
1061   return pbar->priv->show_text;
1062 }
1063
1064 /**
1065  * gtk_progress_bar_set_pulse_step:
1066  * @pbar: a #GtkProgressBar
1067  * @fraction: fraction between 0.0 and 1.0
1068  *
1069  * Sets the fraction of total progress bar length to move the
1070  * bouncing block for each call to gtk_progress_bar_pulse().
1071  **/
1072 void
1073 gtk_progress_bar_set_pulse_step (GtkProgressBar *pbar,
1074                                  gdouble         fraction)
1075 {
1076   GtkProgressBarPriv *priv;
1077
1078   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1079
1080   priv = pbar->priv;
1081
1082   priv->pulse_fraction = fraction;
1083
1084   g_object_notify (G_OBJECT (pbar), "pulse-step");
1085 }
1086
1087 /**
1088  * gtk_progress_bar_set_orientation:
1089  * @pbar: a #GtkProgressBar
1090  * @orientation: orientation of the progress bar
1091  *
1092  * Causes the progress bar to switch to a different orientation
1093  * (left-to-right, right-to-left, top-to-bottom, or bottom-to-top).
1094  **/
1095 void
1096 gtk_progress_bar_set_orientation (GtkProgressBar           *pbar,
1097                                   GtkProgressBarOrientation orientation)
1098 {
1099   GtkProgressBarPriv *priv;
1100
1101   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1102
1103   priv = pbar->priv;
1104
1105   if (priv->orientation != orientation)
1106     {
1107       priv->orientation = orientation;
1108
1109       if (gtk_widget_is_drawable (GTK_WIDGET (pbar)))
1110         gtk_widget_queue_resize (GTK_WIDGET (pbar));
1111
1112       g_object_notify (G_OBJECT (pbar), "orientation");
1113     }
1114 }
1115
1116 /**
1117  * gtk_progress_bar_get_text:
1118  * @pbar: a #GtkProgressBar
1119  *
1120  * Retrieves the text displayed superimposed on the progress bar,
1121  * if any, otherwise %NULL. The return value is a reference
1122  * to the text, not a copy of it, so will become invalid
1123  * if you change the text in the progress bar.
1124  *
1125  * Return value: text, or %NULL; this string is owned by the widget
1126  * and should not be modified or freed.
1127  **/
1128 G_CONST_RETURN gchar*
1129 gtk_progress_bar_get_text (GtkProgressBar *pbar)
1130 {
1131   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), NULL);
1132
1133   return pbar->priv->text;
1134 }
1135
1136 /**
1137  * gtk_progress_bar_get_fraction:
1138  * @pbar: a #GtkProgressBar
1139  *
1140  * Returns the current fraction of the task that's been completed.
1141  *
1142  * Return value: a fraction from 0.0 to 1.0
1143  **/
1144 gdouble
1145 gtk_progress_bar_get_fraction (GtkProgressBar *pbar)
1146 {
1147   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1148
1149   return pbar->priv->fraction;
1150 }
1151
1152 /**
1153  * gtk_progress_bar_get_pulse_step:
1154  * @pbar: a #GtkProgressBar
1155  *
1156  * Retrieves the pulse step set with gtk_progress_bar_set_pulse_step()
1157  *
1158  * Return value: a fraction from 0.0 to 1.0
1159  **/
1160 gdouble
1161 gtk_progress_bar_get_pulse_step (GtkProgressBar *pbar)
1162 {
1163   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1164
1165   return pbar->priv->pulse_fraction;
1166 }
1167
1168 /**
1169  * gtk_progress_bar_get_orientation:
1170  * @pbar: a #GtkProgressBar
1171  *
1172  * Retrieves the current progress bar orientation.
1173  *
1174  * Return value: orientation of the progress bar
1175  **/
1176 GtkProgressBarOrientation
1177 gtk_progress_bar_get_orientation (GtkProgressBar *pbar)
1178 {
1179   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1180
1181   return pbar->priv->orientation;
1182 }
1183
1184 /**
1185  * gtk_progress_bar_set_ellipsize:
1186  * @pbar: a #GtkProgressBar
1187  * @mode: a #PangoEllipsizeMode
1188  *
1189  * Sets the mode used to ellipsize (add an ellipsis: "...") the text
1190  * if there is not enough space to render the entire string.
1191  *
1192  * Since: 2.6
1193  **/
1194 void
1195 gtk_progress_bar_set_ellipsize (GtkProgressBar     *pbar,
1196                                 PangoEllipsizeMode  mode)
1197 {
1198   GtkProgressBarPriv *priv;
1199
1200   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1201   g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE &&
1202                     mode <= PANGO_ELLIPSIZE_END);
1203
1204   priv = pbar->priv;
1205
1206   if ((PangoEllipsizeMode)priv->ellipsize != mode)
1207     {
1208       priv->ellipsize = mode;
1209
1210       g_object_notify (G_OBJECT (pbar), "ellipsize");
1211       gtk_widget_queue_resize (GTK_WIDGET (pbar));
1212     }
1213 }
1214
1215 /**
1216  * gtk_progress_bar_get_ellipsize:
1217  * @pbar: a #GtkProgressBar
1218  *
1219  * Returns the ellipsizing position of the progressbar.
1220  * See gtk_progress_bar_set_ellipsize().
1221  *
1222  * Return value: #PangoEllipsizeMode
1223  *
1224  * Since: 2.6
1225  **/
1226 PangoEllipsizeMode
1227 gtk_progress_bar_get_ellipsize (GtkProgressBar *pbar)
1228 {
1229   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), PANGO_ELLIPSIZE_NONE);
1230
1231   return pbar->priv->ellipsize;
1232 }