Stop using GnomeBG for drawing the background

Load the image directly with GdkPixbuf and do the drawing with Cogl.
This avoids creating a screen-sized texture (which is likely to be outside
of HW limits), and avoids doing all blending and scaling in software.

For now, only simple images are supported. The next commit will restore
support for slideshows.
This commit is contained in:
Giovanni Campagna 2013-02-04 18:40:58 +01:00
parent 7332eb3db2
commit 94ac7ff02c
4 changed files with 464 additions and 197 deletions

View File

@ -75,7 +75,6 @@ MUTTER_PC_MODULES="
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.13.5
cogl-1.0 >= 1.13.3
gnome-desktop-3.0
"
GLIB_GSETTINGS

View File

@ -3,9 +3,6 @@
#ifndef META_BACKGROUND_ACTOR_PRIVATE_H
#define META_BACKGROUND_ACTOR_PRIVATE_H
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-bg.h>
#include <meta/screen.h>
#include <meta/meta-background-actor.h>
@ -13,12 +10,13 @@ void meta_background_actor_set_visible_region (MetaBackgroundActor *self,
cairo_region_t *visible_region);
GTask *meta_background_draw_async (MetaScreen *screen,
GnomeBG *bg,
const char *picture_uri,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
CoglHandle meta_background_draw_finish (MetaScreen *screen,
GAsyncResult *result,
char **picture_uri,
GError **error);

View File

@ -25,13 +25,8 @@
#include <config.h>
#include <cogl/cogl-texture-pixmap-x11.h>
#include <clutter/clutter.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-bg.h>
#include "cogl-utils.h"
#include "compositor-private.h"
#include <meta/errors.h>
@ -47,6 +42,19 @@
*/
typedef struct _MetaBackground MetaBackground;
typedef struct {
CoglTexture *texture;
float texture_width;
float texture_height;
/* ClutterColor, not CoglColor, because
the latter is opaque... */
ClutterColor colors[2];
GDesktopBackgroundStyle style;
GDesktopBackgroundShading shading;
char *picture_uri;
} MetaBackgroundState;
struct _MetaBackground
{
GSList *actors;
@ -54,11 +62,9 @@ struct _MetaBackground
MetaScreen *screen;
GCancellable *cancellable;
float texture_width;
float texture_height;
CoglTexture *old_texture;
CoglTexture *texture;
GnomeBG *bg;
MetaBackgroundState old_state;
MetaBackgroundState state;
GSettings *settings;
GTask *rendering_task;
};
@ -69,8 +75,8 @@ struct _MetaBackgroundActorPrivate
MetaBackground *background;
GSettings *settings;
CoglPipeline *solid_pipeline;
CoglPipeline *pipeline;
CoglMaterialWrapMode wrap_mode;
cairo_region_t *visible_region;
float dim_factor;
@ -95,20 +101,22 @@ static GParamSpec *obj_props[PROP_LAST];
G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR);
static void meta_background_update (GnomeBG *bg,
MetaBackground *background);
static void meta_background_update (MetaBackground *background,
const char *picture_uri);
static void meta_background_actor_screen_size_changed (MetaScreen *screen,
MetaBackgroundActor *actor);
static void meta_background_actor_constructed (GObject *object);
static void clear_old_texture (MetaBackground *background);
static void set_texture (MetaBackground *background,
CoglHandle texture);
static void clear_state (MetaBackgroundState *state);
static void set_texture (MetaBackground *background,
CoglHandle texture,
const char *picture_uri);
static void
meta_background_free (MetaBackground *background)
{
set_texture (background, COGL_INVALID_HANDLE);
clear_state (&background->old_state);
clear_state (&background->state);
g_cancellable_cancel (background->cancellable);
g_object_unref (background->cancellable);
@ -119,11 +127,15 @@ meta_background_free (MetaBackground *background)
}
static void
on_settings_changed (GSettings *settings,
const char *key,
GnomeBG *bg)
on_settings_changed (GSettings *settings,
const char *key,
MetaBackground *background)
{
gnome_bg_load_from_preferences (bg, settings);
char *picture_uri;
picture_uri = g_settings_get_string (settings, "picture-uri");
meta_background_update (background, picture_uri);
g_free (picture_uri);
}
static GSettings *
@ -149,26 +161,12 @@ meta_background_get (MetaScreen *screen,
g_object_set_qdata_full (G_OBJECT (settings), background_quark,
background, (GDestroyNotify) meta_background_free);
background->bg = gnome_bg_new ();
background->settings = settings;
background->screen = screen;
g_signal_connect (settings, "changed",
G_CALLBACK (on_settings_changed), background->bg);
on_settings_changed (settings, NULL, background->bg);
background->screen = screen;
background->texture_width = -1;
background->texture_height = -1;
g_signal_connect (background->bg, "transitioned",
G_CALLBACK (meta_background_update), background);
g_signal_connect (background->bg, "changed",
G_CALLBACK (meta_background_update), background);
/* GnomeBG has queued a changed event, but we need to start rendering now,
or it will be too late when we paint the first frame.
*/
g_object_set_data (G_OBJECT (background->bg), "ignore-pending-change", GINT_TO_POINTER (TRUE));
meta_background_update (background->bg, background);
G_CALLBACK (on_settings_changed), background);
on_settings_changed (settings, NULL, background);
}
return background;
@ -181,80 +179,79 @@ update_actor_pipeline (MetaBackgroundActor *self,
MetaBackgroundActorPrivate *priv = self->priv;
priv->is_crossfading = crossfade;
cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, priv->wrap_mode);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
static inline void
clear_state (MetaBackgroundState *state)
{
g_clear_pointer (&state->texture, cogl_handle_unref);
g_free (state->picture_uri);
state->picture_uri = NULL;
}
static void
crossfade_completed (ClutterTimeline *timeline,
MetaBackgroundActor *actor)
{
clear_old_texture (actor->priv->background);
clear_state (&actor->priv->background->old_state);
update_actor_pipeline (actor, FALSE);
}
static void
clear_old_texture (MetaBackground *background)
static inline gboolean
state_is_valid (MetaBackgroundState *state)
{
if (background->old_texture != COGL_INVALID_HANDLE)
{
cogl_handle_unref (background->old_texture);
background->old_texture = COGL_INVALID_HANDLE;
}
return state->texture != COGL_INVALID_HANDLE;
}
static inline void
get_color_from_settings (GSettings *settings,
const char *key,
ClutterColor *color)
{
char *str;
str = g_settings_get_string (settings, key);
clutter_color_from_string (color, str);
g_free (str);
}
static void
set_texture (MetaBackground *background,
CoglHandle texture)
CoglHandle texture,
const char *picture_uri)
{
GSList *l;
gboolean crossfade;
int width, height;
CoglMaterialWrapMode wrap_mode;
if (background->old_texture != COGL_INVALID_HANDLE)
{
cogl_handle_unref (background->old_texture);
background->old_texture = COGL_INVALID_HANDLE;
}
g_assert (texture != COGL_INVALID_HANDLE);
if (texture != COGL_INVALID_HANDLE)
{
background->old_texture = background->texture;
background->texture = cogl_handle_ref (texture);
}
else if (background->texture != COGL_INVALID_HANDLE)
{
cogl_handle_unref (background->texture);
background->texture = COGL_INVALID_HANDLE;
}
clear_state (&background->old_state);
if (texture != COGL_INVALID_HANDLE &&
background->old_texture != COGL_INVALID_HANDLE)
crossfade = TRUE;
else
crossfade = FALSE;
if (state_is_valid (&background->state))
background->old_state = background->state;
background->texture_width = cogl_texture_get_width (background->texture);
background->texture_height = cogl_texture_get_height (background->texture);
background->state.texture = cogl_handle_ref (texture);
get_color_from_settings (background->settings, "primary-color",
&background->state.colors[0]);
get_color_from_settings (background->settings, "secondary-color",
&background->state.colors[1]);
background->state.style = g_settings_get_enum (background->settings, "picture-options");
background->state.shading = g_settings_get_enum (background->settings, "color-shading-type");
background->state.texture_width = cogl_texture_get_width (background->state.texture);
background->state.texture_height = cogl_texture_get_height (background->state.texture);
background->state.picture_uri = g_strdup (picture_uri);
crossfade = state_is_valid (&background->old_state);
meta_screen_get_size (background->screen, &width, &height);
/* We turn off repeating when we have a full-screen pixmap to keep from
* getting artifacts from one side of the image sneaking into the other
* side of the image via bilinear filtering.
*/
if (width == background->texture_width && height == background->texture_height)
wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
else
wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
for (l = background->actors; l; l = l->next)
{
MetaBackgroundActor *actor = l->data;
actor->priv->wrap_mode = wrap_mode;
update_actor_pipeline (actor, crossfade);
if (crossfade)
@ -286,7 +283,7 @@ static inline void
meta_background_ensure_rendered (MetaBackground *background)
{
if (G_LIKELY (background->rendering_task == NULL ||
background->texture != COGL_INVALID_HANDLE))
background->state.texture != COGL_INVALID_HANDLE))
return;
g_task_wait_sync (background->rendering_task);
@ -306,6 +303,7 @@ meta_background_actor_dispose (GObject *object)
priv->background = NULL;
}
g_clear_pointer (&priv->solid_pipeline, cogl_object_unref);
g_clear_pointer (&priv->pipeline, cogl_object_unref);
g_clear_object (&priv->settings);
@ -350,40 +348,345 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
}
static void
paint_background (MetaBackgroundActor *self)
paint_gradient (MetaBackgroundState *state,
CoglPipeline *pipeline,
float color_factor,
float alpha_factor,
ClutterActorBox *monitor_box,
float actor_width,
float actor_height,
float screen_width,
float screen_height)
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *context = clutter_backend_get_cogl_context (backend);
CoglPrimitive *primitive;
int i;
/* Order is:
* 1 -- 0
* | |
* 3 -- 2
*
* (tri strip with counter-clockwise winding)
*/
CoglVertexP2C4 vertices[4] = {
{ monitor_box->x2 * (actor_width / screen_width), monitor_box->y1 * (actor_height / screen_height),
state->colors[0].red, state->colors[0].green, state->colors[0].blue, state->colors[0].alpha },
{ monitor_box->x1 * (actor_width / screen_width), monitor_box->y1 * (actor_height / screen_height),
state->colors[0].red, state->colors[0].green, state->colors[0].blue, state->colors[0].alpha },
{ monitor_box->x2 * (actor_width / screen_width), monitor_box->y2 * (actor_height / screen_height),
state->colors[0].red, state->colors[0].green, state->colors[0].blue, state->colors[0].alpha },
{ monitor_box->x1 * (actor_width / screen_width), monitor_box->y2 * (actor_height / screen_height),
state->colors[0].red, state->colors[0].green, state->colors[0].blue, state->colors[0].alpha },
};
/* These styles cover the entire screen */
if (state->style == G_DESKTOP_BACKGROUND_STYLE_WALLPAPER ||
state->style == G_DESKTOP_BACKGROUND_STYLE_STRETCHED ||
state->style == G_DESKTOP_BACKGROUND_STYLE_ZOOM)
return;
if (state->shading != G_DESKTOP_BACKGROUND_SHADING_SOLID)
{
if (state->shading == G_DESKTOP_BACKGROUND_SHADING_HORIZONTAL)
{
vertices[2].r = vertices[3].r = state->colors[1].red;
vertices[2].g = vertices[3].g = state->colors[1].green;
vertices[2].b = vertices[3].b = state->colors[1].blue;
vertices[2].a = vertices[3].a = state->colors[1].alpha;
}
else
{
vertices[0].r = vertices[2].r = state->colors[1].red;
vertices[0].g = vertices[2].g = state->colors[1].green;
vertices[0].b = vertices[2].b = state->colors[1].blue;
vertices[0].a = vertices[2].a = state->colors[1].alpha;
}
}
for (i = 0; i < 4; i++)
{
vertices[i].r *= color_factor;
vertices[i].g *= color_factor;
vertices[i].b *= color_factor;
vertices[i].a *= alpha_factor;
}
primitive = cogl_primitive_new_p2c4 (context,
COGL_VERTICES_MODE_TRIANGLE_STRIP,
4, vertices);
cogl_framebuffer_draw_primitive (cogl_get_draw_framebuffer (),
pipeline, primitive);
cogl_object_unref (primitive);
}
static void
paint_background_box (MetaBackgroundState *state,
CoglPipeline *pipeline,
float color_factor,
float alpha_factor,
ClutterActorBox *monitor_box,
float actor_width,
float actor_height,
float screen_width,
float screen_height)
{
CoglPrimitive *primitive;
CoglPipeline *pipeline_copy;
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *context = clutter_backend_get_cogl_context (backend);
int i;
float monitor_width, monitor_height;
float image_width, image_height;
/* Order is:
* 1 -- 0
* | |
* 3 -- 2
*
* (tri strip with counter-clockwise winding)
*/
CoglVertexP2T2 vertices[4];
if (state->style == G_DESKTOP_BACKGROUND_STYLE_NONE)
return;
vertices[0].s = 1.0;
vertices[0].t = 0.0;
vertices[1].s = 0.0;
vertices[1].t = 0.0;
vertices[2].s = 1.0;
vertices[2].t = 1.0;
vertices[3].s = 0.0;
vertices[3].t = 1.0;
clutter_actor_box_get_size (monitor_box, &monitor_width, &monitor_height);
switch (state->style) {
case G_DESKTOP_BACKGROUND_STYLE_STRETCHED:
/* Stretched:
The easy case: the image is stretched to cover the monitor fully.
*/
image_width = monitor_width;
image_height = monitor_height;
break;
case G_DESKTOP_BACKGROUND_STYLE_SPANNED:
/* Spanned:
The image is scaled to fit and drawn across all monitors.
If this is the case, monitor_box is actually the union of all monitors,
and we can fall through to scaled.
*/
case G_DESKTOP_BACKGROUND_STYLE_SCALED:
/* Scaled:
The image is scaled to fit (so one dimension is always covered)
*/
{
float scaling_factor = MIN (monitor_width / state->texture_width,
monitor_height / state->texture_height);
image_width = state->texture_width * scaling_factor;
image_height = state->texture_height * scaling_factor;
}
break;
case G_DESKTOP_BACKGROUND_STYLE_ZOOM:
/* Zoom:
The image is zoomed to fill the screen.
*/
{
float scaling_factor = MAX (monitor_width / state->texture_width,
monitor_height / state->texture_height);
image_width = state->texture_width * scaling_factor;
image_height = state->texture_height * scaling_factor;
}
break;
case G_DESKTOP_BACKGROUND_STYLE_CENTERED:
/* Centered:
The image is centered and not scaled.
*/
case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER:
/* Wallpaper:
The image is not scaled but tiled.
*/
image_width = state->texture_width;
image_height = state->texture_height;
break;
default:
g_assert_not_reached ();
}
pipeline_copy = cogl_pipeline_copy (pipeline);
cogl_pipeline_set_color4f (pipeline_copy,
color_factor,
color_factor,
color_factor,
alpha_factor);
if (state->style == G_DESKTOP_BACKGROUND_STYLE_WALLPAPER)
{
for (i = 0; i < 4; i++)
{
vertices[i].s *= (monitor_width / image_width);
vertices[i].t *= (monitor_height / image_height);
}
vertices[0].x = monitor_width;
vertices[0].y = 0;
vertices[1].x = 0;
vertices[1].y = 0;
vertices[2].x = monitor_width;
vertices[2].y = monitor_height;
vertices[3].x = 0;
vertices[3].y = monitor_height;
cogl_pipeline_set_layer_wrap_mode (pipeline_copy, 0, COGL_PIPELINE_WRAP_MODE_REPEAT);
}
else
{
/* Coordinates of the vertices, relative to the image */
float x0, x1, y0, y1;
x0 = (monitor_width - image_width) / 2;
y0 = (monitor_height - image_height) / 2;
x1 = x0 + image_width;
y1 = y0 + image_height;
vertices[0].x = x1;
vertices[0].y = y0;
vertices[1].x = x0;
vertices[1].y = y0;
vertices[2].x = x1;
vertices[2].y = y1;
vertices[3].x = x0;
vertices[3].y = y1;
}
for (i = 0; i < 4; i++)
{
vertices[i].x *= (actor_width / screen_width);
vertices[i].y *= (actor_height / screen_height);
}
primitive = cogl_primitive_new_p2t2 (context,
COGL_VERTICES_MODE_TRIANGLE_STRIP,
4, vertices);
cogl_framebuffer_draw_primitive (cogl_get_draw_framebuffer (),
pipeline_copy, primitive);
cogl_object_unref (primitive);
cogl_object_unref (pipeline_copy);
}
static void
paint_background_unclipped (MetaBackgroundActor *self,
MetaBackgroundState *state,
float color_factor,
float alpha_factor)
{
MetaBackgroundActorPrivate *priv;
int screen_width, screen_height;
float actor_width, actor_height;
ClutterActorBox monitor_box;
priv = self->priv;
clutter_actor_get_size (CLUTTER_ACTOR (self), &actor_width, &actor_height);
meta_screen_get_size (priv->screen, &screen_width, &screen_height);
if (state->style == G_DESKTOP_BACKGROUND_STYLE_SPANNED)
{
/* Prepare a box covering the screen */
monitor_box.x1 = 0;
monitor_box.y1 = 0;
monitor_box.x2 = screen_width;
monitor_box.y2 = screen_height;
paint_gradient (state, priv->solid_pipeline,
color_factor, alpha_factor,
&monitor_box,
actor_width, actor_height,
screen_width, screen_height);
paint_background_box (state, priv->pipeline,
color_factor, alpha_factor,
&monitor_box,
actor_width, actor_height,
screen_width, screen_height);
}
else
{
/* Iterate each monitor */
int i, n;
MetaRectangle monitor_rect;
n = meta_screen_get_n_monitors (priv->screen);
for (i = 0; i < n; i++)
{
meta_screen_get_monitor_geometry (priv->screen, i, &monitor_rect);
monitor_box.x1 = monitor_rect.x;
monitor_box.y1 = monitor_rect.y;
monitor_box.x2 = monitor_rect.x + monitor_rect.width;
monitor_box.y2 = monitor_rect.y + monitor_rect.height;
/* Sad truth: we need to paint twice to get the border of the image
right.
A similar effect could be obtained with GL_CLAMP_TO_BORDER, but
Cogl doesn't expose that.
*/
paint_gradient (state, priv->solid_pipeline,
color_factor, alpha_factor,
&monitor_box,
actor_width, actor_height,
screen_width, screen_height);
paint_background_box (state, priv->pipeline,
color_factor, alpha_factor,
&monitor_box,
actor_width, actor_height,
screen_width, screen_height);
}
}
}
static void
paint_background (MetaBackgroundActor *self,
MetaBackgroundState *state,
float color_factor,
float alpha_factor)
{
MetaBackgroundActorPrivate *priv = self->priv;
float width, height;
ClutterActorBox alloc;
clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &alloc);
clutter_actor_box_get_size (&alloc, &width, &height);
cogl_pipeline_set_layer_texture (priv->pipeline, 0, state->texture);
if (priv->visible_region)
{
int n_rectangles = cairo_region_num_rectangles (priv->visible_region);
int i;
cogl_path_new ();
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (priv->visible_region, i, &rect);
cogl_rectangle_with_texture_coords (rect.x, rect.y,
rect.x + rect.width, rect.y + rect.height,
rect.x / priv->background->texture_width,
rect.y / priv->background->texture_height,
(rect.x + rect.width) / priv->background->texture_width,
(rect.y + rect.height) / priv->background->texture_height);
cogl_path_rectangle (rect.x,
rect.y,
rect.x + rect.width,
rect.y + rect.height);
}
cogl_clip_push_from_path ();
paint_background_unclipped (self, state, color_factor, alpha_factor);
cogl_clip_pop ();
}
else
{
cogl_rectangle_with_texture_coords (0.0f, 0.0f,
width, height,
0.0f, 0.0f,
width / priv->background->texture_width,
height / priv->background->texture_height);
paint_background_unclipped (self, state, color_factor, alpha_factor);
}
}
@ -409,29 +712,16 @@ meta_background_actor_paint (ClutterActor *actor)
second_color_factor = (opacity / 256.f) * priv->dim_factor * (1 - crossfade_progress);
second_alpha_factor = (opacity / 256.f) * (1 - crossfade_progress);
cogl_set_source (priv->pipeline);
if (priv->is_crossfading)
{
cogl_pipeline_set_color4f (priv->pipeline,
second_color_factor,
second_color_factor,
second_color_factor,
second_alpha_factor);
cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->background->old_texture);
paint_background (self);
paint_background (self, &priv->background->old_state,
second_color_factor,
second_alpha_factor);
}
cogl_pipeline_set_color4f (priv->pipeline,
first_color_factor,
first_color_factor,
first_color_factor,
first_alpha_factor);
cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->background->texture);
paint_background (self);
paint_background (self, &priv->background->state,
first_color_factor,
first_alpha_factor);
}
static gboolean
@ -644,12 +934,13 @@ meta_background_actor_init (MetaBackgroundActor *self)
MetaBackgroundActorPrivate);
priv->dim_factor = 1.0;
priv->crossfade_progress = 0.0;
priv->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
}
static void
meta_background_actor_constructed (GObject *object)
{
ClutterBackend *backend = clutter_get_default_backend ();
CoglContext *context = clutter_backend_get_cogl_context (backend);
MetaBackgroundActor *self;
MetaBackgroundActorPrivate *priv;
@ -661,10 +952,12 @@ meta_background_actor_constructed (GObject *object)
priv->background = meta_background_get (priv->screen, priv->settings);
priv->background->actors = g_slist_prepend (priv->background->actors, self);
priv->pipeline = meta_create_texture_material (priv->background->texture);
if (priv->background->texture != COGL_INVALID_HANDLE)
update_actor_pipeline (self, FALSE);
priv->solid_pipeline = cogl_pipeline_new (context);
priv->pipeline = meta_create_texture_material (COGL_INVALID_HANDLE);
cogl_pipeline_set_layer_filters (priv->pipeline, 0,
COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR,
COGL_MATERIAL_FILTER_LINEAR_MIPMAP_LINEAR);
update_actor_pipeline (self, FALSE);
}
/**
@ -697,9 +990,10 @@ on_background_drawn (GObject *object,
MetaBackground *background;
CoglHandle texture;
GError *error;
char *picture_uri;
error = NULL;
texture = meta_background_draw_finish (META_SCREEN (object), result, &error);
texture = meta_background_draw_finish (META_SCREEN (object), result, &picture_uri, &error);
/* Don't even access user_data if cancelled, it might be already
freed */
@ -716,8 +1010,9 @@ on_background_drawn (GObject *object,
if (texture != COGL_INVALID_HANDLE)
{
set_texture (background, texture);
set_texture (background, texture, picture_uri);
cogl_handle_unref (texture);
g_free (picture_uri);
return;
}
else
@ -730,17 +1025,20 @@ on_background_drawn (GObject *object,
/*
* meta_background_update:
* @bg: the #GnomeBG that triggered the update
* @background: a #MetaBackground
* @picture_uri: the new image URI
*
* Forces a redraw of the background. The redraw happens asynchronously in
* a thread, and the actual on screen change is therefore delayed until
* the redraw is finished.
*/
void
meta_background_update (GnomeBG *bg,
MetaBackground *background)
meta_background_update (MetaBackground *background,
const char *picture_uri)
{
if (g_strcmp0 (background->state.picture_uri, picture_uri) == 0)
return;
if (background->cancellable)
{
g_cancellable_cancel (background->cancellable);
@ -750,8 +1048,9 @@ meta_background_update (GnomeBG *bg,
g_clear_object (&background->rendering_task);
background->cancellable = g_cancellable_new ();
background->rendering_task = meta_background_draw_async (background->screen,
bg,
picture_uri,
background->cancellable,
on_background_drawn, background);
}
@ -799,21 +1098,6 @@ static void
meta_background_actor_screen_size_changed (MetaScreen *screen,
MetaBackgroundActor *actor)
{
MetaBackgroundActorPrivate *priv;
MetaBackground *background;
int width, height;
priv = actor->priv;
background = priv->background;
meta_screen_get_size (screen, &width, &height);
if (width == background->texture_width && height == background->texture_height)
priv->wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
else
priv->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
update_actor_pipeline (actor, actor->priv->is_crossfading);
clutter_actor_queue_relayout (CLUTTER_ACTOR (actor));
}

View File

@ -29,78 +29,60 @@
#include "meta-background-actor-private.h"
#include <core/screen-private.h>
typedef struct {
GnomeBG *bg;
GdkPixbuf *pixbuf;
GdkRectangle *monitors;
int num_monitors;
} TaskData;
static void
task_data_free (gpointer task_data)
{
TaskData *td = task_data;
g_object_unref (td->bg);
g_object_unref (td->pixbuf);
g_free (td->monitors);
g_slice_free (TaskData, td);
}
static void
meta_background_draw_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
TaskData *td = task_data;
GFile *file;
GInputStream *stream;
GdkPixbuf *pixbuf;
GError *error;
gnome_bg_draw_areas (td->bg,
td->pixbuf,
TRUE,
td->monitors,
td->num_monitors);
/* TODO: handle slideshows and other complications */
g_task_return_pointer (task, g_object_ref (td->pixbuf), g_object_unref);
file = g_file_new_for_uri (task_data);
error = NULL;
stream = G_INPUT_STREAM (g_file_read (file, cancellable, &error));
if (stream == NULL)
{
g_object_unref (file);
g_task_return_error (task, error);
return;
}
pixbuf = gdk_pixbuf_new_from_stream (stream, cancellable, &error);
if (pixbuf == NULL)
{
g_object_unref (file);
g_object_unref (stream);
g_task_return_error (task, error);
}
g_task_return_pointer (task, pixbuf, g_object_unref);
g_object_unref (file);
g_object_unref (stream);
}
GTask *
meta_background_draw_async (MetaScreen *screen,
GnomeBG *bg,
const char *picture_uri,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
TaskData *td;
int i;
g_return_val_if_fail (META_IS_SCREEN (screen), NULL);
g_return_val_if_fail (GNOME_IS_BG (bg), NULL);
task = g_task_new (screen, cancellable, callback, user_data);
g_task_set_source_tag (task, meta_background_draw_async);
g_task_set_return_on_cancel (task, TRUE);
g_task_set_check_cancellable (task, TRUE);
td = g_slice_new (TaskData);
td->bg = g_object_ref (bg);
td->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
FALSE, /* has alpha */
8, /* bits per sample */
screen->rect.width,
screen->rect.height);
td->num_monitors = meta_screen_get_n_monitors (screen);
td->monitors = g_new (GdkRectangle, td->num_monitors);
for (i = 0; i < td->num_monitors; i++)
meta_screen_get_monitor_geometry (screen, i, (MetaRectangle*)(td->monitors + i));
g_task_set_task_data (task, td, task_data_free);
g_task_set_task_data (task, g_strdup (picture_uri), g_free);
g_task_run_in_thread (task, meta_background_draw_thread);
return task;
@ -109,6 +91,7 @@ meta_background_draw_async (MetaScreen *screen,
CoglHandle
meta_background_draw_finish (MetaScreen *screen,
GAsyncResult *result,
char **picture_uri,
GError **error)
{
GdkPixbuf *pixbuf;
@ -118,6 +101,9 @@ meta_background_draw_finish (MetaScreen *screen,
if (pixbuf == NULL)
return COGL_INVALID_HANDLE;
if (picture_uri != NULL)
*picture_uri = g_strdup (g_task_get_task_data (G_TASK (result)));
handle = cogl_texture_new_from_data (gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
COGL_TEXTURE_NO_ATLAS | COGL_TEXTURE_NO_SLICING,