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