Compare commits
	
		
			3 Commits
		
	
	
		
			gtk3-ci
			...
			wip/backgr
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 3c2284e69a | ||
|   | c632dcdd98 | ||
|   | 786f358888 | 
| @@ -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			\ | ||||
|   | ||||
| @@ -51,6 +51,12 @@ round_to_fixed (float x) | ||||
|   return roundf (x * 256); | ||||
| } | ||||
|  | ||||
| /* Help macros to scale from OpenGL <-1,1> coordinates system to | ||||
|  * window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c | ||||
|  */ | ||||
| #define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) | ||||
| #define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) | ||||
|  | ||||
| /* This helper function checks if (according to our fixed point precision) | ||||
|  * the vertices @verts form a box of width @widthf and height @heightf | ||||
|  * located at integral coordinates. These coordinates are returned | ||||
| @@ -118,3 +124,67 @@ meta_actor_is_untransformed (ClutterActor *actor, | ||||
|   return meta_actor_vertices_are_untransformed (verts, widthf, heightf, x_origin, y_origin); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * meta_actor_painting_untransformed: | ||||
|  * @paint_width: the width of the painted area | ||||
|  * @paint_height: the height of the painted area | ||||
|  * @x_origin: if the transform is only an integer translation | ||||
|  *  then the X coordinate of the location of the origin under the transformation | ||||
|  *  from drawing space to screen pixel space is returned here. | ||||
|  * @y_origin: if the transform is only an integer translation | ||||
|  *  then the X coordinate of the location of the origin under the transformation | ||||
|  *  from drawing space to screen pixel space is returned here. | ||||
|  * | ||||
|  * Determines if the current painting transform is an integer translation. | ||||
|  * This can differ from the result of meta_actor_is_untransformed() when | ||||
|  * painting an actor if we're inside a inside a clone paint. @paint_width | ||||
|  * and @paint_height are used to determine the vertices of the rectangle | ||||
|  * we check to see if the painted area is "close enough" to the integer | ||||
|  * transform. | ||||
|  */ | ||||
| gboolean | ||||
| meta_actor_painting_untransformed (int              paint_width, | ||||
|                                    int              paint_height, | ||||
|                                    int             *x_origin, | ||||
|                                    int             *y_origin) | ||||
| { | ||||
|   CoglMatrix modelview, projection, modelview_projection; | ||||
|   ClutterVertex vertices[4]; | ||||
|   float viewport[4]; | ||||
|   int i; | ||||
|  | ||||
|   cogl_get_modelview_matrix (&modelview); | ||||
|   cogl_get_projection_matrix (&projection); | ||||
|  | ||||
|   cogl_matrix_multiply (&modelview_projection, | ||||
|                         &projection, | ||||
|                         &modelview); | ||||
|  | ||||
|   vertices[0].x = 0; | ||||
|   vertices[0].y = 0; | ||||
|   vertices[0].z = 0; | ||||
|   vertices[1].x = paint_width; | ||||
|   vertices[1].y = 0; | ||||
|   vertices[1].z = 0; | ||||
|   vertices[2].x = 0; | ||||
|   vertices[2].y = paint_height; | ||||
|   vertices[2].z = 0; | ||||
|   vertices[3].x = paint_width; | ||||
|   vertices[3].y = paint_height; | ||||
|   vertices[3].z = 0; | ||||
|  | ||||
|   cogl_get_viewport (viewport); | ||||
|  | ||||
|   for (i = 0; i < 4; i++) | ||||
|     { | ||||
|       float w = 1; | ||||
|       cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w); | ||||
|       vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w, | ||||
|                                       viewport[2], viewport[0]); | ||||
|       vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w, | ||||
|                                       viewport[3], viewport[1]); | ||||
|     } | ||||
|  | ||||
|   return meta_actor_vertices_are_untransformed (vertices, paint_width, paint_height, x_origin, y_origin); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -31,4 +31,9 @@ gboolean meta_actor_is_untransformed (ClutterActor *actor, | ||||
|                                       int          *x_origin, | ||||
|                                       int          *y_origin); | ||||
|  | ||||
| gboolean meta_actor_painting_untransformed (int         paint_width, | ||||
|                                             int         paint_height, | ||||
|                                             int        *x_origin, | ||||
|                                             int        *y_origin); | ||||
|  | ||||
| #endif /* __META_CLUTTER_UTILS_H__ */ | ||||
|   | ||||
| @@ -64,3 +64,37 @@ meta_create_texture_pipeline (CoglTexture *src_texture) | ||||
|  | ||||
|   return pipeline; | ||||
| } | ||||
|  | ||||
| static gboolean is_pot(int x) | ||||
| { | ||||
|   return x > 0 && (x & (x - 1)) == 0; | ||||
| } | ||||
|  | ||||
| CoglTexture * | ||||
| meta_create_large_texture (int                   width, | ||||
|                            int                   height, | ||||
|                            CoglTextureComponents components) | ||||
| { | ||||
|   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; | ||||
|     } | ||||
|  | ||||
|   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); | ||||
|  | ||||
|   return texture; | ||||
| } | ||||
|   | ||||
| @@ -25,4 +25,8 @@ | ||||
|  | ||||
| CoglPipeline * meta_create_texture_pipeline (CoglTexture *texture); | ||||
|  | ||||
| CoglTexture *meta_create_large_texture (int                   width, | ||||
|                                         int                   height, | ||||
|                                         CoglTextureComponents components); | ||||
|  | ||||
| #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,306 @@ 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 *snippet; | ||||
|  | ||||
|           if (!snippet) | ||||
|             snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX, | ||||
|                                         VERTEX_SHADER_DECLARATIONS, VERTEX_SHADER_CODE); | ||||
|  | ||||
|           cogl_pipeline_add_snippet (*templatep, snippet); | ||||
|         } | ||||
|  | ||||
|       if ((pipeline_flags & PIPELINE_VIGNETTE) != 0) | ||||
|         { | ||||
|           static CoglSnippet *snippet; | ||||
|  | ||||
|           if (!snippet) | ||||
|             snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, | ||||
|                                         FRAGMENT_SHADER_DECLARATIONS, FRAGMENT_SHADER_CODE); | ||||
|  | ||||
|           cogl_pipeline_add_snippet (*templatep, 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 | ||||
| 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; | ||||
|   cairo_region_t *paintable_region = NULL; | ||||
|   int n_texture_subareas; | ||||
|   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; | ||||
|  | ||||
|   /* Now figure out what to actually paint. | ||||
|    */ | ||||
|   paintable_region = cairo_region_create_rectangle (&actor_pixel_rect); | ||||
|   if (priv->clip_region != NULL) | ||||
|     cairo_region_intersect (paintable_region, priv->clip_region); | ||||
|  | ||||
|   if (cairo_region_is_empty (paintable_region)) | ||||
|     goto out; | ||||
|  | ||||
|   setup_pipeline (self, &actor_pixel_rect); | ||||
|   set_glsl_parameters (self, &actor_pixel_rect); | ||||
|  | ||||
|   /* Finally, split the paintable region up into distinct areas | ||||
|    * and paint each area one by one | ||||
|    */ | ||||
|   n_texture_subareas = cairo_region_num_rectangles (paintable_region); | ||||
|   for (i = 0; i < n_texture_subareas; i++) | ||||
|     { | ||||
|       cairo_rectangle_int_t rect; | ||||
|       float tx1, tx2, ty1, ty2; | ||||
|  | ||||
|       cairo_region_get_rectangle (paintable_region, i, &rect); | ||||
|  | ||||
|       tx1 = (rect.x - actor_pixel_rect.x - priv->texture_area.x) / (float)priv->texture_area.width; | ||||
|       ty1 = (rect.y - actor_pixel_rect.y - priv->texture_area.y) / (float)priv->texture_area.height; | ||||
|       tx2 = (rect.x + rect.width - actor_pixel_rect.x - priv->texture_area.x) / (float)priv->texture_area.width; | ||||
|       ty2 = (rect.y + rect.height - actor_pixel_rect.y - priv->texture_area.y) / (float)priv->texture_area.height; | ||||
|  | ||||
|       cogl_framebuffer_draw_textured_rectangle (cogl_get_draw_framebuffer (), | ||||
|                                                 priv->pipeline, | ||||
|                                                 rect.x, rect.y, | ||||
|                                                 rect.x + rect.width, rect.y + rect.height, | ||||
|                                                 tx1, ty1, tx2, ty2); | ||||
|     } | ||||
|  | ||||
|  out: | ||||
|   cairo_region_destroy (paintable_region); | ||||
| } | ||||
|  | ||||
| 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 +537,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 +594,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_add_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_remove_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)); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										342
									
								
								src/compositor/meta-background-image.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								src/compositor/meta-background-image.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,342 @@ | ||||
