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