diff --git a/src/st/st-theme-node-drawing.c b/src/st/st-theme-node-drawing.c index 3250536e6..b2f88c2fe 100644 --- a/src/st/st-theme-node-drawing.c +++ b/src/st/st-theme-node-drawing.c @@ -462,7 +462,6 @@ get_background_coordinates (StThemeNode *node, static void get_background_position (StThemeNode *self, - StThemeNodePaintState *state, const ClutterActorBox *allocation, ClutterActorBox *result, ClutterActorBox *texture_coords) @@ -473,8 +472,8 @@ get_background_position (StThemeNode *self, gdouble scale_w, scale_h; /* get the background image size */ - background_image_width = cogl_texture_get_width (state->background_texture); - background_image_height = cogl_texture_get_height (state->background_texture); + background_image_width = cogl_texture_get_width (self->background_texture); + background_image_height = cogl_texture_get_height (self->background_texture); /* get the painting area size */ painting_area_width = allocation->x2 - allocation->x1; @@ -1274,26 +1273,117 @@ static void st_theme_node_paint_borders (StThemeNode *node, const ClutterActorBox *box, guint8 paint_opacity); +void +st_theme_node_invalidate_border_image (StThemeNode *node) +{ + if (node->border_slices_texture != COGL_INVALID_HANDLE) + { + cogl_handle_unref (node->border_slices_texture); + node->border_slices_texture = COGL_INVALID_HANDLE; + } + + if (node->border_slices_material != COGL_INVALID_HANDLE) + { + cogl_handle_unref (node->border_slices_material); + node->border_slices_material = COGL_INVALID_HANDLE; + } +} + +static gboolean +st_theme_node_load_border_image (StThemeNode *node) +{ + if (node->border_slices_texture == COGL_INVALID_HANDLE) + { + StBorderImage *border_image; + + border_image = st_theme_node_get_border_image (node); + if (border_image == NULL) + goto out; + + const char *filename; + filename = st_border_image_get_filename (border_image); + node->border_slices_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (), + filename); + if (node->border_slices_texture == COGL_INVALID_HANDLE) + goto out; + + node->border_slices_material = _st_create_texture_material (node->border_slices_texture); + } + + out: + return node->border_slices_texture != COGL_INVALID_HANDLE; +} + +void +st_theme_node_invalidate_background_image (StThemeNode *node) +{ + if (node->background_texture != COGL_INVALID_HANDLE) + { + cogl_handle_unref (node->background_texture); + node->background_texture = COGL_INVALID_HANDLE; + } + + if (node->background_material != COGL_INVALID_HANDLE) + { + cogl_handle_unref (node->background_material); + node->background_material = COGL_INVALID_HANDLE; + } + + if (node->background_shadow_material != COGL_INVALID_HANDLE) + { + cogl_handle_unref (node->background_shadow_material); + node->background_shadow_material = COGL_INVALID_HANDLE; + } +} + +static gboolean +st_theme_node_load_background_image (StThemeNode *node) +{ + if (node->background_texture == COGL_INVALID_HANDLE) + { + const char *background_image; + StShadow *background_image_shadow_spec; + + background_image = st_theme_node_get_background_image (node); + if (background_image == NULL) + goto out; + + background_image_shadow_spec = st_theme_node_get_background_image_shadow (node); + node->background_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (), + background_image); + if (node->background_texture == COGL_INVALID_HANDLE) + goto out; + + node->background_material = _st_create_texture_material (node->background_texture); + + if (node->background_repeat) + cogl_material_set_layer_wrap_mode (node->background_material, 0, COGL_MATERIAL_WRAP_MODE_REPEAT); + + if (background_image_shadow_spec) + { + node->background_shadow_material = _st_create_shadow_material (background_image_shadow_spec, + node->background_texture); + } + } + + out: + return node->background_texture != COGL_INVALID_HANDLE; +} + static void st_theme_node_render_resources (StThemeNode *node, StThemeNodePaintState *state, float width, float height) { - StTextureCache *texture_cache; - StBorderImage *border_image; gboolean has_border; gboolean has_border_radius; gboolean has_inset_box_shadow; gboolean has_large_corners; StShadow *box_shadow_spec; - StShadow *background_image_shadow_spec; - const char *background_image; g_return_if_fail (width > 0 && height > 0); - texture_cache = st_texture_cache_get_default (); - /* FIXME - need to separate this into things that need to be recomputed on * geometry change versus things that can be cached regardless, such as * a background image. @@ -1346,24 +1436,6 @@ st_theme_node_render_resources (StThemeNode *node, } } - /* Load referenced images from disk and draw anything we need with cairo now */ - background_image = st_theme_node_get_background_image (node); - border_image = st_theme_node_get_border_image (node); - - if (border_image) - { - const char *filename; - - filename = st_border_image_get_filename (border_image); - - state->border_slices_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, filename); - } - - if (state->border_slices_texture) - state->border_slices_material = _st_create_texture_material (state->border_slices_texture); - else - state->border_slices_material = COGL_INVALID_HANDLE; - state->corner_material[ST_CORNER_TOPLEFT] = st_theme_node_lookup_corner (node, width, height, ST_CORNER_TOPLEFT); state->corner_material[ST_CORNER_TOPRIGHT] = @@ -1384,7 +1456,7 @@ st_theme_node_render_resources (StThemeNode *node, */ if ((node->background_gradient_type != ST_GRADIENT_NONE) || (has_inset_box_shadow && (has_border || node->background_color.alpha > 0)) - || (background_image && (has_border || has_border_radius)) + || (st_theme_node_get_background_image (node) && (has_border || has_border_radius)) || has_large_corners) state->prerendered_texture = st_theme_node_prerender_background (node, width, height); @@ -1395,9 +1467,9 @@ st_theme_node_render_resources (StThemeNode *node, if (box_shadow_spec && !has_inset_box_shadow) { - if (state->border_slices_texture != COGL_INVALID_HANDLE) + if (st_theme_node_load_border_image (node)) state->box_shadow_material = _st_create_shadow_material (box_shadow_spec, - state->border_slices_texture); + node->border_slices_texture); else if (state->prerendered_texture != COGL_INVALID_HANDLE) state->box_shadow_material = _st_create_shadow_material (box_shadow_spec, state->prerendered_texture); @@ -1434,22 +1506,6 @@ st_theme_node_render_resources (StThemeNode *node, cogl_handle_unref (buffer); } } - - background_image_shadow_spec = st_theme_node_get_background_image_shadow (node); - if (background_image != NULL && !has_border && !has_border_radius) - { - state->background_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, background_image); - state->background_material = _st_create_texture_material (state->background_texture); - - if (node->background_repeat) - cogl_material_set_layer_wrap_mode (state->background_material, 0, COGL_MATERIAL_WRAP_MODE_REPEAT); - - if (background_image_shadow_spec) - { - state->background_shadow_material = _st_create_shadow_material (background_image_shadow_spec, - state->background_texture); - } - } } static void @@ -1738,7 +1794,6 @@ st_theme_node_paint_borders (StThemeNode *node, static void st_theme_node_paint_sliced_border_image (StThemeNode *node, - StThemeNodePaintState *state, float width, float height, guint8 paint_opacity) @@ -1756,8 +1811,8 @@ st_theme_node_paint_sliced_border_image (StThemeNode *node, st_border_image_get_borders (border_image, &border_left, &border_right, &border_top, &border_bottom); - img_width = cogl_texture_get_width (state->border_slices_texture); - img_height = cogl_texture_get_height (state->border_slices_texture); + img_width = cogl_texture_get_width (node->border_slices_texture); + img_height = cogl_texture_get_height (node->border_slices_texture); tx1 = border_left / img_width; tx2 = (img_width - border_right) / img_width; @@ -1772,7 +1827,7 @@ st_theme_node_paint_sliced_border_image (StThemeNode *node, if (ey < 0) ey = border_bottom; /* FIXME ? */ - material = state->border_slices_material; + material = node->border_slices_material; cogl_material_set_color4ub (material, paint_opacity, paint_opacity, paint_opacity, paint_opacity); @@ -1945,7 +2000,7 @@ st_theme_node_paint (StThemeNode *node, paint_opacity); if (state->prerendered_material != COGL_INVALID_HANDLE || - state->border_slices_material != COGL_INVALID_HANDLE) + st_theme_node_load_border_image (node)) { if (state->prerendered_material != COGL_INVALID_HANDLE) { @@ -1961,8 +2016,8 @@ st_theme_node_paint (StThemeNode *node, paint_opacity); } - if (state->border_slices_material != COGL_INVALID_HANDLE) - st_theme_node_paint_sliced_border_image (node, state, width, height, paint_opacity); + if (node->border_slices_material != COGL_INVALID_HANDLE) + st_theme_node_paint_sliced_border_image (node, width, height, paint_opacity); } else { @@ -1971,7 +2026,8 @@ st_theme_node_paint (StThemeNode *node, st_theme_node_paint_outline (node, box, paint_opacity); - if (state->background_texture != COGL_INVALID_HANDLE) + if (state->prerendered_material == COGL_INVALID_HANDLE && + st_theme_node_load_background_image (node)) { ClutterActorBox background_box; ClutterActorBox texture_coords; @@ -1983,7 +2039,7 @@ st_theme_node_paint (StThemeNode *node, */ has_visible_outline = st_theme_node_has_visible_outline (node); - get_background_position (node, state, &allocation, &background_box, &texture_coords); + get_background_position (node, &allocation, &background_box, &texture_coords); if (has_visible_outline || node->background_repeat) cogl_clip_push_rectangle (allocation.x1, allocation.y1, allocation.x2, allocation.y2); @@ -2001,13 +2057,13 @@ st_theme_node_paint (StThemeNode *node, * there is nothing (like a border, or the edge of the background color) * to logically confine it. */ - if (state->background_shadow_material != COGL_INVALID_HANDLE) + if (node->background_shadow_material != COGL_INVALID_HANDLE) _st_paint_shadow_with_opacity (node->background_image_shadow, - state->background_shadow_material, + node->background_shadow_material, &background_box, paint_opacity); - paint_material_with_opacity (state->background_material, + paint_material_with_opacity (node->background_material, &background_box, &texture_coords, paint_opacity); @@ -2022,16 +2078,6 @@ st_theme_node_paint_state_free (StThemeNodePaintState *state) { int corner_id; - if (state->background_texture != COGL_INVALID_HANDLE) - cogl_handle_unref (state->background_texture); - if (state->background_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->background_material); - if (state->background_shadow_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->background_shadow_material); - if (state->border_slices_texture != COGL_INVALID_HANDLE) - cogl_handle_unref (state->border_slices_texture); - if (state->border_slices_material != COGL_INVALID_HANDLE) - cogl_handle_unref (state->border_slices_material); if (state->prerendered_texture != COGL_INVALID_HANDLE) cogl_handle_unref (state->prerendered_texture); if (state->prerendered_material != COGL_INVALID_HANDLE) @@ -2051,12 +2097,7 @@ st_theme_node_paint_state_init (StThemeNodePaintState *state) { int corner_id; - state->background_texture = COGL_INVALID_HANDLE; - state->background_material = COGL_INVALID_HANDLE; - state->background_shadow_material = COGL_INVALID_HANDLE; state->box_shadow_material = COGL_INVALID_HANDLE; - state->border_slices_texture = COGL_INVALID_HANDLE; - state->border_slices_material = COGL_INVALID_HANDLE; state->prerendered_texture = COGL_INVALID_HANDLE; state->prerendered_material = COGL_INVALID_HANDLE; @@ -2078,18 +2119,8 @@ st_theme_node_paint_state_copy (StThemeNodePaintState *state, state->alloc_width = other->alloc_width; state->alloc_height = other->alloc_height; - if (other->background_shadow_material) - state->background_shadow_material = cogl_handle_ref (other->background_shadow_material); if (other->box_shadow_material) state->box_shadow_material = cogl_handle_ref (other->box_shadow_material); - if (other->background_texture) - state->background_texture = cogl_handle_ref (other->background_texture); - if (other->background_material) - state->background_material = cogl_handle_ref (other->background_material); - if (other->border_slices_texture) - state->border_slices_texture = cogl_handle_ref (other->border_slices_texture); - if (other->border_slices_material) - state->border_slices_material = cogl_handle_ref (other->border_slices_material); if (other->prerendered_texture) state->prerendered_texture = cogl_handle_ref (other->prerendered_texture); if (other->prerendered_material) diff --git a/src/st/st-theme-node-private.h b/src/st/st-theme-node-private.h index 0da4edb66..331343993 100644 --- a/src/st/st-theme-node-private.h +++ b/src/st/st-theme-node-private.h @@ -99,6 +99,12 @@ struct _StThemeNode { guint background_image_shadow_computed : 1; guint text_shadow_computed : 1; guint link_type : 2; + + CoglHandle border_slices_texture; + CoglHandle border_slices_material; + CoglHandle background_texture; + CoglHandle background_material; + CoglHandle background_shadow_material; }; struct _StThemeNodeClass { diff --git a/src/st/st-theme-node.c b/src/st/st-theme-node.c index ff712dcee..62980b1df 100644 --- a/src/st/st-theme-node.c +++ b/src/st/st-theme-node.c @@ -49,6 +49,11 @@ static void st_theme_node_init (StThemeNode *node) { node->transition_duration = -1; + node->background_texture = COGL_INVALID_HANDLE; + node->background_material = COGL_INVALID_HANDLE; + node->background_shadow_material = COGL_INVALID_HANDLE; + node->border_slices_texture = COGL_INVALID_HANDLE; + node->border_slices_material = COGL_INVALID_HANDLE; } static void @@ -151,6 +156,17 @@ st_theme_node_finalize (GObject *object) if (node->background_image) g_free (node->background_image); + if (node->background_texture != COGL_INVALID_HANDLE) + cogl_handle_unref (node->background_texture); + if (node->background_material != COGL_INVALID_HANDLE) + cogl_handle_unref (node->background_material); + if (node->background_shadow_material != COGL_INVALID_HANDLE) + cogl_handle_unref (node->background_shadow_material); + if (node->border_slices_texture != COGL_INVALID_HANDLE) + cogl_handle_unref (node->border_slices_texture); + if (node->border_slices_material != COGL_INVALID_HANDLE) + cogl_handle_unref (node->border_slices_material); + G_OBJECT_CLASS (st_theme_node_parent_class)->finalize (object); } diff --git a/src/st/st-theme-node.h b/src/st/st-theme-node.h index 9593bde6f..8f5da57e5 100644 --- a/src/st/st-theme-node.h +++ b/src/st/st-theme-node.h @@ -100,11 +100,6 @@ struct _StThemeNodePaintState { float alloc_width; float alloc_height; - CoglHandle background_texture; - CoglHandle background_material; - CoglHandle border_slices_texture; - CoglHandle border_slices_material; - CoglHandle background_shadow_material; CoglHandle box_shadow_material; CoglHandle prerendered_texture; CoglHandle prerendered_material; @@ -271,11 +266,14 @@ void st_theme_node_paint (StThemeNode *node, const ClutterActorBox *box, guint8 paint_opacity); +void st_theme_node_invalidate_background_image (StThemeNode *node); +void st_theme_node_invalidate_border_image (StThemeNode *node); + void st_theme_node_paint_state_init (StThemeNodePaintState *state); void st_theme_node_paint_state_free (StThemeNodePaintState *state); void st_theme_node_paint_state_copy (StThemeNodePaintState *state, StThemeNodePaintState *other); -void st_theme_node_paint_state_invalidate (StThemeNodePaintState *node); +void st_theme_node_paint_state_invalidate (StThemeNodePaintState *state); G_END_DECLS diff --git a/src/st/st-widget.c b/src/st/st-widget.c index 737b3e875..01c7b4c63 100644 --- a/src/st/st-widget.c +++ b/src/st/st-widget.c @@ -278,30 +278,40 @@ st_widget_texture_cache_changed (StTextureCache *cache, { StWidget *actor = ST_WIDGET (user_data); StThemeNode *node = actor->priv->theme_node; - StBorderImage *border_image; char *path; - gboolean changed; + gboolean changed = FALSE; if (node == NULL) return; path = g_filename_from_uri (uri, NULL, NULL); - changed = g_strcmp0 (st_theme_node_get_background_image (node), path) == 0; + if (g_strcmp0 (st_theme_node_get_background_image (node), path) == 0) + { + st_theme_node_invalidate_background_image (node); + changed = TRUE; + } - border_image = st_theme_node_get_border_image (node); - if (!changed && border_image) - changed = strcmp (st_border_image_get_filename (border_image), path) == 0; + if (g_strcmp0 (st_border_image_get_filename (st_theme_node_get_border_image (node)), path) == 0) + { + st_theme_node_invalidate_border_image (node); + changed = TRUE; + } + + if (changed) + { + /* If we prerender the background / border, we need to update + * the paint state. We should probably implement a method to + * the theme node to determine this, but for now, just wipe + * the entire paint state. + */ + st_theme_node_paint_state_invalidate (&actor->priv->paint_state); + + if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR (actor))) + clutter_actor_queue_redraw (CLUTTER_ACTOR (actor)); + } g_free (path); - - if (!changed) - return; - - st_theme_node_paint_state_invalidate (&actor->priv->paint_state); - - if (CLUTTER_ACTOR_IS_MAPPED (CLUTTER_ACTOR (actor))) - clutter_actor_queue_redraw (CLUTTER_ACTOR (actor)); } static void