From eae9513cbda36f8cc70143e387c5017c83f80689 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 10 Nov 2013 01:20:27 -0500 Subject: Make activity mode progress bars animate better Use a tick callback and move the block each frame, instead of making it jump only when gtk_progress_bar_pulse() is called. --- gtk/gtkprogressbar.c | 130 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 40 deletions(-) (limited to 'gtk/gtkprogressbar.c') diff --git a/gtk/gtkprogressbar.c b/gtk/gtkprogressbar.c index 39e438876f..00080bb3fd 100644 --- a/gtk/gtkprogressbar.c +++ b/gtk/gtkprogressbar.c @@ -80,6 +80,11 @@ struct _GtkProgressBarPrivate GtkOrientation orientation; + guint tick_id; + gint64 pulse1; + gint64 pulse2; + gint64 frame1; + guint activity_dir : 1; guint activity_mode : 1; guint ellipsize : 3; @@ -113,10 +118,10 @@ static void gtk_progress_bar_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); -static void gtk_progress_bar_real_update (GtkProgressBar *progress); static gboolean gtk_progress_bar_draw (GtkWidget *widget, cairo_t *cr); static void gtk_progress_bar_act_mode_enter (GtkProgressBar *progress); +static void gtk_progress_bar_act_mode_leave (GtkProgressBar *progress); static void gtk_progress_bar_finalize (GObject *object); static void gtk_progress_bar_set_orientation (GtkProgressBar *progress, GtkOrientation orientation); @@ -407,48 +412,15 @@ gtk_progress_bar_new (void) return pbar; } -static void -gtk_progress_bar_real_update (GtkProgressBar *pbar) -{ - GtkProgressBarPrivate *priv; - GtkWidget *widget; - - g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); - - priv = pbar->priv; - widget = GTK_WIDGET (pbar); - - if (priv->activity_mode) - { - /* advance the block */ - if (priv->activity_dir == 0) - { - priv->activity_pos += priv->pulse_fraction; - if (priv->activity_pos > 1.0) - { - priv->activity_pos = 1.0; - priv->activity_dir = 1; - } - } - else - { - priv->activity_pos -= priv->pulse_fraction; - if (priv->activity_pos <= 0) - { - priv->activity_pos = 0; - priv->activity_dir = 0; - } - } - } - gtk_widget_queue_draw (widget); -} - static void gtk_progress_bar_finalize (GObject *object) { GtkProgressBar *pbar = GTK_PROGRESS_BAR (object); GtkProgressBarPrivate *priv = pbar->priv; + if (priv->activity_mode) + gtk_progress_bar_act_mode_leave (pbar); + g_free (priv->text); G_OBJECT_CLASS (gtk_progress_bar_parent_class)->finalize (object); @@ -597,6 +569,58 @@ gtk_progress_bar_get_preferred_height (GtkWidget *widget, *minimum = *natural = MAX (min_height, height); } +static gboolean +tick_cb (GtkWidget *widget, + GdkFrameClock *frame_clock, + gpointer user_data) +{ + GtkProgressBar *pbar = GTK_PROGRESS_BAR (widget); + GtkProgressBarPrivate *priv = pbar->priv; + gint64 frame2; + gdouble fraction; + + frame2 = gdk_frame_clock_get_frame_time (frame_clock); + if (priv->frame1 == 0) + priv->frame1 = frame2 - 16667; + if (priv->pulse1 == 0) + priv->pulse1 = priv->pulse2 - 250 * 1000000; + + g_assert (priv->pulse2 > priv->pulse1); + g_assert (frame2 > priv->frame1); + + /* Determine the fraction to move the block from one frame + * to the next when pulse_fraction is how far the block should + * move between two calls to gtk_progress_bar_pulse(). + */ + fraction = priv->pulse_fraction * (frame2 - priv->frame1) / (priv->pulse2 - priv->pulse1); + + priv->frame1 = frame2; + + /* advance the block */ + if (priv->activity_dir == 0) + { + priv->activity_pos += fraction; + if (priv->activity_pos > 1.0) + { + priv->activity_pos = 1.0; + priv->activity_dir = 1; + } + } + else + { + priv->activity_pos -= fraction; + if (priv->activity_pos <= 0) + { + priv->activity_pos = 0; + priv->activity_dir = 0; + } + } + + gtk_widget_queue_draw (widget); + + return G_SOURCE_CONTINUE; +} + static void gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar) { @@ -648,6 +672,21 @@ gtk_progress_bar_act_mode_enter (GtkProgressBar *pbar) priv->activity_dir = 1; } } + + priv->tick_id = gtk_widget_add_tick_callback (widget, tick_cb, NULL, NULL); + priv->pulse2 = 0; + priv->pulse1 = 0; + priv->frame1 = 0; +} + +static void +gtk_progress_bar_act_mode_leave (GtkProgressBar *pbar) +{ + GtkProgressBarPrivate *priv = pbar->priv; + + if (priv->tick_id) + gtk_widget_remove_tick_callback (GTK_WIDGET (pbar), priv->tick_id); + priv->tick_id = 0; } static void @@ -998,6 +1037,8 @@ gtk_progress_bar_set_activity_mode (GtkProgressBar *pbar, if (priv->activity_mode) gtk_progress_bar_act_mode_enter (pbar); + else + gtk_progress_bar_act_mode_leave (pbar); gtk_widget_queue_resize (GTK_WIDGET (pbar)); } @@ -1022,13 +1063,22 @@ gtk_progress_bar_set_fraction (GtkProgressBar *pbar, priv = pbar->priv; - priv->fraction = CLAMP(fraction, 0.0, 1.0); + priv->fraction = CLAMP (fraction, 0.0, 1.0); gtk_progress_bar_set_activity_mode (pbar, FALSE); - gtk_progress_bar_real_update (pbar); + gtk_widget_queue_draw (GTK_WIDGET (pbar)); g_object_notify (G_OBJECT (pbar), "fraction"); } +static void +gtk_progress_bar_update_pulse (GtkProgressBar *pbar) +{ + GtkProgressBarPrivate *priv = pbar->priv; + + priv->pulse1 = priv->pulse2; + priv->pulse2 = g_get_monotonic_time (); +} + /** * gtk_progress_bar_pulse: * @pbar: a #GtkProgressBar @@ -1045,7 +1095,7 @@ gtk_progress_bar_pulse (GtkProgressBar *pbar) g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar)); gtk_progress_bar_set_activity_mode (pbar, TRUE); - gtk_progress_bar_real_update (pbar); + gtk_progress_bar_update_pulse (pbar); } /** -- cgit v1.2.1