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