| /* -*- 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_large_texture (width, height, | ||||
|                                        has_alpha ? COGL_TEXTURE_COMPONENTS_RGBA : COGL_TEXTURE_COMPONENTS_RGB); | ||||
|   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_success() 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
											
										
									
								
							| @@ -343,7 +343,7 @@ meta_shaped_texture_paint (ClutterActor *actor) | ||||
|  | ||||
|   filter = COGL_PIPELINE_FILTER_LINEAR; | ||||
|  | ||||
|   if (!clutter_actor_is_in_clone_paint (actor) && meta_actor_is_untransformed (actor, NULL, NULL)) | ||||
|   if (meta_actor_painting_untransformed (tex_width, tex_height, NULL, NULL)) | ||||
|     filter = COGL_PIPELINE_FILTER_NEAREST; | ||||
|  | ||||
|   ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); | ||||
|   | ||||
| @@ -31,64 +31,6 @@ static void cullable_iface_init (MetaCullableInterface *iface); | ||||
| G_DEFINE_TYPE_WITH_CODE (MetaWindowGroup, meta_window_group, CLUTTER_TYPE_ACTOR, | ||||
|                          G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init)); | ||||
|  | ||||
| /* Help macros to scale from OpenGL <-1,1> coordinates system to | ||||
|  * window coordinates ranging [0,window-size]. Borrowed from clutter-utils.c | ||||
|  */ | ||||
| #define MTX_GL_SCALE_X(x,w,v1,v2) ((((((x) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) | ||||
| #define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - (((((y) / (w)) + 1.0f) / 2.0f) * (v1)) + (v2)) | ||||
|  | ||||
| /* Check if we're painting the MetaWindowGroup "untransformed". This can | ||||
|  * differ from the result of actor_is_untransformed(window_group) if we're | ||||
|  * inside a clone paint. The integer translation, if any, is returned. | ||||
|  */ | ||||
| static gboolean | ||||
| painting_untransformed (MetaWindowGroup *window_group, | ||||
|                         int             *x_origin, | ||||
|                         int             *y_origin) | ||||
| { | ||||
|   CoglMatrix modelview, projection, modelview_projection; | ||||
|   ClutterVertex vertices[4]; | ||||
|   int width, height; | ||||
|   float viewport[4]; | ||||
|   int i; | ||||
|  | ||||
|   cogl_get_modelview_matrix (&modelview); | ||||
|   cogl_get_projection_matrix (&projection); | ||||
|  | ||||
|   cogl_matrix_multiply (&modelview_projection, | ||||
|                         &projection, | ||||
|                         &modelview); | ||||
|  | ||||
|   meta_screen_get_size (window_group->screen, &width, &height); | ||||
|  | ||||
|   vertices[0].x = 0; | ||||
|   vertices[0].y = 0; | ||||
|   vertices[0].z = 0; | ||||
|   vertices[1].x = width; | ||||
|   vertices[1].y = 0; | ||||
|   vertices[1].z = 0; | ||||
|   vertices[2].x = 0; | ||||
|   vertices[2].y = height; | ||||
|   vertices[2].z = 0; | ||||
|   vertices[3].x = width; | ||||
|   vertices[3].y = height; | ||||
|   vertices[3].z = 0; | ||||
|  | ||||
|   cogl_get_viewport (viewport); | ||||
|  | ||||
|   for (i = 0; i < 4; i++) | ||||
|     { | ||||
|       float w = 1; | ||||
|       cogl_matrix_transform_point (&modelview_projection, &vertices[i].x, &vertices[i].y, &vertices[i].z, &w); | ||||
|       vertices[i].x = MTX_GL_SCALE_X (vertices[i].x, w, | ||||
|                                       viewport[2], viewport[0]); | ||||
|       vertices[i].y = MTX_GL_SCALE_Y (vertices[i].y, w, | ||||
|                                       viewport[3], viewport[1]); | ||||
|     } | ||||
|  | ||||
|   return meta_actor_vertices_are_untransformed (vertices, width, height, x_origin, y_origin); | ||||
| } | ||||
|  | ||||
| static void | ||||
| meta_window_group_cull_out (MetaCullable   *cullable, | ||||
|                             cairo_region_t *unobscured_region, | ||||
| @@ -119,10 +61,13 @@ meta_window_group_paint (ClutterActor *actor) | ||||
|   int paint_x_offset, paint_y_offset; | ||||
|   int paint_x_origin, paint_y_origin; | ||||
|   int actor_x_origin, actor_y_origin; | ||||
|   int screen_width, screen_height; | ||||
|  | ||||
|   MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); | ||||
|   ClutterActor *stage = clutter_actor_get_stage (actor); | ||||
|  | ||||
|   meta_screen_get_size (window_group->screen, &screen_width, &screen_height); | ||||
|  | ||||
|   /* Normally we expect an actor to be drawn at it's position on the screen. | ||||
|    * However, if we're inside the paint of a ClutterClone, that won't be the | ||||
|    * case and we need to compensate. We look at the position of the window | ||||
| @@ -136,7 +81,7 @@ meta_window_group_paint (ClutterActor *actor) | ||||
|    * painting currently, and never worry about how actors are positioned | ||||
|    * on the stage. | ||||
|    */ | ||||
|   if (!painting_untransformed (window_group, &paint_x_origin, &paint_y_origin) || | ||||
|   if (!meta_actor_painting_untransformed (screen_width, screen_height, &paint_x_origin, &paint_y_origin) || | ||||
|       !meta_actor_is_untransformed (actor, &actor_x_origin, &actor_y_origin)) | ||||
|     { | ||||
|       CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor); | ||||
|   | ||||
| @@ -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_add_vignette    (MetaBackgroundActor *self, | ||||
|                                             double               brightness, | ||||
|                                             double               sharpness); | ||||
| void meta_background_actor_remove_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 */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user