line-visualizer-row: adjust surface when time range changes

We can reuse the existing surface, but we need to render it
at an offset so that we aren't so shaky under scrolling.
This commit is contained in:
Christian Hergert
2016-09-30 18:07:39 -07:00
parent fef48610da
commit 974f0b45fb

View File

@ -51,12 +51,7 @@ typedef struct
* to render to the front buffer (during our ::draw vfunc). * to render to the front buffer (during our ::draw vfunc).
*/ */
cairo_surface_t *surface; cairo_surface_t *surface;
gint64 surface_begin_time;
/*
* We track the draw sequence so that we only "consume" the newest
* draw operation after a threaded render completes.
*/
guint draw_sequence;
/* /*
* Child widget to display the label in the upper corner. * Child widget to display the label in the upper corner.
@ -69,6 +64,10 @@ typedef struct
gdouble y_lower; gdouble y_lower;
gdouble y_upper; gdouble y_upper;
/* Cached copy of begin/end time for quick access */
gint64 begin_time;
gint64 end_time;
/* /*
* If we have a new counter discovered or the reader is set, we might * If we have a new counter discovered or the reader is set, we might
* want to delay loading until we return to the main loop. This can * want to delay loading until we return to the main loop. This can
@ -91,6 +90,7 @@ typedef struct
PointCache *cache; PointCache *cache;
GArray *lines; GArray *lines;
GdkRGBA color; GdkRGBA color;
gint64 begin_time;
gint scale_factor; gint scale_factor;
gint width; gint width;
gint height; gint height;
@ -123,6 +123,7 @@ static void sp_line_visualizer_row_render_async (SpLineVisualize
gpointer user_data); gpointer user_data);
static cairo_surface_t *sp_line_visualizer_row_render_finish (SpLineVisualizerRow *self, static cairo_surface_t *sp_line_visualizer_row_render_finish (SpLineVisualizerRow *self,
GAsyncResult *result, GAsyncResult *result,
gint64 *surface_begin_time,
GError **error); GError **error);
enum { enum {
@ -183,12 +184,13 @@ sp_line_visualizer_row_render_cb (GObject *object,
SpLineVisualizerRowPrivate *priv = sp_line_visualizer_row_get_instance_private (self); SpLineVisualizerRowPrivate *priv = sp_line_visualizer_row_get_instance_private (self);
g_autoptr(GError) error = NULL; g_autoptr(GError) error = NULL;
cairo_surface_t *surface; cairo_surface_t *surface;
gint64 surface_begin_time;
g_assert (SP_IS_LINE_VISUALIZER_ROW (self)); g_assert (SP_IS_LINE_VISUALIZER_ROW (self));
g_assert (G_IS_ASYNC_RESULT (result)); g_assert (G_IS_ASYNC_RESULT (result));
g_assert (user_data == NULL); g_assert (user_data == NULL);
surface = sp_line_visualizer_row_render_finish (self, result, &error); surface = sp_line_visualizer_row_render_finish (self, result, &surface_begin_time, &error);
if (surface == NULL) if (surface == NULL)
{ {
@ -197,7 +199,9 @@ sp_line_visualizer_row_render_cb (GObject *object,
} }
g_clear_pointer (&priv->surface, cairo_surface_destroy); g_clear_pointer (&priv->surface, cairo_surface_destroy);
priv->surface = surface; priv->surface = surface;
priv->surface_begin_time = surface_begin_time;
gtk_widget_queue_draw (GTK_WIDGET (self)); gtk_widget_queue_draw (GTK_WIDGET (self));
} }
@ -249,6 +253,17 @@ adjust_alloc_for_borders (SpLineVisualizerRow *self,
subtract_border (alloc, &border); subtract_border (alloc, &border);
} }
static inline gdouble
get_x_for_time (SpLineVisualizerRow *self,
const GtkAllocation *alloc,
gint64 t)
{
SpLineVisualizerRowPrivate *priv = sp_line_visualizer_row_get_instance_private (self);
gint64 timespan = priv->end_time - priv->begin_time;
gdouble x_ratio = (gdouble)(t - priv->begin_time) / (gdouble)timespan;
return alloc->width * x_ratio;
}
static gboolean static gboolean
sp_line_visualizer_row_draw (GtkWidget *widget, sp_line_visualizer_row_draw (GtkWidget *widget,
cairo_t *cr) cairo_t *cr)
@ -271,6 +286,7 @@ sp_line_visualizer_row_draw (GtkWidget *widget,
gint scale_factor = gtk_widget_get_scale_factor (widget); gint scale_factor = gtk_widget_get_scale_factor (widget);
gint width; gint width;
gint height; gint height;
gint x_offset = 0;
width = cairo_image_surface_get_width (priv->surface) / scale_factor; width = cairo_image_surface_get_width (priv->surface) / scale_factor;
height = cairo_image_surface_get_height (priv->surface) / scale_factor; height = cairo_image_surface_get_height (priv->surface) / scale_factor;
@ -290,12 +306,19 @@ sp_line_visualizer_row_draw (GtkWidget *widget,
return ret; return ret;
} }
/*
* If we have moved our time range since we last rendered, then we
* might need to adjust the x_offset when reusing this cached surface.
*/
if (priv->surface_begin_time != priv->begin_time)
x_offset = get_x_for_time (self, &alloc, priv->surface_begin_time);
/* /*
* This is our ideal path, where we have a 1-to-1 match of our backing * This is our ideal path, where we have a 1-to-1 match of our backing
* surface matching the widgets current allocation. * surface matching the widgets current allocation.
*/ */
cairo_rectangle (cr, 0, 0, alloc.width, alloc.height); cairo_rectangle (cr, 0, 0, alloc.width, alloc.height);
cairo_set_source_surface (cr, priv->surface, 0, 0); cairo_set_source_surface (cr, priv->surface, x_offset, 0);
cairo_fill (cr); cairo_fill (cr);
} }
@ -454,10 +477,14 @@ sp_line_visualizer_row_set_time_range (SpVisualizerRow *row,
gint64 end_time) gint64 end_time)
{ {
SpLineVisualizerRow *self = (SpLineVisualizerRow *)row; SpLineVisualizerRow *self = (SpLineVisualizerRow *)row;
SpLineVisualizerRowPrivate *priv = sp_line_visualizer_row_get_instance_private (self);
g_assert (SP_IS_LINE_VISUALIZER_ROW (row)); g_assert (SP_IS_LINE_VISUALIZER_ROW (row));
g_assert (begin_time <= end_time); g_assert (begin_time <= end_time);
priv->begin_time = begin_time;
priv->end_time = end_time;
sp_line_visualizer_row_queue_reload (self); sp_line_visualizer_row_queue_reload (self);
} }
@ -1006,6 +1033,8 @@ sp_line_visualizer_row_render_async (SpLineVisualizerRow *self,
render->height = alloc.height; render->height = alloc.height;
render->scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self)); render->scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self));
sp_visualizer_row_get_time_range (SP_VISUALIZER_ROW (self), &render->begin_time, NULL);
style_context = gtk_widget_get_style_context (GTK_WIDGET (self)); style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
state = gtk_widget_get_state_flags (GTK_WIDGET (self)); state = gtk_widget_get_state_flags (GTK_WIDGET (self));
gtk_style_context_get_color (style_context, state, &render->color); gtk_style_context_get_color (style_context, state, &render->color);
@ -1028,10 +1057,18 @@ sp_line_visualizer_row_render_async (SpLineVisualizerRow *self,
static cairo_surface_t * static cairo_surface_t *
sp_line_visualizer_row_render_finish (SpLineVisualizerRow *self, sp_line_visualizer_row_render_finish (SpLineVisualizerRow *self,
GAsyncResult *result, GAsyncResult *result,
gint64 *surface_begin_time,
GError **error) GError **error)
{ {
RenderData *render;
g_assert (SP_IS_LINE_VISUALIZER_ROW (self)); g_assert (SP_IS_LINE_VISUALIZER_ROW (self));
g_assert (G_IS_TASK (result)); g_assert (G_IS_TASK (result));
render = g_task_get_task_data (G_TASK (result));
if (surface_begin_time != NULL)
*surface_begin_time = render->begin_time;
return g_task_propagate_pointer (G_TASK (result), error); return g_task_propagate_pointer (G_TASK (result), error);
} }