Bug 736411 - Ruler updates cause slowdown when painting
We now avoid drawing rulers in the position property setter and use gtk's region invalidation instead. Previously, we were basically redrawing the ruler inside the mouse event handler, which is pure evil.
This commit is contained in:
@ -69,12 +69,10 @@ typedef struct
|
||||
|
||||
GdkWindow *input_window;
|
||||
cairo_surface_t *backing_store;
|
||||
gboolean backing_store_valid;
|
||||
PangoLayout *layout;
|
||||
gdouble font_scale;
|
||||
|
||||
gint xsrc;
|
||||
gint ysrc;
|
||||
|
||||
GList *track_widgets;
|
||||
} GimpRulerPrivate;
|
||||
|
||||
@ -119,6 +117,8 @@ static gboolean gimp_ruler_expose (GtkWidget *widget,
|
||||
GdkEventExpose *event);
|
||||
|
||||
static void gimp_ruler_draw_ticks (GimpRuler *ruler);
|
||||
static GdkRectangle gimp_ruler_get_pos_rect (GimpRuler *ruler,
|
||||
gdouble position);
|
||||
static void gimp_ruler_draw_pos (GimpRuler *ruler,
|
||||
cairo_t *cr);
|
||||
static void gimp_ruler_make_pixmap (GimpRuler *ruler);
|
||||
@ -228,14 +228,15 @@ gimp_ruler_init (GimpRuler *ruler)
|
||||
|
||||
gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE);
|
||||
|
||||
priv->orientation = GTK_ORIENTATION_HORIZONTAL;
|
||||
priv->unit = GIMP_PIXELS;
|
||||
priv->lower = 0;
|
||||
priv->upper = 0;
|
||||
priv->position = 0;
|
||||
priv->max_size = 0;
|
||||
priv->backing_store = NULL;
|
||||
priv->font_scale = DEFAULT_RULER_FONT_SCALE;
|
||||
priv->orientation = GTK_ORIENTATION_HORIZONTAL;
|
||||
priv->unit = GIMP_PIXELS;
|
||||
priv->lower = 0;
|
||||
priv->upper = 0;
|
||||
priv->position = 0;
|
||||
priv->max_size = 0;
|
||||
priv->backing_store = NULL;
|
||||
priv->backing_store_valid = FALSE;
|
||||
priv->font_scale = DEFAULT_RULER_FONT_SCALE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -573,6 +574,7 @@ gimp_ruler_set_unit (GimpRuler *ruler,
|
||||
priv->unit = unit;
|
||||
g_object_notify (G_OBJECT (ruler), "unit");
|
||||
|
||||
priv->backing_store_valid = FALSE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (ruler));
|
||||
}
|
||||
}
|
||||
@ -614,10 +616,28 @@ gimp_ruler_set_position (GimpRuler *ruler,
|
||||
|
||||
if (priv->position != position)
|
||||
{
|
||||
gdouble old_pos = priv->position;
|
||||
|
||||
priv->position = position;
|
||||
g_object_notify (G_OBJECT (ruler), "position");
|
||||
|
||||
gimp_ruler_draw_pos (ruler, NULL);
|
||||
{
|
||||
GdkRectangle rect;
|
||||
|
||||
rect = gimp_ruler_get_pos_rect (ruler, old_pos);
|
||||
gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height);
|
||||
|
||||
rect = gimp_ruler_get_pos_rect (ruler, position);
|
||||
gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
|
||||
rect.x,
|
||||
rect.y,
|
||||
rect.width,
|
||||
rect.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -679,6 +699,7 @@ gimp_ruler_set_range (GimpRuler *ruler,
|
||||
}
|
||||
g_object_thaw_notify (G_OBJECT (ruler));
|
||||
|
||||
priv->backing_store_valid = FALSE;
|
||||
gtk_widget_queue_draw (GTK_WIDGET (ruler));
|
||||
}
|
||||
|
||||
@ -759,6 +780,8 @@ gimp_ruler_unrealize (GtkWidget *widget)
|
||||
priv->backing_store = NULL;
|
||||
}
|
||||
|
||||
priv->backing_store_valid = FALSE;
|
||||
|
||||
if (priv->layout)
|
||||
{
|
||||
g_object_unref (priv->layout);
|
||||
@ -883,16 +906,16 @@ gimp_ruler_expose (GtkWidget *widget,
|
||||
GtkAllocation allocation;
|
||||
cairo_t *cr;
|
||||
|
||||
gimp_ruler_draw_ticks (ruler);
|
||||
if (! priv->backing_store_valid)
|
||||
gimp_ruler_draw_ticks (ruler);
|
||||
|
||||
cr = gdk_cairo_create (gtk_widget_get_window (widget));
|
||||
gdk_cairo_region (cr, event->region);
|
||||
cairo_clip (cr);
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
cairo_translate (cr, allocation.x, allocation.y);
|
||||
|
||||
cairo_set_source_surface (cr, priv->backing_store, 0, 0);
|
||||
cairo_set_source_surface (cr, priv->backing_store,
|
||||
allocation.x, allocation.y);
|
||||
cairo_paint (cr);
|
||||
|
||||
gimp_ruler_draw_pos (ruler, cr);
|
||||
@ -1137,27 +1160,30 @@ gimp_ruler_draw_ticks (GimpRuler *ruler)
|
||||
}
|
||||
|
||||
cairo_fill (cr);
|
||||
|
||||
priv->backing_store_valid = TRUE;
|
||||
|
||||
out:
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_ruler_draw_pos (GimpRuler *ruler,
|
||||
cairo_t *cr)
|
||||
static GdkRectangle
|
||||
gimp_ruler_get_pos_rect (GimpRuler *ruler, gdouble position)
|
||||
{
|
||||
GdkRectangle rect = {0, };
|
||||
|
||||
GtkWidget *widget = GTK_WIDGET (ruler);
|
||||
GtkStyle *style = gtk_widget_get_style (widget);
|
||||
GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler);
|
||||
GtkStateType state = gtk_widget_get_state (widget);
|
||||
GtkAllocation allocation;
|
||||
gint x, y;
|
||||
gint width, height;
|
||||
gint bs_width, bs_height;
|
||||
gint xthickness;
|
||||
gint ythickness;
|
||||
gdouble upper, lower;
|
||||
gdouble increment;
|
||||
|
||||
if (! gtk_widget_is_drawable (widget))
|
||||
return;
|
||||
return rect;
|
||||
|
||||
gtk_widget_get_allocation (widget, &allocation);
|
||||
|
||||
@ -1169,91 +1195,79 @@ gimp_ruler_draw_pos (GimpRuler *ruler,
|
||||
width = allocation.width;
|
||||
height = allocation.height - ythickness * 2;
|
||||
|
||||
bs_width = height / 2 + 2;
|
||||
bs_width |= 1; /* make sure it's odd */
|
||||
bs_height = bs_width / 2 + 1;
|
||||
rect.width = height / 2 + 2;
|
||||
rect.width |= 1; /* make sure it's odd */
|
||||
rect.height = rect.width / 2 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = allocation.width - xthickness * 2;
|
||||
height = allocation.height;
|
||||
|
||||
bs_height = width / 2 + 2;
|
||||
bs_height |= 1; /* make sure it's odd */
|
||||
bs_width = bs_height / 2 + 1;
|
||||
rect.height = width / 2 + 2;
|
||||
rect.height |= 1; /* make sure it's odd */
|
||||
rect.width = rect.height / 2 + 1;
|
||||
}
|
||||
|
||||
if ((bs_width > 0) && (bs_height > 0))
|
||||
gimp_ruler_get_range (ruler, &lower, &upper, NULL);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
gdouble lower;
|
||||
gdouble upper;
|
||||
gdouble position;
|
||||
gdouble increment;
|
||||
increment = (gdouble) width / (upper - lower);
|
||||
|
||||
if (! cr)
|
||||
{
|
||||
cr = gdk_cairo_create (gtk_widget_get_window (widget));
|
||||
rect.x = ROUND ((position - lower) * increment) + (xthickness - rect.width) / 2 - 1;
|
||||
rect.y = (height + rect.height) / 2 + ythickness;
|
||||
}
|
||||
else
|
||||
{
|
||||
increment = (gdouble) height / (upper - lower);
|
||||
|
||||
cairo_rectangle (cr,
|
||||
allocation.x, allocation.y,
|
||||
allocation.width, allocation.height);
|
||||
cairo_clip (cr);
|
||||
rect.x = (width + rect.width) / 2 + xthickness;
|
||||
rect.y = ROUND ((position - lower) * increment) + (ythickness - rect.height) / 2 - 1;
|
||||
}
|
||||
|
||||
cairo_translate (cr, allocation.x, allocation.y);
|
||||
rect.x += allocation.x;
|
||||
rect.y += allocation.y;
|
||||
|
||||
/* If a backing store exists, restore the ruler */
|
||||
if (priv->backing_store)
|
||||
{
|
||||
cairo_set_source_surface (cr, priv->backing_store, 0, 0);
|
||||
cairo_rectangle (cr, priv->xsrc, priv->ysrc, bs_width, bs_height);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_reference (cr);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
position = gimp_ruler_get_position (ruler);
|
||||
static void
|
||||
gimp_ruler_draw_pos (GimpRuler *ruler, cairo_t *cr)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (ruler);
|
||||
GtkStyle *style = gtk_widget_get_style (widget);
|
||||
GimpRulerPrivate *priv = GIMP_RULER_GET_PRIVATE (ruler);
|
||||
GtkStateType state = gtk_widget_get_state (widget);
|
||||
GdkRectangle pos_rect;
|
||||
|
||||
gimp_ruler_get_range (ruler, &lower, &upper, NULL);
|
||||
if (! gtk_widget_is_drawable (widget))
|
||||
return;
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
increment = (gdouble) width / (upper - lower);
|
||||
|
||||
x = ROUND ((position - lower) * increment) + (xthickness - bs_width) / 2 - 1;
|
||||
y = (height + bs_height) / 2 + ythickness;
|
||||
}
|
||||
else
|
||||
{
|
||||
increment = (gdouble) height / (upper - lower);
|
||||
|
||||
x = (width + bs_width) / 2 + xthickness;
|
||||
y = ROUND ((position - lower) * increment) + (ythickness - bs_height) / 2 - 1;
|
||||
}
|
||||
pos_rect = gimp_ruler_get_pos_rect (ruler, gimp_ruler_get_position (ruler));
|
||||
|
||||
if ((pos_rect.width > 0) && (pos_rect.height > 0))
|
||||
{
|
||||
gdk_cairo_set_source_color (cr, &style->fg[state]);
|
||||
|
||||
cairo_move_to (cr, x, y);
|
||||
cairo_move_to (cr, pos_rect.x, pos_rect.y);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
cairo_line_to (cr, x + bs_width / 2.0, y + bs_height);
|
||||
cairo_line_to (cr, x + bs_width, y);
|
||||
cairo_line_to (cr, pos_rect.x + pos_rect.width / 2.0,
|
||||
pos_rect.y + pos_rect.height);
|
||||
cairo_line_to (cr, pos_rect.x + pos_rect.width,
|
||||
pos_rect.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_line_to (cr, x + bs_width, y + bs_height / 2.0);
|
||||
cairo_line_to (cr, x, y + bs_height);
|
||||
cairo_line_to (cr, pos_rect.x + pos_rect.width,
|
||||
pos_rect.y + pos_rect.height / 2.0);
|
||||
cairo_line_to (cr, pos_rect.x,
|
||||
pos_rect.y + pos_rect.height);
|
||||
}
|
||||
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
|
||||
priv->xsrc = x;
|
||||
priv->ysrc = y;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1274,6 +1288,8 @@ gimp_ruler_make_pixmap (GimpRuler *ruler)
|
||||
CAIRO_CONTENT_COLOR,
|
||||
allocation.width,
|
||||
allocation.height);
|
||||
|
||||
priv->backing_store_valid = FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user