Rewrite background code
The old requirement that multiple MetaBackgroundActor objects be layered on top of each to produce blended backgrounds resulted in extremely inefficient drawing since the entire framebuffer had to be read and written multiple times. * Replace the MetaBackground ClutterContent with a plain GObject that serves to hold the background parameters and prerender textures to be used to draw the background. It handles colors, gradients, and blended images, but does not handle vignetting * Add vignetting to MetaBackgroundActor directly. * Add MetaBackgroundImage and MetaBackgroundImageCache to allow multiple MetaBackground objects to share the same images By removing the usage of ClutterContent, the following optimizations were easy to add: Blending is turned off when the actor is fully opaque Nearest-neighbour filtering is used when drawing 1:1 The GLSL vignette code is slightly improved to use a vertex shader snippet for computing the texture coordinate => position in actor mapping. https://bugzilla.gnome.org/show_bug.cgi?id=735637
This commit is contained in:
parent
17dc5c57dd
commit
a4a688ed83
@ -100,8 +100,10 @@ libmutter_la_SOURCES = \
|
||||
compositor/compositor.c \
|
||||
compositor/compositor-private.h \
|
||||
compositor/meta-background.c \
|
||||
compositor/meta-background-private.h \
|
||||
compositor/meta-background-actor.c \
|
||||
compositor/meta-background-actor-private.h \
|
||||
compositor/meta-background-image.c \
|
||||
compositor/meta-background-group.c \
|
||||
compositor/meta-cullable.c \
|
||||
compositor/meta-cullable.h \
|
||||
@ -133,6 +135,7 @@ libmutter_la_SOURCES = \
|
||||
meta/compositor.h \
|
||||
meta/meta-background.h \
|
||||
meta/meta-background-actor.h \
|
||||
meta/meta-background-image.h \
|
||||
meta/meta-background-group.h \
|
||||
meta/meta-plugin.h \
|
||||
meta/meta-shadow-factory.h \
|
||||
@ -282,9 +285,10 @@ libmutterinclude_headers = \
|
||||
meta/keybindings.h \
|
||||
meta/main.h \
|
||||
meta/meta-backend.h \
|
||||
meta/meta-background-actor.h \
|
||||
meta/meta-background-group.h \
|
||||
meta/meta-background.h \
|
||||
meta/meta-background-actor.h \
|
||||
meta/meta-background-image.h \
|
||||
meta/meta-background-group.h \
|
||||
meta/meta-cursor-tracker.h \
|
||||
meta/meta-idle-monitor.h \
|
||||
meta/meta-plugin.h \
|
||||
|
@ -64,3 +64,78 @@ meta_create_texture_pipeline (CoglTexture *src_texture)
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
static gboolean is_pot(int x)
|
||||
{
|
||||
return x > 0 && (x & (x - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_create_texture:
|
||||
* @width: width of the texture to create
|
||||
* @height: height of the texture to create
|
||||
* @components; components to store in the texture (color or alpha)
|
||||
* @flags: flags that affect the allocation behavior
|
||||
*
|
||||
* Creates a texture of the given size with the specified components
|
||||
* for use as a frame buffer object.
|
||||
*
|
||||
* If non-power-of-two textures are not supported on the system, then
|
||||
* the texture will be created as a texture rectangle; in this case,
|
||||
* hardware repeating isn't possible, and texture coordinates are also
|
||||
* different, but Cogl hides these issues from the application, except from
|
||||
* GLSL shaders. Since GLSL is never (or at least almost never)
|
||||
* present on such a system, this is not typically an issue.
|
||||
*
|
||||
* If %META_TEXTURE_ALLOW_SLICING is present in @flags, and the texture
|
||||
* is larger than the texture size limits of the system, then the texture
|
||||
* will be created as a sliced texture. This also will cause problems
|
||||
* with using the texture with GLSL, and is more likely to be an issue
|
||||
* since all GL implementations have texture size limits, and they can
|
||||
* be as small as 2048x2048 on reasonably current systems.
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_create_texture (int width,
|
||||
int height,
|
||||
CoglTextureComponents components,
|
||||
MetaTextureFlags flags)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
||||
CoglTexture *texture;
|
||||
|
||||
gboolean should_use_rectangle = FALSE;
|
||||
|
||||
if (!(is_pot (width) && is_pot (height)) &&
|
||||
!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT))
|
||||
{
|
||||
if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
|
||||
should_use_rectangle = TRUE;
|
||||
else
|
||||
g_error ("Cannot create texture. Support for GL_ARB_texture_non_power_of_two or "
|
||||
"ARB_texture_rectangle is required");
|
||||
}
|
||||
|
||||
if (should_use_rectangle)
|
||||
texture = COGL_TEXTURE (cogl_texture_rectangle_new_with_size (ctx, width, height));
|
||||
else
|
||||
texture = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, width, height));
|
||||
cogl_texture_set_components (texture, components);
|
||||
|
||||
if ((flags & META_TEXTURE_ALLOW_SLICING) != 0)
|
||||
{
|
||||
/* To find out if we need to slice the texture, we have to go ahead and force storage
|
||||
* to be allocated
|
||||
*/
|
||||
CoglError *catch_error = NULL;
|
||||
if (!cogl_texture_allocate (texture, &catch_error))
|
||||
{
|
||||
cogl_error_free (catch_error);
|
||||
cogl_object_unref (texture);
|
||||
texture = COGL_TEXTURE (cogl_texture_2d_sliced_new_with_size (ctx, width, height, COGL_TEXTURE_MAX_WASTE));
|
||||
cogl_texture_set_components (texture, components);
|
||||
}
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
@ -25,4 +25,14 @@
|
||||
|
||||
CoglPipeline * meta_create_texture_pipeline (CoglTexture *texture);
|
||||
|
||||
typedef enum {
|
||||
META_TEXTURE_FLAGS_NONE = 0,
|
||||
META_TEXTURE_ALLOW_SLICING = 1 << 1
|
||||
} MetaTextureFlags;
|
||||
|
||||
CoglTexture *meta_create_texture (int width,
|
||||
int height,
|
||||
CoglTextureComponents components,
|
||||
MetaTextureFlags flags);
|
||||
|
||||
#endif /* __META_COGL_UTILS_H__ */
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright 2009 Sander Dijkhuis
|
||||
* Copyright 2010 Red Hat, Inc.
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@ -26,23 +26,119 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
/*
|
||||
* The overall model drawing model of this widget is that we have one
|
||||
* texture, or two interpolated textures, possibly with alpha or
|
||||
* margins that let the underlying background show through, blended
|
||||
* over a solid color or a gradient. The result of that combination
|
||||
* can then be affected by a "vignette" that darkens the background
|
||||
* away from a central point (or as a no-GLSL fallback, simply darkens
|
||||
* the background) and by overall opacity.
|
||||
*
|
||||
* As of GNOME 3.14, GNOME is only using a fraction of this when the
|
||||
* user sets the background through the control center - what can be
|
||||
* set is:
|
||||
*
|
||||
* A single image without a border
|
||||
* An animation of images without a border that blend together,
|
||||
* with the blend changing every 4-5 minutes
|
||||
* A solid color with a repeated noise texture blended over it
|
||||
*
|
||||
* This all is pretty easy to do in a fragment shader, except when:
|
||||
*
|
||||
* A) We don't have GLSL - in this case, the operation of
|
||||
* interpolating the two textures and blending the result over the
|
||||
* background can't be expressed with Cogl's fixed-function layer
|
||||
* combining (which is confined to what GL's texture environment
|
||||
* combining can do) So we can only handle the above directly if
|
||||
* there are no margins or alpha.
|
||||
*
|
||||
* B) The image textures are sliced. Texture size limits on older
|
||||
* hardware (pre-965 intel hardware, r300, etc.) is often 2048,
|
||||
* and it would be common to use a texture larger than this for a
|
||||
* background and expect it to be scaled down. Cogl can compensate
|
||||
* for this by breaking the texture up into multiple textures, but
|
||||
* can't multitexture with sliced textures. So we can only handle
|
||||
* the above if there's a single texture.
|
||||
*
|
||||
* However, even when we *can* represent everything in a single pass,
|
||||
* it's not necessarily efficient. If we want to draw a 1024x768
|
||||
* background, it's pretty inefficient to bilinearly texture from
|
||||
* two 2560x1440 images and mix that. So the drawing model we take
|
||||
* here is that MetaBackground generates a single texture (which
|
||||
* might be a 1x1 texture for a solid color, or a 1x2 texture for a
|
||||
* gradient, or a repeated texture for wallpaper, or a pre-rendered
|
||||
* texture the size of the screen), and we draw with that, possibly
|
||||
* adding the vignette and opacity.
|
||||
*/
|
||||
|
||||
#include <cogl/cogl-texture-pixmap-x11.h>
|
||||
#include <config.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "cogl-utils.h"
|
||||
#include "compositor-private.h"
|
||||
#include "clutter-utils.h"
|
||||
#include <meta/errors.h>
|
||||
#include <meta/meta-background.h>
|
||||
#include "meta-background-actor-private.h"
|
||||
#include "meta-background-private.h"
|
||||
#include "meta-cullable.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_META_SCREEN = 1,
|
||||
PROP_MONITOR,
|
||||
PROP_BACKGROUND,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
CHANGED_BACKGROUND = 1 << 0,
|
||||
CHANGED_EFFECTS = 1 << 2,
|
||||
CHANGED_VIGNETTE_PARAMETERS = 1 << 3,
|
||||
CHANGED_ALL = 0xFFFF
|
||||
} ChangedFlags;
|
||||
|
||||
#define VERTEX_SHADER_DECLARATIONS \
|
||||
"uniform vec2 scale;\n" \
|
||||
"uniform vec2 offset;\n" \
|
||||
"varying vec2 position;\n" \
|
||||
|
||||
#define VERTEX_SHADER_CODE \
|
||||
"position = cogl_tex_coord0_in.xy * scale + offset;\n" \
|
||||
|
||||
#define FRAGMENT_SHADER_DECLARATIONS \
|
||||
"uniform float vignette_sharpness;\n" \
|
||||
"varying vec2 position;\n" \
|
||||
|
||||
#define FRAGMENT_SHADER_CODE \
|
||||
"float t = 2.0 * length(position);\n" \
|
||||
"t = min(t, 1.0);\n" \
|
||||
"float pixel_brightness = 1 - t * vignette_sharpness;\n" \
|
||||
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
|
||||
|
||||
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;
|
||||
|
||||
typedef enum {
|
||||
PIPELINE_VIGNETTE = (1 << 0),
|
||||
PIPELINE_BLEND = (1 << 1),
|
||||
} PipelineFlags;
|
||||
|
||||
struct _MetaBackgroundActorPrivate
|
||||
{
|
||||
MetaScreen *screen;
|
||||
int monitor;
|
||||
|
||||
MetaBackground *background;
|
||||
|
||||
gboolean vignette;
|
||||
float brightness;
|
||||
float vignette_sharpness;
|
||||
|
||||
ChangedFlags changed;
|
||||
CoglPipeline *pipeline;
|
||||
PipelineFlags pipeline_flags;
|
||||
cairo_rectangle_int_t texture_area;
|
||||
gboolean force_bilinear;
|
||||
|
||||
cairo_region_t *clip_region;
|
||||
};
|
||||
|
||||
@ -66,27 +162,45 @@ static void
|
||||
meta_background_actor_dispose (GObject *object)
|
||||
{
|
||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
|
||||
set_clip_region (self, NULL);
|
||||
meta_background_actor_set_background (self, NULL);
|
||||
if (priv->pipeline)
|
||||
{
|
||||
cogl_object_unref (priv->pipeline);
|
||||
priv->pipeline = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
get_preferred_size (MetaBackgroundActor *self,
|
||||
gfloat *width,
|
||||
gfloat *height)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = META_BACKGROUND_ACTOR (self)->priv;
|
||||
MetaRectangle monitor_geometry;
|
||||
|
||||
meta_screen_get_monitor_geometry (priv->screen, priv->monitor, &monitor_geometry);
|
||||
|
||||
if (width != NULL)
|
||||
*width = monitor_geometry.width;
|
||||
|
||||
if (height != NULL)
|
||||
*height = monitor_geometry.height;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_get_preferred_width (ClutterActor *actor,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
ClutterContent *content;
|
||||
gfloat width;
|
||||
|
||||
content = clutter_actor_get_content (actor);
|
||||
|
||||
if (content)
|
||||
clutter_content_get_preferred_size (content, &width, NULL);
|
||||
else
|
||||
width = 0;
|
||||
get_preferred_size (META_BACKGROUND_ACTOR (actor), &width, NULL);
|
||||
|
||||
if (min_width_p)
|
||||
*min_width_p = width;
|
||||
@ -101,15 +215,9 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
|
||||
gfloat *natural_height_p)
|
||||
|
||||
{
|
||||
ClutterContent *content;
|
||||
gfloat height;
|
||||
|
||||
content = clutter_actor_get_content (actor);
|
||||
|
||||
if (content)
|
||||
clutter_content_get_preferred_size (content, NULL, &height);
|
||||
else
|
||||
height = 0;
|
||||
get_preferred_size (META_BACKGROUND_ACTOR (actor), NULL, &height);
|
||||
|
||||
if (min_height_p)
|
||||
*min_height_p = height;
|
||||
@ -117,18 +225,320 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
|
||||
*natural_height_p = height;
|
||||
}
|
||||
|
||||
static CoglPipeline *
|
||||
make_pipeline (PipelineFlags pipeline_flags)
|
||||
{
|
||||
static CoglPipeline *templates[4];
|
||||
CoglPipeline **templatep;
|
||||
|
||||
templatep = &templates[pipeline_flags];
|
||||
if (*templatep == NULL)
|
||||
{
|
||||
/* Cogl automatically caches pipelines with no eviction policy,
|
||||
* so we need to prevent identical pipelines from getting cached
|
||||
* separately, by reusing the same shader snippets.
|
||||
*/
|
||||
*templatep = COGL_PIPELINE (meta_create_texture_pipeline (NULL));
|
||||
|
||||
if ((pipeline_flags & PIPELINE_VIGNETTE) != 0)
|
||||
{
|
||||
static CoglSnippet *vertex_snippet;
|
||||
static CoglSnippet *fragment_snippet;
|
||||
|
||||
if (!vertex_snippet)
|
||||
vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
|
||||
VERTEX_SHADER_DECLARATIONS, VERTEX_SHADER_CODE);
|
||||
|
||||
cogl_pipeline_add_snippet (*templatep, vertex_snippet);
|
||||
|
||||
if (!fragment_snippet)
|
||||
fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
|
||||
FRAGMENT_SHADER_DECLARATIONS, FRAGMENT_SHADER_CODE);
|
||||
|
||||
cogl_pipeline_add_snippet (*templatep, fragment_snippet);
|
||||
}
|
||||
|
||||
if ((pipeline_flags & PIPELINE_BLEND) == 0)
|
||||
cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL);
|
||||
}
|
||||
|
||||
return cogl_pipeline_copy (*templatep);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_pipeline (MetaBackgroundActor *self,
|
||||
cairo_rectangle_int_t *actor_pixel_rect)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
PipelineFlags pipeline_flags = 0;
|
||||
guint8 opacity;
|
||||
float color_component;
|
||||
CoglPipelineFilter filter;
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
|
||||
if (opacity < 255)
|
||||
pipeline_flags |= PIPELINE_BLEND;
|
||||
if (priv->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
|
||||
pipeline_flags |= PIPELINE_VIGNETTE;
|
||||
|
||||
if (priv->pipeline &&
|
||||
pipeline_flags != priv->pipeline_flags)
|
||||
{
|
||||
cogl_object_unref (priv->pipeline);
|
||||
priv->pipeline = NULL;
|
||||
}
|
||||
|
||||
if (priv->pipeline == NULL)
|
||||
{
|
||||
priv->pipeline_flags = pipeline_flags;
|
||||
priv->pipeline = make_pipeline (pipeline_flags);
|
||||
priv->changed = CHANGED_ALL;
|
||||
}
|
||||
|
||||
if ((priv->changed & CHANGED_BACKGROUND) != 0)
|
||||
{
|
||||
CoglPipelineWrapMode wrap_mode;
|
||||
CoglTexture *texture = meta_background_get_texture (priv->background,
|
||||
priv->monitor,
|
||||
&priv->texture_area,
|
||||
&wrap_mode);
|
||||
priv->force_bilinear = texture &&
|
||||
(priv->texture_area.width != (int)cogl_texture_get_width (texture) ||
|
||||
priv->texture_area.height != (int)cogl_texture_get_height (texture));
|
||||
|
||||
cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture);
|
||||
cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, wrap_mode);
|
||||
}
|
||||
|
||||
if ((priv->changed & CHANGED_VIGNETTE_PARAMETERS) != 0)
|
||||
{
|
||||
cogl_pipeline_set_uniform_1f (priv->pipeline,
|
||||
cogl_pipeline_get_uniform_location (priv->pipeline,
|
||||
"vignette_sharpness"),
|
||||
priv->vignette_sharpness);
|
||||
}
|
||||
|
||||
if (priv->vignette)
|
||||
color_component = priv->brightness * opacity / 255.;
|
||||
else
|
||||
color_component = opacity / 255.;
|
||||
|
||||
cogl_pipeline_set_color4f (priv->pipeline,
|
||||
color_component,
|
||||
color_component,
|
||||
color_component,
|
||||
opacity / 255.);
|
||||
|
||||
if (!priv->force_bilinear &&
|
||||
meta_actor_painting_untransformed (actor_pixel_rect->width, actor_pixel_rect->height, NULL, NULL))
|
||||
filter = COGL_PIPELINE_FILTER_NEAREST;
|
||||
else
|
||||
filter = COGL_PIPELINE_FILTER_LINEAR;
|
||||
|
||||
cogl_pipeline_set_layer_filters (priv->pipeline, 0, filter, filter);
|
||||
}
|
||||
|
||||
static void
|
||||
set_glsl_parameters (MetaBackgroundActor *self,
|
||||
cairo_rectangle_int_t *actor_pixel_rect)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
float scale[2];
|
||||
float offset[2];
|
||||
|
||||
/* Compute a scale and offset for transforming texture coordinates to the
|
||||
* coordinate system from [-0.5 to 0.5] across the area of the actor
|
||||
*/
|
||||
scale[0] = priv->texture_area.width / (float)actor_pixel_rect->width;
|
||||
scale[1] = priv->texture_area.height / (float)actor_pixel_rect->height;
|
||||
offset[0] = priv->texture_area.x / (float)actor_pixel_rect->width - 0.5;
|
||||
offset[1] = priv->texture_area.y / (float)actor_pixel_rect->height - 0.5;
|
||||
|
||||
cogl_pipeline_set_uniform_float (priv->pipeline,
|
||||
cogl_pipeline_get_uniform_location (priv->pipeline,
|
||||
"scale"),
|
||||
2, 1, scale);
|
||||
|
||||
cogl_pipeline_set_uniform_float (priv->pipeline,
|
||||
cogl_pipeline_get_uniform_location (priv->pipeline,
|
||||
"offset"),
|
||||
2, 1, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
paint_clipped_rectangle (CoglFramebuffer *fb,
|
||||
CoglPipeline *pipeline,
|
||||
cairo_rectangle_int_t *rect,
|
||||
cairo_rectangle_int_t *texture_area)
|
||||
{
|
||||
float x1, y1, x2, y2;
|
||||
float tx1, ty1, tx2, ty2;
|
||||
|
||||
x1 = rect->x;
|
||||
y1 = rect->y;
|
||||
x2 = rect->x + rect->width;
|
||||
y2 = rect->y + rect->height;
|
||||
|
||||
tx1 = (x1 - texture_area->x) / texture_area->width;
|
||||
ty1 = (y1 - texture_area->y) / texture_area->height;
|
||||
tx2 = (x2 - texture_area->x) / texture_area->width;
|
||||
ty2 = (y2 - texture_area->y) / texture_area->height;
|
||||
|
||||
cogl_framebuffer_draw_textured_rectangle (fb, pipeline,
|
||||
x1, y1, x2, y2,
|
||||
tx1, ty1, tx2, ty2);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
ClutterActorBox actor_box;
|
||||
cairo_rectangle_int_t actor_pixel_rect;
|
||||
CoglFramebuffer *fb;
|
||||
int i;
|
||||
|
||||
if ((priv->clip_region && cairo_region_is_empty (priv->clip_region)))
|
||||
return;
|
||||
|
||||
clutter_actor_get_content_box (actor, &actor_box);
|
||||
actor_pixel_rect.x = actor_box.x1;
|
||||
actor_pixel_rect.y = actor_box.y1;
|
||||
actor_pixel_rect.width = actor_box.x2 - actor_box.x1;
|
||||
actor_pixel_rect.height = actor_box.y2 - actor_box.y1;
|
||||
|
||||
setup_pipeline (self, &actor_pixel_rect);
|
||||
set_glsl_parameters (self, &actor_pixel_rect);
|
||||
|
||||
/* Limit to how many separate rectangles we'll draw; beyond this just
|
||||
* fall back and draw the whole thing */
|
||||
#define MAX_RECTS 64
|
||||
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
|
||||
/* Now figure out what to actually paint.
|
||||
*/
|
||||
if (priv->clip_region != NULL)
|
||||
{
|
||||
int n_rects = cairo_region_num_rectangles (priv->clip_region);
|
||||
if (n_rects <= MAX_RECTS)
|
||||
{
|
||||
for (i = 0; i < n_rects; i++)
|
||||
{
|
||||
cairo_rectangle_int_t rect;
|
||||
cairo_region_get_rectangle (priv->clip_region, i, &rect);
|
||||
|
||||
if (!gdk_rectangle_intersect (&actor_pixel_rect, &rect, &rect))
|
||||
continue;
|
||||
|
||||
paint_clipped_rectangle (fb, priv->pipeline, &rect, &priv->texture_area);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
paint_clipped_rectangle (fb, priv->pipeline, &actor_pixel_rect, &priv->texture_area);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_META_SCREEN:
|
||||
priv->screen = g_value_get_object (value);
|
||||
break;
|
||||
case PROP_MONITOR:
|
||||
priv->monitor = g_value_get_int (value);
|
||||
break;
|
||||
case PROP_BACKGROUND:
|
||||
meta_background_actor_set_background (self, g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = META_BACKGROUND_ACTOR (object)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_META_SCREEN:
|
||||
g_value_set_object (value, priv->screen);
|
||||
break;
|
||||
case PROP_MONITOR:
|
||||
g_value_set_int (value, priv->monitor);
|
||||
break;
|
||||
case PROP_BACKGROUND:
|
||||
g_value_set_object (value, priv->background);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_actor_class_init (MetaBackgroundActorClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
GParamSpec *param_spec;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (MetaBackgroundActorPrivate));
|
||||
|
||||
object_class->dispose = meta_background_actor_dispose;
|
||||
object_class->set_property = meta_background_actor_set_property;
|
||||
object_class->get_property = meta_background_actor_get_property;
|
||||
|
||||
actor_class->get_preferred_width = meta_background_actor_get_preferred_width;
|
||||
actor_class->get_preferred_height = meta_background_actor_get_preferred_height;
|
||||
actor_class->paint = meta_background_actor_paint;
|
||||
|
||||
param_spec = g_param_spec_object ("meta-screen",
|
||||
"MetaScreen",
|
||||
"MetaScreen",
|
||||
META_TYPE_SCREEN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_META_SCREEN,
|
||||
param_spec);
|
||||
|
||||
param_spec = g_param_spec_int ("monitor",
|
||||
"monitor",
|
||||
"monitor",
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_MONITOR,
|
||||
param_spec);
|
||||
|
||||
param_spec = g_param_spec_object ("background",
|
||||
"Background",
|
||||
"MetaBackground object holding background parameters",
|
||||
META_TYPE_BACKGROUND,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_BACKGROUND,
|
||||
param_spec);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -141,19 +551,22 @@ meta_background_actor_init (MetaBackgroundActor *self)
|
||||
|
||||
/**
|
||||
* meta_background_actor_new:
|
||||
* @monitor: Index of the monitor for which to draw the background
|
||||
*
|
||||
* Creates a new actor to draw the background for the given monitor.
|
||||
* This actor should be associated with a #MetaBackground using
|
||||
* clutter_actor_set_content()
|
||||
*
|
||||
* Return value: the newly created background actor
|
||||
*/
|
||||
ClutterActor *
|
||||
meta_background_actor_new (void)
|
||||
meta_background_actor_new (MetaScreen *screen,
|
||||
int monitor)
|
||||
{
|
||||
MetaBackgroundActor *self;
|
||||
|
||||
self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL);
|
||||
self = g_object_new (META_TYPE_BACKGROUND_ACTOR,
|
||||
"meta-screen", screen,
|
||||
"monitor", monitor,
|
||||
NULL);
|
||||
|
||||
return CLUTTER_ACTOR (self);
|
||||
}
|
||||
@ -195,3 +608,95 @@ meta_background_actor_get_clip_region (MetaBackgroundActor *self)
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
return priv->clip_region;
|
||||
}
|
||||
|
||||
static void
|
||||
invalidate_pipeline (MetaBackgroundActor *self,
|
||||
ChangedFlags changed)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv = self->priv;
|
||||
|
||||
priv->changed |= changed;
|
||||
}
|
||||
|
||||
static void
|
||||
on_background_changed (MetaBackground *background,
|
||||
MetaBackgroundActor *self)
|
||||
{
|
||||
invalidate_pipeline (self, CHANGED_BACKGROUND);
|
||||
}
|
||||
|
||||
void
|
||||
meta_background_actor_set_background (MetaBackgroundActor *self,
|
||||
MetaBackground *background)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
|
||||
g_return_if_fail (background == NULL || META_IS_BACKGROUND (background));
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
if (background == priv->background)
|
||||
return;
|
||||
|
||||
if (priv->background)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (priv->background,
|
||||
(gpointer)on_background_changed,
|
||||
self);
|
||||
g_object_unref (priv->background);
|
||||
priv->background = NULL;
|
||||
}
|
||||
|
||||
if (background)
|
||||
{
|
||||
priv->background = g_object_ref (background);
|
||||
g_signal_connect (priv->background, "changed",
|
||||
G_CALLBACK (on_background_changed), self);
|
||||
}
|
||||
|
||||
invalidate_pipeline (self, CHANGED_BACKGROUND);
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||
}
|
||||
|
||||
void
|
||||
meta_background_actor_set_vignette (MetaBackgroundActor *self,
|
||||
double brightness,
|
||||
double sharpness)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
|
||||
g_return_if_fail (brightness >= 0. && brightness <= 1.);
|
||||
g_return_if_fail (sharpness >= 0.);
|
||||
|
||||
priv = self->priv;
|
||||
|
||||
if (!priv->vignette)
|
||||
invalidate_pipeline (self, CHANGED_EFFECTS);
|
||||
|
||||
priv->vignette = TRUE;
|
||||
priv->brightness = brightness;
|
||||
priv->vignette_sharpness = sharpness;
|
||||
invalidate_pipeline (self, CHANGED_VIGNETTE_PARAMETERS);
|
||||
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||
}
|
||||
|
||||
void
|
||||
meta_background_actor_unset_vignette (MetaBackgroundActor *self)
|
||||
{
|
||||
MetaBackgroundActorPrivate *priv;
|
||||
priv = self->priv;
|
||||
|
||||
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
|
||||
|
||||
if (!priv->vignette)
|
||||
return;
|
||||
|
||||
priv->vignette = FALSE;
|
||||
|
||||
invalidate_pipeline (self, CHANGED_EFFECTS);
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||
}
|
||||
|
||||
|
344
src/compositor/meta-background-image.c
Normal file
344
src/compositor/meta-background-image.c
Normal file
@ -0,0 +1,344 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:meta-background-image
|
||||
* @title: MetaBackgroundImage
|
||||
* @short_description: objects holding images loaded from files, used for backgrounds
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <clutter/clutter.h>
|
||||
#include <meta/meta-background-image.h>
|
||||
#include "cogl-utils.h"
|
||||
|
||||
enum
|
||||
{
|
||||
LOADED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
struct _MetaBackgroundImageCache
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GHashTable *images;
|
||||
};
|
||||
|
||||
struct _MetaBackgroundImageCacheClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _MetaBackgroundImage
|
||||
{
|
||||
GObject parent_instance;
|
||||
char *filename;
|
||||
MetaBackgroundImageCache *cache;
|
||||
gboolean in_cache;
|
||||
gboolean loaded;
|
||||
CoglTexture *texture;
|
||||
};
|
||||
|
||||
struct _MetaBackgroundImageClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaBackgroundImageCache, meta_background_image_cache, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
meta_background_image_cache_init (MetaBackgroundImageCache *cache)
|
||||
{
|
||||
cache->images = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_cache_finalize (GObject *object)
|
||||
{
|
||||
MetaBackgroundImageCache *cache = META_BACKGROUND_IMAGE_CACHE (object);
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, cache->images);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
MetaBackgroundImage *image = value;
|
||||
image->in_cache = FALSE;
|
||||
}
|
||||
|
||||
g_hash_table_destroy (cache->images);
|
||||
|
||||
G_OBJECT_CLASS (meta_background_image_cache_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_cache_class_init (MetaBackgroundImageCacheClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_background_image_cache_finalize;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_cache_get_default:
|
||||
*
|
||||
* Return value: (transfer none): the global singleton background cache
|
||||
*/
|
||||
MetaBackgroundImageCache *
|
||||
meta_background_image_cache_get_default (void)
|
||||
{
|
||||
static MetaBackgroundImageCache *cache;
|
||||
|
||||
if (cache == NULL)
|
||||
cache = g_object_new (META_TYPE_BACKGROUND_IMAGE_CACHE, NULL);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static void
|
||||
load_file (GTask *task,
|
||||
MetaBackgroundImage *image,
|
||||
gpointer task_data,
|
||||
GCancellable *cancellable)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (image->filename,
|
||||
&error);
|
||||
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_pointer (task, pixbuf, (GDestroyNotify) g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
file_loaded (GObject *source_object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (source_object);
|
||||
GError *error = NULL;
|
||||
GTask *task;
|
||||
CoglTexture *texture;
|
||||
GdkPixbuf *pixbuf;
|
||||
int width, height, row_stride;
|
||||
guchar *pixels;
|
||||
gboolean has_alpha;
|
||||
|
||||
task = G_TASK (result);
|
||||
pixbuf = g_task_propagate_pointer (task, &error);
|
||||
|
||||
if (pixbuf == NULL)
|
||||
{
|
||||
g_warning ("Failed to load background '%s': %s",
|
||||
image->filename, error->message);
|
||||
g_clear_error (&error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
width = gdk_pixbuf_get_width (pixbuf);
|
||||
height = gdk_pixbuf_get_height (pixbuf);
|
||||
row_stride = gdk_pixbuf_get_rowstride (pixbuf);
|
||||
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
||||
has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
|
||||
|
||||
texture = meta_create_texture (width, height,
|
||||
has_alpha ? COGL_TEXTURE_COMPONENTS_RGBA : COGL_TEXTURE_COMPONENTS_RGB,
|
||||
META_TEXTURE_ALLOW_SLICING);
|
||||
|
||||
if (!cogl_texture_set_data (texture,
|
||||
has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
|
||||
row_stride,
|
||||
pixels, 0,
|
||||
NULL))
|
||||
{
|
||||
g_warning ("Failed to create texture for background");
|
||||
cogl_object_unref (texture);
|
||||
}
|
||||
|
||||
image->texture = texture;
|
||||
|
||||
out:
|
||||
image->loaded = TRUE;
|
||||
g_signal_emit (image, signals[LOADED], 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_cache_load:
|
||||
* @cache: a #MetaBackgroundImageCache
|
||||
* @filename: filename to load
|
||||
*
|
||||
* Loads an image to use as a background, or returns a reference to an
|
||||
* image that is already in the process of loading or loaded. In either
|
||||
* case, what is returned is a #MetaBackgroundImage which can be derefenced
|
||||
* to get a #CoglTexture. If meta_background_image_is_loaded() returns %TRUE,
|
||||
* the background is loaded, otherwise the MetaBackgroundImage::loaded
|
||||
* signal will be emitted exactly once. The 'loaded' state means that the
|
||||
* loading process finished, whether it succeeded or failed.
|
||||
*
|
||||
* Return value: (transfer full): a #MetaBackgroundImage to dereference to get the loaded texture
|
||||
*/
|
||||
MetaBackgroundImage *
|
||||
meta_background_image_cache_load (MetaBackgroundImageCache *cache,
|
||||
const char *filename)
|
||||
{
|
||||
MetaBackgroundImage *image;
|
||||
GTask *task;
|
||||
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
|
||||
image = g_hash_table_lookup (cache->images, filename);
|
||||
if (image != NULL)
|
||||
return g_object_ref (image);
|
||||
|
||||
image = g_object_new (META_TYPE_BACKGROUND_IMAGE, NULL);
|
||||
image->cache = cache;
|
||||
image->in_cache = TRUE;
|
||||
image->filename = g_strdup (filename);
|
||||
g_hash_table_insert (cache->images, image->filename, image);
|
||||
|
||||
task = g_task_new (image, NULL, file_loaded, NULL);
|
||||
|
||||
g_task_run_in_thread (task, (GTaskThreadFunc) load_file);
|
||||
g_object_unref (task);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_cache_purge:
|
||||
* @cache: a #MetaBackgroundImageCache
|
||||
* @filename: filename to remove from the cache
|
||||
*
|
||||
* Remove an entry from the cache; this would be used if monitoring
|
||||
* showed that the file changed.
|
||||
*/
|
||||
void
|
||||
meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
|
||||
const char *filename)
|
||||
{
|
||||
MetaBackgroundImage *image;
|
||||
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE_CACHE (cache), NULL);
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
|
||||
image = g_hash_table_lookup (cache->images, filename);
|
||||
if (image == NULL)
|
||||
return;
|
||||
|
||||
g_hash_table_remove (cache->images, image->filename);
|
||||
image->in_cache = FALSE;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE (MetaBackgroundImage, meta_background_image, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
meta_background_image_init (MetaBackgroundImage *image)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_finalize (GObject *object)
|
||||
{
|
||||
MetaBackgroundImage *image = META_BACKGROUND_IMAGE (object);
|
||||
|
||||
if (image->in_cache)
|
||||
g_hash_table_remove (image->cache->images, image->filename);
|
||||
|
||||
if (image->texture)
|
||||
cogl_object_unref (image->texture);
|
||||
if (image->filename)
|
||||
g_free (image->filename);
|
||||
|
||||
G_OBJECT_CLASS (meta_background_image_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_background_image_class_init (MetaBackgroundImageClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_background_image_finalize;
|
||||
|
||||
signals[LOADED] =
|
||||
g_signal_new ("loaded",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_is_loaded:
|
||||
* @image: a #MetaBackgroundImage
|
||||
*
|
||||
* Return value: %TRUE if loading has already completed, %FALSE otherwise
|
||||
*/
|
||||
gboolean
|
||||
meta_background_image_is_loaded (MetaBackgroundImage *image)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE);
|
||||
|
||||
return image->loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_get_success:
|
||||
* @image: a #MetaBackgroundImage
|
||||
*
|
||||
* This function is a convenience function for checking for success,
|
||||
* without having to call meta_background_image_get_texture() and
|
||||
* handle the return of a Cogl type.
|
||||
*
|
||||
* Return value: %TRUE if loading completed successfully, otherwise %FALSE
|
||||
*/
|
||||
gboolean
|
||||
meta_background_image_get_success (MetaBackgroundImage *image)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), FALSE);
|
||||
|
||||
return image->texture != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* meta_background_image_get_texture:
|
||||
* @image: a #MetaBackgroundImage
|
||||
*
|
||||
* Return value: (transfer none): a #CoglTexture if loading succeeded; if
|
||||
* loading failed or has not yet finished, %NULL.
|
||||
*/
|
||||
CoglTexture *
|
||||
meta_background_image_get_texture (MetaBackgroundImage *image)
|
||||
{
|
||||
g_return_val_if_fail (META_IS_BACKGROUND_IMAGE (image), NULL);
|
||||
|
||||
return image->texture;
|
||||
}
|
15
src/compositor/meta-background-private.h
Normal file
15
src/compositor/meta-background-private.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#ifndef META_BACKGROUND_PRIVATE_H
|
||||
#define META_BACKGROUND_PRIVATE_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "meta-background-private.h"
|
||||
|
||||
CoglTexture *meta_background_get_texture (MetaBackground *self,
|
||||
int monitor_index,
|
||||
cairo_rectangle_int_t *texture_area,
|
||||
CoglPipelineWrapMode *wrap_mode);
|
||||
|
||||
#endif /* META_BACKGROUND_PRIVATE_H */
|
File diff suppressed because it is too large
Load Diff
@ -303,15 +303,16 @@ on_monitors_changed (MetaScreen *screen,
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
MetaRectangle rect;
|
||||
ClutterActor *background;
|
||||
ClutterActor *background_actor;
|
||||
MetaBackground *background;
|
||||
ClutterColor color;
|
||||
|
||||
meta_screen_get_monitor_geometry (screen, i, &rect);
|
||||
|
||||
background = meta_background_actor_new ();
|
||||
background_actor = meta_background_actor_new (screen, i);
|
||||
|
||||
clutter_actor_set_position (background, rect.x, rect.y);
|
||||
clutter_actor_set_size (background, rect.width, rect.height);
|
||||
clutter_actor_set_position (background_actor, rect.x, rect.y);
|
||||
clutter_actor_set_size (background_actor, rect.width, rect.height);
|
||||
|
||||
/* Don't use rand() here, mesa calls srand() internally when
|
||||
parsing the driconf XML, but it's nice if the colors are
|
||||
@ -322,9 +323,13 @@ on_monitors_changed (MetaScreen *screen,
|
||||
g_rand_int_range (rand, 0, 255),
|
||||
g_rand_int_range (rand, 0, 255),
|
||||
255);
|
||||
clutter_actor_set_background_color (background, &color);
|
||||
|
||||
clutter_actor_add_child (self->priv->background_group, background);
|
||||
background = meta_background_new (screen);
|
||||
meta_background_set_color (background, &color);
|
||||
meta_background_actor_set_background (META_BACKGROUND_ACTOR (background_actor), background);
|
||||
g_object_unref (background);
|
||||
|
||||
clutter_actor_add_child (self->priv->background_group, background_actor);
|
||||
}
|
||||
|
||||
g_rand_free (rand);
|
||||
|
@ -22,10 +22,8 @@
|
||||
#define META_BACKGROUND_ACTOR_H
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
#include <meta/gradient.h>
|
||||
#include <meta/screen.h>
|
||||
#include <meta/meta-background.h>
|
||||
|
||||
#include <gsettings-desktop-schemas/gdesktop-enums.h>
|
||||
|
||||
@ -63,6 +61,15 @@ struct _MetaBackgroundActor
|
||||
|
||||
GType meta_background_actor_get_type (void);
|
||||
|
||||
ClutterActor *meta_background_actor_new (void);
|
||||
ClutterActor *meta_background_actor_new (MetaScreen *screen,
|
||||
int monitor);
|
||||
|
||||
void meta_background_actor_set_background (MetaBackgroundActor *self,
|
||||
MetaBackground *background);
|
||||
|
||||
void meta_background_actor_set_vignette (MetaBackgroundActor *self,
|
||||
double brightness,
|
||||
double sharpness);
|
||||
void meta_background_actor_unset_vignette (MetaBackgroundActor *self);
|
||||
|
||||
#endif /* META_BACKGROUND_ACTOR_H */
|
||||
|
76
src/meta/meta-background-image.h
Normal file
76
src/meta/meta-background-image.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* MetaBackgroundImageCache:
|
||||
*
|
||||
* Simple cache for background textures loaded from files
|
||||
*
|
||||
* Copyright 2014 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __META_BACKGROUND_IMAGE_H__
|
||||
#define __META_BACKGROUND_IMAGE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
#define META_TYPE_BACKGROUND_IMAGE (meta_background_image_get_type ())
|
||||
#define META_BACKGROUND_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND_IMAGE, MetaBackgroundImage))
|
||||
#define META_BACKGROUND_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND_IMAGE, MetaBackgroundImageClass))
|
||||
#define META_IS_BACKGROUND_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND_IMAGE))
|
||||
#define META_IS_BACKGROUND_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND_IMAGE))
|
||||
#define META_BACKGROUND_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND_IMAGE, MetaBackgroundImageClass))
|
||||
|
||||
/**
|
||||
* MetaBackgroundImage:
|
||||
*
|
||||
* #MetaBackgroundImage is an object that represents a loaded or loading background image.
|
||||
*/
|
||||
typedef struct _MetaBackgroundImage MetaBackgroundImage;
|
||||
typedef struct _MetaBackgroundImageClass MetaBackgroundImageClass;
|
||||
|
||||
GType meta_background_image_get_type (void);
|
||||
|
||||
gboolean meta_background_image_is_loaded (MetaBackgroundImage *image);
|
||||
gboolean meta_background_image_get_success (MetaBackgroundImage *image);
|
||||
CoglTexture *meta_background_image_get_texture (MetaBackgroundImage *image);
|
||||
|
||||
#define META_TYPE_BACKGROUND_IMAGE_CACHE (meta_background_image_cache_get_type ())
|
||||
#define META_BACKGROUND_IMAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND_IMAGE_CACHE, MetaBackgroundImageCache))
|
||||
#define META_BACKGROUND_IMAGE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND_IMAGE_CACHE, MetaBackgroundImageCacheClass))
|
||||
#define META_IS_BACKGROUND_IMAGE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND_IMAGE_CACHE))
|
||||
#define META_IS_BACKGROUND_IMAGE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND_IMAGE_CACHE))
|
||||
#define META_BACKGROUND_IMAGE_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND_IMAGE_CACHE, MetaBackgroundImageCacheClass))
|
||||
|
||||
/**
|
||||
* MetaBackgroundImageCache:
|
||||
*
|
||||
* #MetaBackgroundImageCache caches loading of textures for backgrounds; there's actually
|
||||
* nothing background specific about it, other than it is tuned to work well for
|
||||
* large images as typically are used for backgrounds.
|
||||
*/
|
||||
typedef struct _MetaBackgroundImageCache MetaBackgroundImageCache;
|
||||
typedef struct _MetaBackgroundImageCacheClass MetaBackgroundImageCacheClass;
|
||||
|
||||
MetaBackgroundImageCache *meta_background_image_cache_get_default (void);
|
||||
|
||||
GType meta_background_image_cache_get_type (void);
|
||||
|
||||
MetaBackgroundImage *meta_background_image_cache_load (MetaBackgroundImageCache *cache,
|
||||
const char *filename);
|
||||
void meta_background_image_cache_purge (MetaBackgroundImageCache *cache,
|
||||
const char *filename);
|
||||
|
||||
#endif /* __META_BACKGROUND_IMAGE_H__ */
|
@ -1,8 +1,8 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* meta-background.h: CoglTexture for paintnig the system background
|
||||
* meta-background-actor.h: for painting the root window background
|
||||
*
|
||||
* Copyright 2013 Red Hat, Inc.
|
||||
* Copyright 2010 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
@ -21,20 +21,16 @@
|
||||
#ifndef META_BACKGROUND_H
|
||||
#define META_BACKGROUND_H
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <meta/gradient.h>
|
||||
#include <meta/screen.h>
|
||||
|
||||
#include <gsettings-desktop-schemas/gdesktop-enums.h>
|
||||
#include <meta/screen.h>
|
||||
|
||||
/**
|
||||
* MetaBackground:
|
||||
*
|
||||
* This class handles loading a background from file, screenshot, or
|
||||
* color scheme. The resulting object can be associated with one or
|
||||
* more #MetaBackgroundActor objects to handle loading the background.
|
||||
* This class handles tracking and painting the root window background.
|
||||
* By integrating with #MetaWindowGroup we can avoid painting parts of
|
||||
* the background that are obscured by other windows.
|
||||
*/
|
||||
|
||||
#define META_TYPE_BACKGROUND (meta_background_get_type ())
|
||||
@ -48,20 +44,6 @@ typedef struct _MetaBackground MetaBackground;
|
||||
typedef struct _MetaBackgroundClass MetaBackgroundClass;
|
||||
typedef struct _MetaBackgroundPrivate MetaBackgroundPrivate;
|
||||
|
||||
/**
|
||||
* MetaBackgroundEffects:
|
||||
* @META_BACKGROUND_EFFECTS_NONE: No effect
|
||||
* @META_BACKGROUND_EFFECTS_VIGNETTE: Vignette
|
||||
*
|
||||
* Which effects to enable on the background
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
META_BACKGROUND_EFFECTS_NONE = 0,
|
||||
META_BACKGROUND_EFFECTS_VIGNETTE = 1 << 1,
|
||||
} MetaBackgroundEffects;
|
||||
|
||||
struct _MetaBackgroundClass
|
||||
{
|
||||
/*< private >*/
|
||||
@ -70,7 +52,6 @@ struct _MetaBackgroundClass
|
||||
|
||||
struct _MetaBackground
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent;
|
||||
|
||||
MetaBackgroundPrivate *priv;
|
||||
@ -78,33 +59,21 @@ struct _MetaBackground
|
||||
|
||||
GType meta_background_get_type (void);
|
||||
|
||||
MetaBackground *meta_background_new (MetaScreen *screen,
|
||||
int monitor,
|
||||
MetaBackgroundEffects effects);
|
||||
MetaBackground *meta_background_copy (MetaBackground *self,
|
||||
int monitor,
|
||||
MetaBackgroundEffects effects);
|
||||
MetaBackground *meta_background_new (MetaScreen *screen);
|
||||
|
||||
void meta_background_load_gradient (MetaBackground *self,
|
||||
GDesktopBackgroundShading shading_direction,
|
||||
ClutterColor *color,
|
||||
ClutterColor *second_color);
|
||||
void meta_background_load_color (MetaBackground *self,
|
||||
ClutterColor *color);
|
||||
void meta_background_load_file_async (MetaBackground *self,
|
||||
const char *filename,
|
||||
GDesktopBackgroundStyle style,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean meta_background_load_file_finish (MetaBackground *self,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
const char *meta_background_get_filename (MetaBackground *self);
|
||||
GDesktopBackgroundStyle meta_background_get_style (MetaBackground *self);
|
||||
GDesktopBackgroundShading meta_background_get_shading (MetaBackground *self);
|
||||
const ClutterColor *meta_background_get_color (MetaBackground *self);
|
||||
const ClutterColor *meta_background_get_second_color (MetaBackground *self);
|
||||
void meta_background_set_color (MetaBackground *self,
|
||||
ClutterColor *color);
|
||||
void meta_background_set_gradient (MetaBackground *self,
|
||||
GDesktopBackgroundShading shading_direction,
|
||||
ClutterColor *color,
|
||||
ClutterColor *second_color);
|
||||
void meta_background_set_filename (MetaBackground *self,
|
||||
const char *filename,
|
||||
GDesktopBackgroundStyle style);
|
||||
void meta_background_set_blend (MetaBackground *self,
|
||||
const char *filename1,
|
||||
const char *filename2,
|
||||
double blend_factor,
|
||||
GDesktopBackgroundStyle style);
|
||||
|
||||
#endif /* META_BACKGROUND_H */
|
||||
|
Loading…
Reference in New Issue
Block a user