diff options
author | Ray Strode <rstrode@redhat.com> | 2013-01-23 15:54:41 -0500 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2013-02-13 15:30:24 -0500 |
commit | 5792e2311094ea2b6f5a62bc9138c7cf832a1088 (patch) | |
tree | c45c8a7a98210513bea6ceceea78d59cb49a1ab1 | |
parent | 995e8040dd696e8b0c33a19ca4a49de7a03691b0 (diff) | |
download | mutter-wip/drop-gnome-bg.tar.gz |
compositor: rework how backgrounds are managedwip/drop-gnome-bg
Background handling in GNOME is very roundabout at the moment.
gnome-settings-daemon uses gnome-desktop to read the background from
disk into a screen-sized pixmap. It then sets the XID of that pixmap
on the _XROOTPMAP_ID root window property.
mutter puts that pixmap into a texture/actor which gnome-shell then
uses.
Having the gnome-settings-daemon detour from disk to screen means we
can't easily let the compositor handle transition effects when
switching backgrounds. Also, having the background actor be
per-screen instead of per-monitor means we may have oversized
textures in certain multihead setups.
This commit changes mutter to read backgrounds from disk itself, and
it changes backgrounds to be per-monitor.
This way background handling/compositing is left to the compositor.
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/compositor/compositor-private.h | 1 | ||||
-rw-r--r-- | src/compositor/compositor.c | 116 | ||||
-rw-r--r-- | src/compositor/meta-background-actor-private.h | 3 | ||||
-rw-r--r-- | src/compositor/meta-background-actor.c | 600 | ||||
-rw-r--r-- | src/compositor/meta-background-group-private.h | 11 | ||||
-rw-r--r-- | src/compositor/meta-background-group.c | 78 | ||||
-rw-r--r-- | src/compositor/meta-background.c | 1163 | ||||
-rw-r--r-- | src/compositor/meta-window-group.c | 16 | ||||
-rw-r--r-- | src/meta/compositor-mutter.h | 1 | ||||
-rw-r--r-- | src/meta/meta-background-actor.h | 41 | ||||
-rw-r--r-- | src/meta/meta-background-group.h | 46 | ||||
-rw-r--r-- | src/meta/meta-background.h | 104 |
13 files changed, 1531 insertions, 656 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 51fc9453c..ea0f69709 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,8 +46,11 @@ libmutter_la_SOURCES = \ compositor/cogl-utils.h \ compositor/compositor.c \ compositor/compositor-private.h \ + compositor/meta-background.c \ compositor/meta-background-actor.c \ compositor/meta-background-actor-private.h \ + compositor/meta-background-group.c \ + compositor/meta-background-group-private.h \ compositor/meta-module.c \ compositor/meta-module.h \ compositor/meta-plugin.c \ @@ -69,7 +72,9 @@ libmutter_la_SOURCES = \ compositor/region-utils.c \ compositor/region-utils.h \ meta/compositor.h \ + meta/meta-background.h \ meta/meta-background-actor.h \ + meta/meta-background-group.h \ meta/meta-plugin.h \ meta/meta-shadow-factory.h \ meta/meta-window-actor.h \ @@ -173,6 +178,8 @@ libmutterinclude_base_headers = \ meta/keybindings.h \ meta/main.h \ meta/meta-background-actor.h \ + meta/meta-background-group.h \ + meta/meta-background.h \ meta/meta-plugin.h \ meta/meta-shaped-texture.h \ meta/meta-shadow-factory.h \ diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h index 6da647188..7bd810a31 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -39,7 +39,6 @@ struct _MetaCompScreen MetaScreen *screen; ClutterActor *stage, *window_group, *overlay_group; - ClutterActor *background_actor; ClutterActor *hidden_group; GList *windows; GHashTable *windows_by_xid; diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index dabe59ec8..ea27c2273 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -13,10 +13,11 @@ #include "xprops.h" #include <meta/prefs.h> #include <meta/main.h> +#include <meta/meta-background-actor.h> +#include <meta/meta-background-group.h> #include <meta/meta-shadow-factory.h> #include "meta-window-actor-private.h" #include "meta-window-group.h" -#include "meta-background-actor-private.h" #include "window-private.h" /* to check window->hidden */ #include "display-private.h" /* for meta_display_lookup_x_window() */ #include <X11/extensions/shape.h> @@ -117,21 +118,6 @@ process_property_notify (MetaCompositor *compositor, { MetaWindowActor *window_actor; - if (event->atom == compositor->atom_x_root_pixmap) - { - GSList *l; - - for (l = meta_display_get_screens (compositor->display); l; l = l->next) - { - MetaScreen *screen = l->data; - if (event->window == meta_screen_get_xroot (screen)) - { - meta_background_actor_update (screen); - return; - } - } - } - if (window == NULL) return; @@ -238,27 +224,6 @@ meta_get_window_group_for_screen (MetaScreen *screen) } /** - * meta_get_background_actor_for_screen: - * @screen: a #MetaScreen - * - * Gets the actor that draws the root window background under the windows. - * The root window background automatically tracks the image or color set - * by the environment. - * - * Returns: (transfer none): The background actor corresponding to @screen - */ -ClutterActor * -meta_get_background_actor_for_screen (MetaScreen *screen) -{ - MetaCompScreen *info = meta_screen_get_compositor_data (screen); - - if (!info) - return NULL; - - return info->background_actor; -} - -/** * meta_get_window_actors: * @screen: a #MetaScreen * @@ -588,14 +553,9 @@ meta_compositor_manage_screen (MetaCompositor *compositor, } info->window_group = meta_window_group_new (screen); - info->background_actor = meta_background_actor_new_for_screen (screen); info->overlay_group = clutter_group_new (); info->hidden_group = clutter_group_new (); - clutter_container_add (CLUTTER_CONTAINER (info->window_group), - info->background_actor, - NULL); - clutter_container_add (CLUTTER_CONTAINER (info->stage), info->window_group, info->overlay_group, @@ -984,8 +944,11 @@ static void sync_actor_stacking (MetaCompScreen *info) { GList *children; + GList *expected_window_node; GList *tmp; GList *old; + GList *backgrounds; + gboolean has_windows; gboolean reordered; /* NB: The first entries in the lists are stacked the lowest */ @@ -997,48 +960,46 @@ sync_actor_stacking (MetaCompScreen *info) children = clutter_container_get_children (CLUTTER_CONTAINER (info->window_group)); reordered = FALSE; - old = children; - /* We allow for actors in the window group other than the actors we * know about, but it's up to a plugin to try and keep them stacked correctly * (we really need extra API to make that reliable.) */ - /* Of the actors we know, the bottom actor should be the background actor */ - - while (old && old->data != info->background_actor && !META_IS_WINDOW_ACTOR (old->data)) - old = old->next; - if (old == NULL || old->data != info->background_actor) - { - reordered = TRUE; - goto done_with_check; - } - - /* Then the window actors should follow in sequence */ - - old = old->next; - for (tmp = info->windows; tmp != NULL; tmp = tmp->next) + /* First we collect a list of all backgrounds, and check if they're at the + * bottom. Then we check if the window actors are in the correct sequence */ + backgrounds = NULL; + expected_window_node = info->windows; + for (old = children; old != NULL; old = old->next) { - while (old && !META_IS_WINDOW_ACTOR (old->data)) - old = old->next; + ClutterActor *actor = old->data; - /* old == NULL: someone reparented a window out of the window group, - * order undefined, always restack */ - if (old == NULL || old->data != tmp->data) + if (META_IS_BACKGROUND_GROUP (actor) || + META_IS_BACKGROUND_ACTOR (actor)) { - reordered = TRUE; - goto done_with_check; + backgrounds = g_list_prepend (backgrounds, actor); + + if (has_windows) + reordered = TRUE; } + else if (META_IS_WINDOW_ACTOR (actor) && !reordered) + { + has_windows = TRUE; - old = old->next; + if (expected_window_node != NULL && actor == expected_window_node->data) + expected_window_node = expected_window_node->next; + else + reordered = TRUE; + } } - done_with_check: - - g_list_free (children); - if (!reordered) - return; + { + g_list_free (backgrounds); + return; + } + + /* reorder the actors by lowering them in turn to the bottom of the stack. + * windows first, then backgrounds */ for (tmp = g_list_last (info->windows); tmp != NULL; tmp = tmp->prev) { @@ -1047,7 +1008,16 @@ sync_actor_stacking (MetaCompScreen *info) clutter_actor_lower_bottom (CLUTTER_ACTOR (window_actor)); } - clutter_actor_lower_bottom (info->background_actor); + /* we prepended the backgrounds above so the last actor in the list + * should get lowered to the bottom last. + */ + for (tmp = backgrounds; tmp != NULL; tmp = tmp->next) + { + ClutterActor *actor = tmp->data; + + clutter_actor_lower_bottom (CLUTTER_ACTOR (actor)); + } + g_list_free (backgrounds); } void @@ -1202,8 +1172,6 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor, XResizeWindow (xdisplay, xwin, width, height); - meta_background_actor_screen_size_changed (screen); - meta_verbose ("Changed size for stage on screen %d to %dx%d\n", meta_screen_get_screen_number (screen), width, height); diff --git a/src/compositor/meta-background-actor-private.h b/src/compositor/meta-background-actor-private.h index f5d656e0c..aeaf77fa0 100644 --- a/src/compositor/meta-background-actor-private.h +++ b/src/compositor/meta-background-actor-private.h @@ -9,7 +9,6 @@ void meta_background_actor_set_visible_region (MetaBackgroundActor *self, cairo_region_t *visible_region); -void meta_background_actor_update (MetaScreen *screen); -void meta_background_actor_screen_size_changed (MetaScreen *screen); +cairo_region_t *meta_background_actor_get_visible_region (MetaBackgroundActor *self); #endif /* META_BACKGROUND_ACTOR_PRIVATE_H */ diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c index 41306b16c..d2296dd85 100644 --- a/src/compositor/meta-background-actor.c +++ b/src/compositor/meta-background-actor.c @@ -34,223 +34,29 @@ #include "cogl-utils.h" #include "compositor-private.h" #include <meta/errors.h> +#include <meta/meta-background.h> #include "meta-background-actor-private.h" -/* We allow creating multiple MetaBackgroundActors for the same MetaScreen to - * allow different rendering options to be set for different copies. - * But we want to share the same underlying CoglTexture for efficiency and - * to avoid driver bugs that might occur if we created multiple CoglTexturePixmaps - * for the same pixmap. - * - * This structure holds common information. - */ -typedef struct _MetaScreenBackground MetaScreenBackground; - -struct _MetaScreenBackground -{ - MetaScreen *screen; - GSList *actors; - - float texture_width; - float texture_height; - CoglTexture *texture; - CoglMaterialWrapMode wrap_mode; - guint have_pixmap : 1; -}; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE +#else +#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE +#endif struct _MetaBackgroundActorPrivate { - MetaScreenBackground *background; - CoglPipeline *pipeline; - cairo_region_t *visible_region; - float dim_factor; -}; - -enum -{ - PROP_0, - - PROP_DIM_FACTOR, - - PROP_LAST }; -static GParamSpec *obj_props[PROP_LAST]; - G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR); -static void set_texture (MetaScreenBackground *background, - CoglHandle texture); -static void set_texture_to_stage_color (MetaScreenBackground *background); - -static void -on_notify_stage_color (GObject *stage, - GParamSpec *pspec, - MetaScreenBackground *background) -{ - if (!background->have_pixmap) - set_texture_to_stage_color (background); -} - -static void -free_screen_background (MetaScreenBackground *background) -{ - set_texture (background, COGL_INVALID_HANDLE); - - if (background->screen != NULL) - { - ClutterActor *stage = meta_get_stage_for_screen (background->screen); - g_signal_handlers_disconnect_by_func (stage, - (gpointer) on_notify_stage_color, - background); - background->screen = NULL; - } -} - -static MetaScreenBackground * -meta_screen_background_get (MetaScreen *screen) -{ - MetaScreenBackground *background; - - background = g_object_get_data (G_OBJECT (screen), "meta-screen-background"); - if (background == NULL) - { - ClutterActor *stage; - - background = g_new0 (MetaScreenBackground, 1); - - background->screen = screen; - g_object_set_data_full (G_OBJECT (screen), "meta-screen-background", - background, (GDestroyNotify) free_screen_background); - - stage = meta_get_stage_for_screen (screen); - g_signal_connect (stage, "notify::color", - G_CALLBACK (on_notify_stage_color), background); - - meta_background_actor_update (screen); - } - - return background; -} - -static void -update_wrap_mode_of_actor (MetaBackgroundActor *self) -{ - MetaBackgroundActorPrivate *priv = self->priv; - - cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, priv->background->wrap_mode); -} - -static void -update_wrap_mode (MetaScreenBackground *background) -{ - GSList *l; - int width, height; - - meta_screen_get_size (background->screen, &width, &height); - - /* We turn off repeating when we have a full-screen pixmap to keep from - * getting artifacts from one side of the image sneaking into the other - * side of the image via bilinear filtering. - */ - if (width == background->texture_width && height == background->texture_height) - background->wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE; - else - background->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT; - - for (l = background->actors; l; l = l->next) - update_wrap_mode_of_actor (l->data); -} - -static void -set_texture_on_actor (MetaBackgroundActor *self) -{ - MetaBackgroundActorPrivate *priv = self->priv; - MetaDisplay *display = meta_screen_get_display (priv->background->screen); - - /* This may trigger destruction of an old texture pixmap, which, if - * the underlying X pixmap is already gone has the tendency to trigger - * X errors inside DRI. For safety, trap errors */ - meta_error_trap_push (display); - cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->background->texture); - meta_error_trap_pop (display); - - clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); -} - -static void -set_texture (MetaScreenBackground *background, - CoglHandle texture) -{ - MetaDisplay *display = meta_screen_get_display (background->screen); - GSList *l; - - /* This may trigger destruction of an old texture pixmap, which, if - * the underlying X pixmap is already gone has the tendency to trigger - * X errors inside DRI. For safety, trap errors */ - meta_error_trap_push (display); - if (background->texture != COGL_INVALID_HANDLE) - { - cogl_handle_unref (background->texture); - background->texture = COGL_INVALID_HANDLE; - } - meta_error_trap_pop (display); - - if (texture != COGL_INVALID_HANDLE) - background->texture = cogl_handle_ref (texture); - - background->texture_width = cogl_texture_get_width (background->texture); - background->texture_height = cogl_texture_get_height (background->texture); - - for (l = background->actors; l; l = l->next) - set_texture_on_actor (l->data); - - update_wrap_mode (background); -} - -/* Sets our pipeline to paint with a 1x1 texture of the stage's background - * color; doing this when we have no pixmap allows the application to turn - * off painting the stage. There might be a performance benefit to - * painting in this case with a solid color, but the normal solid color - * case is a 1x1 root pixmap, so we'd have to reverse-engineer that to - * actually pick up the (small?) performance win. This is just a fallback. - */ -static void -set_texture_to_stage_color (MetaScreenBackground *background) -{ - ClutterActor *stage = meta_get_stage_for_screen (background->screen); - ClutterColor color; - CoglHandle texture; - - clutter_stage_get_color (CLUTTER_STAGE (stage), &color); - - /* Slicing will prevent COGL from using hardware texturing for - * the tiled 1x1 pixmap, and will cause it to draw the window - * background in millions of separate 1x1 rectangles */ - texture = meta_create_color_texture_4ub (color.red, color.green, - color.blue, 0xff, - COGL_TEXTURE_NO_SLICING); - set_texture (background, texture); - cogl_handle_unref (texture); -} - static void meta_background_actor_dispose (GObject *object) { MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); - MetaBackgroundActorPrivate *priv = self->priv; meta_background_actor_set_visible_region (self, NULL); - if (priv->background != NULL) - { - priv->background->actors = g_slist_remove (priv->background->actors, self); - priv->background = NULL; - } - - g_clear_pointer(&priv->pipeline, cogl_object_unref); - G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object); } @@ -260,11 +66,15 @@ meta_background_actor_get_preferred_width (ClutterActor *actor, gfloat *min_width_p, gfloat *natural_width_p) { - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor); - MetaBackgroundActorPrivate *priv = self->priv; - int width, height; + ClutterContent *content; + gfloat width; + + content = clutter_actor_get_content (actor); - meta_screen_get_size (priv->background->screen, &width, &height); + if (content) + clutter_content_get_preferred_size (content, &width, NULL); + else + width = 0; if (min_width_p) *min_width_p = width; @@ -279,11 +89,15 @@ meta_background_actor_get_preferred_height (ClutterActor *actor, gfloat *natural_height_p) { - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor); - MetaBackgroundActorPrivate *priv = self->priv; - int width, height; + ClutterContent *content; + gfloat height; - meta_screen_get_size (priv->background->screen, &width, &height); + content = clutter_actor_get_content (actor); + + if (content) + clutter_content_get_preferred_size (content, NULL, &height); + else + height = 0; if (min_height_p) *min_height_p = height; @@ -291,64 +105,19 @@ meta_background_actor_get_preferred_height (ClutterActor *actor, *natural_height_p = height; } -static void -meta_background_actor_paint (ClutterActor *actor) -{ - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor); - MetaBackgroundActorPrivate *priv = self->priv; - guint8 opacity = clutter_actor_get_paint_opacity (actor); - guint8 color_component; - int width, height; - - meta_screen_get_size (priv->background->screen, &width, &height); - - color_component = (int)(0.5 + opacity * priv->dim_factor); - - cogl_pipeline_set_color4ub (priv->pipeline, - color_component, - color_component, - color_component, - opacity); - - cogl_set_source (priv->pipeline); - - if (priv->visible_region) - { - int n_rectangles = cairo_region_num_rectangles (priv->visible_region); - int i; - - for (i = 0; i < n_rectangles; i++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (priv->visible_region, i, &rect); - - cogl_rectangle_with_texture_coords (rect.x, rect.y, - rect.x + rect.width, rect.y + rect.height, - rect.x / priv->background->texture_width, - rect.y / priv->background->texture_height, - (rect.x + rect.width) / priv->background->texture_width, - (rect.y + rect.height) / priv->background->texture_height); - } - } - else - { - cogl_rectangle_with_texture_coords (0.0f, 0.0f, - width, height, - 0.0f, 0.0f, - width / priv->background->texture_width, - height / priv->background->texture_height); - } -} - static gboolean meta_background_actor_get_paint_volume (ClutterActor *actor, ClutterPaintVolume *volume) { - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor); - MetaBackgroundActorPrivate *priv = self->priv; - int width, height; + ClutterContent *content; + gfloat width, height; + + content = clutter_actor_get_content (actor); - meta_screen_get_size (priv->background->screen, &width, &height); + if (!content) + return FALSE; + + clutter_content_get_preferred_size (content, &width, &height); clutter_paint_volume_set_width (volume, width); clutter_paint_volume_set_height (volume, height); @@ -357,215 +126,48 @@ meta_background_actor_get_paint_volume (ClutterActor *actor, } static void -meta_background_actor_set_dim_factor (MetaBackgroundActor *self, - gfloat dim_factor) -{ - MetaBackgroundActorPrivate *priv = self->priv; - - if (priv->dim_factor == dim_factor) - return; - - priv->dim_factor = dim_factor; - - clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); - - g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DIM_FACTOR]); -} - -static void -meta_background_actor_get_property(GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); - MetaBackgroundActorPrivate *priv = self->priv; - - switch (prop_id) - { - case PROP_DIM_FACTOR: - g_value_set_float (value, priv->dim_factor); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -meta_background_actor_set_property(GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object); - - switch (prop_id) - { - case PROP_DIM_FACTOR: - meta_background_actor_set_dim_factor (self, g_value_get_float (value)); - 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 *pspec; g_type_class_add_private (klass, sizeof (MetaBackgroundActorPrivate)); object_class->dispose = meta_background_actor_dispose; - object_class->get_property = meta_background_actor_get_property; - object_class->set_property = meta_background_actor_set_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; actor_class->get_paint_volume = meta_background_actor_get_paint_volume; - - /** - * MetaBackgroundActor:dim-factor: - * - * Factor to dim the background by, between 0.0 (black) and 1.0 (original - * colors) - */ - pspec = g_param_spec_float ("dim-factor", - "Dim factor", - "Factor to dim the background by", - 0.0, 1.0, - 1.0, - G_PARAM_READWRITE); - obj_props[PROP_DIM_FACTOR] = pspec; - g_object_class_install_property (object_class, PROP_DIM_FACTOR, pspec); } static void meta_background_actor_init (MetaBackgroundActor *self) { - MetaBackgroundActorPrivate *priv; - - priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, - META_TYPE_BACKGROUND_ACTOR, - MetaBackgroundActorPrivate); - priv->dim_factor = 1.0; + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + META_TYPE_BACKGROUND_ACTOR, + MetaBackgroundActorPrivate); } /** * meta_background_actor_new: - * @screen: the #MetaScreen * - * Creates a new actor to draw the background for the given screen. + * 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_for_screen (MetaScreen *screen) +meta_background_actor_new (void) { MetaBackgroundActor *self; - MetaBackgroundActorPrivate *priv; - - g_return_val_if_fail (META_IS_SCREEN (screen), NULL); self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL); - priv = self->priv; - - priv->background = meta_screen_background_get (screen); - priv->background->actors = g_slist_prepend (priv->background->actors, self); - - /* A CoglMaterial and a CoglPipeline are the same thing */ - priv->pipeline = (CoglPipeline*) meta_create_texture_material (NULL); - - set_texture_on_actor (self); - update_wrap_mode_of_actor (self); return CLUTTER_ACTOR (self); } /** - * meta_background_actor_update: - * @screen: a #MetaScreen - * - * Refetches the _XROOTPMAP_ID property for the root window and updates - * the contents of the background actor based on that. There's no attempt - * to optimize out pixmap values that don't change (since a root pixmap - * could be replaced by with another pixmap with the same ID under some - * circumstances), so this should only be called when we actually receive - * a PropertyNotify event for the property. - */ -void -meta_background_actor_update (MetaScreen *screen) -{ - MetaScreenBackground *background; - MetaDisplay *display; - MetaCompositor *compositor; - Atom type; - int format; - gulong nitems; - gulong bytes_after; - guchar *data; - Pixmap root_pixmap_id; - - background = meta_screen_background_get (screen); - display = meta_screen_get_display (screen); - compositor = meta_display_get_compositor (display); - - root_pixmap_id = None; - if (!XGetWindowProperty (meta_display_get_xdisplay (display), - meta_screen_get_xroot (screen), - compositor->atom_x_root_pixmap, - 0, LONG_MAX, - False, - AnyPropertyType, - &type, &format, &nitems, &bytes_after, &data) && - type != None) - { - /* Got a property. */ - if (type == XA_PIXMAP && format == 32 && nitems == 1) - { - /* Was what we expected. */ - root_pixmap_id = *(Pixmap *)data; - } - - XFree(data); - } - - if (root_pixmap_id != None) - { - CoglHandle texture; - CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - GError *error = NULL; - - meta_error_trap_push (display); - texture = cogl_texture_pixmap_x11_new (ctx, root_pixmap_id, FALSE, &error); - meta_error_trap_pop (display); - - if (texture != COGL_INVALID_HANDLE) - { - set_texture (background, texture); - cogl_handle_unref (texture); - - background->have_pixmap = True; - return; - } - else - { - g_warning ("Failed to create background texture from pixmap: %s", - error->message); - g_error_free (error); - } - } - - background->have_pixmap = False; - set_texture_to_stage_color (background); -} - -/** * meta_background_actor_set_visible_region: * @self: a #MetaBackgroundActor * @visible_region: (allow-none): the area of the actor (in allocate-relative @@ -584,120 +186,44 @@ meta_background_actor_set_visible_region (MetaBackgroundActor *self, priv = self->priv; - if (priv->visible_region) - { - cairo_region_destroy (priv->visible_region); - priv->visible_region = NULL; - } + g_clear_pointer (&priv->visible_region, + (GDestroyNotify) + cairo_region_destroy); if (visible_region) - { - cairo_rectangle_int_t screen_rect = { 0 }; - meta_screen_get_size (priv->background->screen, &screen_rect.width, &screen_rect.height); - - /* Doing the intersection here is probably unnecessary - MetaWindowGroup - * should never compute a visible area that's larger than the root screen! - * but it's not that expensive and adds some extra robustness. - */ - priv->visible_region = cairo_region_create_rectangle (&screen_rect); - cairo_region_intersect (priv->visible_region, visible_region); - } -} - -/** - * meta_background_actor_screen_size_changed: - * @screen: a #MetaScreen - * - * Called by the compositor when the size of the #MetaScreen changes - */ -void -meta_background_actor_screen_size_changed (MetaScreen *screen) -{ - MetaScreenBackground *background = meta_screen_background_get (screen); - GSList *l; - - update_wrap_mode (background); - - for (l = background->actors; l; l = l->next) - clutter_actor_queue_relayout (l->data); + priv->visible_region = cairo_region_copy (visible_region); } /** - * meta_background_actor_add_glsl_snippet: - * @actor: a #MetaBackgroundActor - * @hook: where to insert the code - * @declarations: GLSL declarations - * @code: GLSL code - * @is_replace: wheter Cogl code should be replaced by the custom shader + * meta_background_actor_get_visible_region: + * @self: a #MetaBackgroundActor * - * Adds a GLSL snippet to the pipeline used for drawing the background. - * See #CoglSnippet for details. + * Return value (transfer full): a #cairo_region_t that represents the part of + * the background not obscured by other #MetaBackgroundActor or + * #MetaWindowActor objects. */ -void -meta_background_actor_add_glsl_snippet (MetaBackgroundActor *actor, - MetaSnippetHook hook, - const char *declarations, - const char *code, - gboolean is_replace) +cairo_region_t * +meta_background_actor_get_visible_region (MetaBackgroundActor *self) { - MetaBackgroundActorPrivate *priv; - CoglSnippet *snippet; - - g_return_if_fail (META_IS_BACKGROUND_ACTOR (actor)); - - priv = actor->priv; - - if (is_replace) - { - snippet = cogl_snippet_new (hook, declarations, NULL); - cogl_snippet_set_replace (snippet, code); - } - else - { - snippet = cogl_snippet_new (hook, declarations, code); - } - - if (hook == META_SNIPPET_HOOK_VERTEX || - hook == META_SNIPPET_HOOK_FRAGMENT) - cogl_pipeline_add_snippet (priv->pipeline, snippet); - else - cogl_pipeline_add_layer_snippet (priv->pipeline, 0, snippet); + MetaBackgroundActorPrivate *priv = self->priv; + ClutterActorBox content_box; + cairo_rectangle_int_t content_area = { 0 }; + cairo_region_t *visible_region; - cogl_object_unref (snippet); -} + g_return_val_if_fail (META_IS_BACKGROUND_ACTOR (self), NULL); -/** - * meta_background_actor_set_uniform_float: - * @actor: a #MetaBackgroundActor - * @uniform_name: - * @n_components: number of components (for vector uniforms) - * @count: number of uniforms (for array uniforms) - * @uniform: (array length=uniform_length): the float values to set - * @uniform_length: the length of @uniform. Must be exactly @n_components x @count, - * and is provided mainly for language bindings. - * - * Sets a new GLSL uniform to the provided value. This is mostly - * useful in congiunction with meta_background_actor_add_glsl_snippet(). - */ + if (!priv->visible_region) + return NULL; -void -meta_background_actor_set_uniform_float (MetaBackgroundActor *actor, - const char *uniform_name, - int n_components, - int count, - const float *uniform, - int uniform_length) -{ - MetaBackgroundActorPrivate *priv; + clutter_actor_get_content_box (CLUTTER_ACTOR (self), &content_box); - g_return_if_fail (META_IS_BACKGROUND_ACTOR (actor)); - g_return_if_fail (uniform_length == n_components * count); + content_area.x = content_box.x1; + content_area.y = content_box.y1; + content_area.width = content_box.x2 - content_box.x1; + content_area.height = content_box.y2 - content_box.y1; - priv = actor->priv; + visible_region = cairo_region_create_rectangle (&content_area); + cairo_region_intersect (visible_region, priv->visible_region); - cogl_pipeline_set_uniform_float (priv->pipeline, - cogl_pipeline_get_uniform_location (priv->pipeline, - uniform_name), - n_components, count, uniform); + return visible_region; } - diff --git a/src/compositor/meta-background-group-private.h b/src/compositor/meta-background-group-private.h new file mode 100644 index 000000000..5eca2688b --- /dev/null +++ b/src/compositor/meta-background-group-private.h @@ -0,0 +1,11 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +#ifndef META_BACKGROUND_GROUP_PRIVATE_H +#define META_BACKGROUND_GROUP_PRIVATE_H + +#include <meta/screen.h> +#include <meta/meta-background-group.h> + +void meta_background_group_set_visible_region (MetaBackgroundGroup *self, + cairo_region_t *visible_region); +#endif /* META_BACKGROUND_GROUP_PRIVATE_H */ diff --git a/src/compositor/meta-background-group.c b/src/compositor/meta-background-group.c new file mode 100644 index 000000000..9c3d08376 --- /dev/null +++ b/src/compositor/meta-background-group.c @@ -0,0 +1,78 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +#include <config.h> + +#include "compositor-private.h" +#include "meta-background-actor-private.h" +#include "meta-background-group-private.h" + +G_DEFINE_TYPE (MetaBackgroundGroup, meta_background_group, CLUTTER_TYPE_GROUP); + +struct _MetaBackgroundGroupPrivate +{ + ClutterLayoutManager *layout_manager; +}; + +static void +meta_background_group_dispose (GObject *object) +{ + G_OBJECT_CLASS (meta_background_group_parent_class)->dispose (object); +} + +static void +meta_background_group_class_init (MetaBackgroundGroupClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = meta_background_group_dispose; + + g_type_class_add_private (klass, sizeof (MetaBackgroundGroupPrivate)); +} + +static void +meta_background_group_init (MetaBackgroundGroup *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + META_TYPE_BACKGROUND_GROUP, + MetaBackgroundGroupPrivate); + + self->priv->layout_manager = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_FIXED, + CLUTTER_BIN_ALIGNMENT_FIXED); + + clutter_actor_set_layout_manager (CLUTTER_ACTOR (self), self->priv->layout_manager); +} + +/** + * meta_background_group_set_visible_region: + * @self: a #MetaBackgroundGroup + * @visible_region: (allow-none): the parts of the background to paint + * + * Sets the area of the backgrounds that is unobscured by overlapping windows. + * This is used to optimize and only paint the visible portions. + */ +void +meta_background_group_set_visible_region (MetaBackgroundGroup *self, + cairo_region_t *region) +{ + GList *children, *l; + + children = clutter_actor_get_children (CLUTTER_ACTOR (self)); + for (l = children; l; l = l->next) + { + ClutterActor *actor = l->data; + + if (META_IS_BACKGROUND_ACTOR (actor)) + meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (actor), region); + } + g_list_free (children); +} + +ClutterActor * +meta_background_group_new (void) +{ + MetaBackgroundGroup *background_group; + + background_group = g_object_new (META_TYPE_BACKGROUND_GROUP, NULL); + + return CLUTTER_ACTOR (background_group); +} diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c new file mode 100644 index 000000000..54e113e6c --- /dev/null +++ b/src/compositor/meta-background.c @@ -0,0 +1,1163 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * meta-background.c: CoglTexture for painting the system background + * + * Copyright 2013 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <config.h> + +#define COGL_ENABLE_EXPERIMENTAL_2_0_API +#include <cogl/cogl-texture-pixmap-x11.h> + +#include <clutter/clutter.h> + +#include "cogl-utils.h" +#include "compositor-private.h" +#include "mutter-enum-types.h" +#include <meta/errors.h> +#include <meta/meta-background.h> +#include "meta-background-actor-private.h" + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_BGRA_8888_PRE +#else +#define TEXTURE_FORMAT COGL_PIXEL_FORMAT_ARGB_8888_PRE +#endif + +#define TEXTURE_LOOKUP_SHADER_DECLARATIONS \ +"uniform vec2 pixel_step;\n" \ +"vec4 apply_blur(in sampler2D texture, in vec2 coordinates) {\n" \ +" vec4 texel;\n" \ +" texel = texture2D(texture, coordinates.st);\n" \ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2(-1.0, -1.0));\n"\ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2( 0.0, -1.0));\n"\ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2(+1.0, -1.0));\n"\ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2(-1.0, 0.0));\n"\ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2(+1.0, 0.0));\n"\ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2(-1.0, +1.0));\n"\ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2( 0.0, +1.0));\n"\ +" texel += texture2D(texture, coordinates.st + pixel_step * vec2(+1.0, +1.0));\n"\ +" texel /= 9.0;\n" \ +" return texel;\n" \ +"}\n" \ +"uniform float saturation;\n" \ +"vec3 desaturate(const vec3 color)\n" \ +"{\n" \ +" const vec3 gray_conv = vec3(0.299, 0.587, 0.114);\n" \ +" vec3 gray = vec3(dot(gray_conv, color));\n" \ +" return vec3(mix(color.rgb, gray, saturation));\n" \ +"}\n" \ + +#define DESATURATE_CODE \ +"cogl_texel.rgb = desaturate(cogl_texel.rgb);\n" + +#define BLUR_CODE \ +"cogl_texel = apply_blur(cogl_sampler, cogl_tex_coord.st);\n" + +#define FRAGMENT_SHADER_DECLARATIONS \ +"uniform float dim_factor;\n" \ + +#define VIGNETTE_CODE \ +"vec2 dist = cogl_tex_coord_in[0].xy - vec2(0.5, 0.5);\n" \ +"float ellipse_radius = 0.5;\n" \ +"float y = 250.0 / 255.0;\n" \ +"float x = 180.0 / 255.0;\n" \ +"float val = min(length(dist), ellipse_radius);\n" \ +"float a = mix(x, y, val / ellipse_radius);\n" \ +"a = clamp(a - cogl_color_in.a + (1.0 - dim_factor), 0.0, 1.0);\n" \ +"cogl_color_out.rgb = cogl_color_out.rgb * (1.0 - a);\n" + +/* We allow creating multiple MetaBackgrounds for the same monitor to + * allow different rendering options to be set for different copies. + * But we want to share the same underlying CoglTextures for efficiency and + * to avoid driver bugs that might occur if we created multiple CoglTexturePixmaps + * for the same pixmap. + * + * This object provides a ClutterContent object to assist in sharing between actors. + */ +typedef struct _MetaBackgroundPrivate MetaBackgroundPrivate; + +struct _MetaBackgroundPrivate +{ + MetaScreen *screen; + CoglTexture *texture; + CoglPipeline *pipeline; + int monitor; + + MetaBackgroundEffects effects; + + GDesktopBackgroundStyle style; + GDesktopBackgroundShading shading_direction; + ClutterColor color; + ClutterColor second_color; + + char *filename; + + float dim_factor; + float saturation; + float vignette_radius; +}; + +enum +{ + PROP_META_SCREEN = 1, + PROP_MONITOR, + PROP_EFFECTS, + PROP_DIM_FACTOR, + PROP_SATURATION +}; + +static void clutter_content_iface_init (ClutterContentIface *iface); +static void unset_texture (MetaBackground *self); + +G_DEFINE_TYPE_WITH_CODE (MetaBackground, meta_background, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, + clutter_content_iface_init)) + + +static gboolean +meta_background_get_preferred_size (ClutterContent *content, + gfloat *width, + gfloat *height) +{ + MetaBackgroundPrivate *priv = META_BACKGROUND (content)->priv; + MetaRectangle monitor_geometry; + + if (priv->texture == NULL) + return FALSE; + + 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; + + return TRUE; +} + +static void +get_texture_area_and_scale (MetaBackground *self, + ClutterActorBox *actor_box, + cairo_rectangle_int_t *texture_area, + float *texture_x_scale, + float *texture_y_scale) +{ + MetaBackgroundPrivate *priv = self->priv; + MetaRectangle monitor_geometry; + cairo_rectangle_int_t actor_pixel_rect; + cairo_rectangle_int_t image_area; + int screen_width, screen_height; + float texture_width, texture_height; + float actor_x_scale, actor_y_scale; + float monitor_x_scale, monitor_y_scale; + + meta_screen_get_monitor_geometry (priv->screen, priv->monitor, &monitor_geometry); + + 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; + + texture_width = cogl_texture_get_width (priv->texture); + actor_x_scale = (1.0 * actor_pixel_rect.width / monitor_geometry.width); + + texture_height = cogl_texture_get_height (priv->texture); + actor_y_scale = (1.0 * actor_pixel_rect.height / monitor_geometry.height); + + switch (priv->style) + { + case G_DESKTOP_BACKGROUND_STYLE_STRETCHED: + default: + /* paint region is whole actor, and the texture + * is scaled disproportionately to fit the actor + */ + *texture_area = actor_pixel_rect; + *texture_x_scale = 1.0 / actor_pixel_rect.width; + *texture_y_scale = 1.0 / actor_pixel_rect.height; + break; + case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER: + /* paint region is the union of all monitors, with the origin + * of the region set to align with monitor associated with the background. + */ + meta_screen_get_size (priv->screen, &screen_width, &screen_height); + + /* unclipped texture area is whole screen */ + image_area.width = screen_width * actor_x_scale; + image_area.height = screen_height * actor_y_scale; + + /* But make (0,0) line up with the appropriate monitor */ + image_area.x = -(monitor_geometry.x + monitor_geometry.width / 2.0 - actor_pixel_rect.width / 2.0) * actor_x_scale; + image_area.y = -(monitor_geometry.y + monitor_geometry.height / 2.0 - actor_pixel_rect.height / 2.0) * actor_y_scale; + + *texture_area = image_area; + + /* paint region is whole actor, and the texture + * is left unscaled + */ + image_area = actor_pixel_rect; + *texture_x_scale = 1.0 / texture_width; + *texture_y_scale = 1.0 / texture_height; + + *texture_area = image_area; + break; + case G_DESKTOP_BACKGROUND_STYLE_CENTERED: + /* paint region is the original image size centered in the actor, + * and the texture is scaled to the original image size */ + image_area.width = texture_width; + image_area.height = texture_height; + image_area.x = actor_pixel_rect.x + actor_pixel_rect.width / 2 - image_area.width / 2; + image_area.y = actor_pixel_rect.y + actor_pixel_rect.height / 2 - image_area.height / 2; + + *texture_area = image_area; + *texture_x_scale = 1.0 / texture_width; + *texture_y_scale = 1.0 / texture_height; + break; + case G_DESKTOP_BACKGROUND_STYLE_SCALED: + case G_DESKTOP_BACKGROUND_STYLE_ZOOM: + /* paint region is the actor size in one dimension, and centered and + * scaled by proportional amount in the other dimension. + * + * SCALED forces the centered dimension to fit on screen. + * ZOOM forces the centered dimension to grow off screen + */ + monitor_x_scale = monitor_geometry.width / texture_width; + monitor_y_scale = monitor_geometry.height / texture_height; + + if ((priv->style == G_DESKTOP_BACKGROUND_STYLE_SCALED && + (monitor_x_scale < monitor_y_scale)) || + (priv->style == G_DESKTOP_BACKGROUND_STYLE_ZOOM && + (monitor_x_scale > monitor_y_scale))) + { + /* Fill image to exactly fit actor horizontally */ + image_area.width = actor_pixel_rect.width; + image_area.height = texture_height * monitor_x_scale * actor_y_scale; + + /* Position image centered vertically in actor */ + image_area.x = actor_pixel_rect.x; + image_area.y = actor_pixel_rect.y + actor_pixel_rect.height / 2 - image_area.height / 2; + } + else + { + /* Scale image to exactly fit actor vertically */ + image_area.width = texture_width * monitor_y_scale * actor_x_scale; + image_area.height = actor_pixel_rect.height; + + /* Position image centered horizontally in actor */ + image_area.x = actor_pixel_rect.x + actor_pixel_rect.width / 2 - image_area.width / 2; + image_area.y = actor_pixel_rect.y; + } + + *texture_area = image_area; + *texture_x_scale = 1.0 / image_area.width; + *texture_y_scale = 1.0 / image_area.height; + break; + + case G_DESKTOP_BACKGROUND_STYLE_SPANNED: + { + /* paint region is the union of all monitors, with the origin + * of the region set to align with monitor associated with the background. + */ + meta_screen_get_size (priv->screen, &screen_width, &screen_height); + + /* unclipped texture area is whole screen */ + image_area.width = screen_width * actor_x_scale; + image_area.height = screen_height * actor_y_scale; + + /* But make (0,0) line up with the appropriate monitor */ + image_area.x = -monitor_geometry.x * actor_x_scale; + image_area.y = -monitor_geometry.y * actor_y_scale; + + *texture_area = image_area; + *texture_x_scale = 1.0 / image_area.width; + *texture_y_scale = 1.0 / image_area.height; + break; + } + } +} + +static CoglPipelineWrapMode +get_wrap_mode (MetaBackground *self) +{ + MetaBackgroundPrivate *priv = self->priv; + switch (priv->style) + { + case G_DESKTOP_BACKGROUND_STYLE_WALLPAPER: + return COGL_PIPELINE_WRAP_MODE_REPEAT; + case G_DESKTOP_BACKGROUND_STYLE_NONE: + case G_DESKTOP_BACKGROUND_STYLE_STRETCHED: + case G_DESKTOP_BACKGROUND_STYLE_CENTERED: + case G_DESKTOP_BACKGROUND_STYLE_SCALED: + case G_DESKTOP_BACKGROUND_STYLE_ZOOM: + case G_DESKTOP_BACKGROUND_STYLE_SPANNED: + default: + return COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE; + } +} + +static ClutterPaintNode * +meta_background_paint_node_new (MetaBackground *self, + ClutterActor *actor) +{ + MetaBackgroundPrivate *priv = self->priv; + ClutterPaintNode *node; + guint8 opacity; + guint8 color_component; + + opacity = clutter_actor_get_paint_opacity (actor); + color_component = (guint8) (0.5 + opacity * priv->dim_factor); + + cogl_pipeline_set_color4ub (priv->pipeline, + color_component, + color_component, + color_component, + opacity); + + node = clutter_pipeline_node_new (priv->pipeline); + + return node; +} + +static void +clip_region_to_actor_box (cairo_region_t *region, + ClutterActorBox *actor_box) +{ + cairo_rectangle_int_t clip_rect; + + clip_rect.x = actor_box->x1; + clip_rect.y = actor_box->y1; + clip_rect.width = actor_box->x2 - actor_box->x1; + clip_rect.height = actor_box->y2 - actor_box->y1; + + cairo_region_intersect_rectangle (region, &clip_rect); +} + +static void +set_blur_parameters (MetaBackground *self, + ClutterActorBox *actor_box) +{ + MetaBackgroundPrivate *priv = self->priv; + float pixel_step[2]; + + if (!(priv->effects & META_BACKGROUND_EFFECTS_BLUR)) + return; + + pixel_step[0] = 1.0 / (actor_box->x2 - actor_box->x1); + pixel_step[1] = 1.0 / (actor_box->y2 - actor_box->y1); + + cogl_pipeline_set_uniform_float (priv->pipeline, + cogl_pipeline_get_uniform_location (priv->pipeline, + "pixel_step"), + 2, 1, pixel_step); +} + +static void +meta_background_paint_content (ClutterContent *content, + ClutterActor *actor, + ClutterPaintNode *root) +{ + MetaBackground *self = META_BACKGROUND (content); + MetaBackgroundPrivate *priv = self->priv; + ClutterPaintNode *node; + ClutterActorBox actor_box; + cairo_rectangle_int_t texture_area; + cairo_region_t *paintable_region = NULL; + int n_texture_subareas; + int i; + float texture_x_scale, texture_y_scale; + float tx1 = 0.0, ty1 = 0.0, tx2 = 1.0, ty2 = 1.0; + + if (priv->texture == NULL) + return; + + node = meta_background_paint_node_new (self, actor); + + clutter_actor_get_content_box (actor, &actor_box); + + set_blur_parameters (self, &actor_box); + + /* First figure out where on the monitor the texture is supposed to be painted. + * If the actor is not the size of the monitor, this function makes sure to scale + * everything down to fit in the actor. + */ + get_texture_area_and_scale (self, + &actor_box, + &texture_area, + &texture_x_scale, + &texture_y_scale); + + /* Now figure out what to actually paint. We start by clipping the texture area to + * the actor's bounds. + */ + paintable_region = cairo_region_create_rectangle (&texture_area); + + clip_region_to_actor_box (paintable_region, &actor_box); + + /* And then cut out any parts occluded by window actors + */ + if (META_IS_BACKGROUND_ACTOR (actor)) + { + cairo_region_t *visible_region; + visible_region = meta_background_actor_get_visible_region (META_BACKGROUND_ACTOR (actor)); + + if (visible_region != NULL) + { + cairo_region_intersect (paintable_region, visible_region); + cairo_region_destroy (visible_region); + } + } + + /* 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 texture_subarea; + ClutterActorBox texture_rectangle; + + cairo_region_get_rectangle (paintable_region, i, &texture_subarea); + + tx1 = (texture_subarea.x - texture_area.x) * texture_x_scale; + ty1 = (texture_subarea.y - texture_area.y) * texture_y_scale; + tx2 = (texture_subarea.x + texture_subarea.width - texture_area.x) * texture_x_scale; + ty2 = (texture_subarea.y + texture_subarea.height - texture_area.y) * texture_y_scale; + texture_rectangle.x1 = texture_subarea.x; + texture_rectangle.y1 = texture_subarea.y; + texture_rectangle.x2 = texture_subarea.x + texture_subarea.width; + texture_rectangle.y2 = texture_subarea.y + texture_subarea.height; + + clutter_paint_node_add_texture_rectangle (node, &texture_rectangle, tx1, ty1, tx2, ty2); + } + cairo_region_destroy (paintable_region); + + clutter_paint_node_add_child (root, node); + clutter_paint_node_unref (node); +} + +static void +clutter_content_iface_init (ClutterContentIface *iface) +{ + iface->get_preferred_size = meta_background_get_preferred_size; + iface->paint_content = meta_background_paint_content; +} + +static void +meta_background_dispose (GObject *object) +{ + MetaBackground *self = META_BACKGROUND (object); + MetaBackgroundPrivate *priv = self->priv; + + unset_texture (self); + + g_clear_pointer (&priv->pipeline, + (GDestroyNotify) + cogl_object_unref); + + G_OBJECT_CLASS (meta_background_parent_class)->dispose (object); +} + +static void +ensure_pipeline (MetaBackground *self) +{ + if (self->priv->pipeline == NULL) + self->priv->pipeline = COGL_PIPELINE (meta_create_texture_material (NULL)); +} + +static void +set_dim_factor (MetaBackground *self, + gfloat dim_factor) +{ + MetaBackgroundPrivate *priv = self->priv; + + if (priv->dim_factor == dim_factor) + return; + + priv->dim_factor = dim_factor; + + if (priv->effects & META_BACKGROUND_EFFECTS_VIGNETTE) + { + ensure_pipeline (self); + cogl_pipeline_set_uniform_1f (priv->pipeline, + cogl_pipeline_get_uniform_location (priv->pipeline, + "dim_factor"), + priv->dim_factor); + } + + clutter_content_invalidate (CLUTTER_CONTENT (self)); + + g_object_notify (G_OBJECT (self), "dim-factor"); +} + +static void +set_saturation (MetaBackground *self, + gfloat saturation) +{ + MetaBackgroundPrivate *priv = self->priv; + + if (priv->saturation == saturation) + return; + + priv->saturation = saturation; + + ensure_pipeline (self); + + cogl_pipeline_set_uniform_1f (priv->pipeline, + cogl_pipeline_get_uniform_location (priv->pipeline, + "saturation"), + priv->saturation); + + + clutter_content_invalidate (CLUTTER_CONTENT (self)); + + g_object_notify (G_OBJECT (self), "saturation"); +} + +static void +add_texture_lookup_shader (MetaBackground *self) +{ + MetaBackgroundPrivate *priv = self->priv; + CoglSnippet *snippet; + const char *code; + + ensure_pipeline (self); + + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP, + TEXTURE_LOOKUP_SHADER_DECLARATIONS, + NULL); + if ((priv->effects & META_BACKGROUND_EFFECTS_BLUR) && + (priv->effects & META_BACKGROUND_EFFECTS_DESATURATE)) + code = BLUR_CODE "\n" DESATURATE_CODE; + else if (priv->effects & META_BACKGROUND_EFFECTS_BLUR) + code = BLUR_CODE; + else if (priv->effects & META_BACKGROUND_EFFECTS_DESATURATE) + code = DESATURATE_CODE; + + cogl_snippet_set_replace (snippet, code); + cogl_pipeline_add_layer_snippet (priv->pipeline, 0, snippet); + cogl_object_unref (snippet); + + if (priv->effects & META_BACKGROUND_EFFECTS_DESATURATE) + cogl_pipeline_set_uniform_1f (priv->pipeline, + cogl_pipeline_get_uniform_location (priv->pipeline, + "saturation"), + priv->saturation); +} + +static void +add_vignette (MetaBackground *self) +{ + MetaBackgroundPrivate *priv = self->priv; + CoglSnippet *snippet; + + ensure_pipeline (self); + + snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, FRAGMENT_SHADER_DECLARATIONS, VIGNETTE_CODE); + cogl_pipeline_add_snippet (priv->pipeline, snippet); + cogl_object_unref (snippet); +} + +static void +set_effects (MetaBackground *self, + MetaBackgroundEffects effects) +{ + MetaBackgroundPrivate *priv = self->priv; + + priv->effects = effects; + + if ((priv->effects & META_BACKGROUND_EFFECTS_BLUR) || + (priv->effects & META_BACKGROUND_EFFECTS_DESATURATE)) + add_texture_lookup_shader (self); + + if ((priv->effects & META_BACKGROUND_EFFECTS_VIGNETTE)) + add_vignette (self); + + clutter_content_invalidate (CLUTTER_CONTENT (self)); +} + +static void +meta_background_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MetaBackground *self = META_BACKGROUND (object); + MetaBackgroundPrivate *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_EFFECTS: + set_effects (self, g_value_get_flags (value)); + break; + case PROP_DIM_FACTOR: + set_dim_factor (self, g_value_get_float (value)); + break; + case PROP_SATURATION: + set_saturation (self, g_value_get_float (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_background_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MetaBackgroundPrivate *priv = META_BACKGROUND (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_EFFECTS: + g_value_set_flags (value, priv->effects); + break; + case PROP_DIM_FACTOR: + g_value_set_float (value, priv->dim_factor); + break; + case PROP_SATURATION: + g_value_set_float (value, priv->saturation); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +meta_background_class_init (MetaBackgroundClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *param_spec; + + g_type_class_add_private (klass, sizeof (MetaBackgroundPrivate)); + + object_class->dispose = meta_background_dispose; + object_class->set_property = meta_background_set_property; + object_class->get_property = meta_background_get_property; + + param_spec = g_param_spec_object ("meta-screen", + "MetaScreen", + "MetaScreen", + META_TYPE_SCREEN, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); + + 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); + + g_object_class_install_property (object_class, + PROP_MONITOR, + param_spec); + + param_spec = g_param_spec_float ("dim-factor", + "dim-factor", + "Values less than 1.0 dim background", + 0.0, 1.0, + 1.0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); + g_object_class_install_property (object_class, PROP_DIM_FACTOR, param_spec); + + param_spec = g_param_spec_float ("saturation", + "saturation", + "Values less than 1.0 grays background", + 0.0, 1.0, + 1.0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); + g_object_class_install_property (object_class, PROP_SATURATION, param_spec); + + param_spec = g_param_spec_flags ("effects", + "Effects", + "Set to alter saturation, to blur, etc", + meta_background_effects_get_type (), + META_BACKGROUND_EFFECTS_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, PROP_EFFECTS, param_spec); +} + +static void +meta_background_init (MetaBackground *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + META_TYPE_BACKGROUND, + MetaBackgroundPrivate); + + self->priv->dim_factor = 1.0; + self->priv->saturation = 1.0; +} + +static void +unset_texture (MetaBackground *self) +{ + MetaBackgroundPrivate *priv = self->priv; + cogl_pipeline_set_layer_texture (priv->pipeline, 0, NULL); + + g_clear_pointer (&priv->texture, + (GDestroyNotify) + cogl_handle_unref); +} + +static void +set_texture (MetaBackground *self, + CoglTexture *texture) +{ + MetaBackgroundPrivate *priv = self->priv; + + priv->texture = texture; + cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->texture); +} + +static void +set_style (MetaBackground *self, + GDesktopBackgroundStyle style) +{ + MetaBackgroundPrivate *priv = self->priv; + CoglPipelineWrapMode wrap_mode; + + priv->style = style; + + wrap_mode = get_wrap_mode (self); + cogl_pipeline_set_layer_wrap_mode (priv->pipeline, 0, wrap_mode); +} + +static void +set_filename (MetaBackground *self, + const char *filename) +{ + MetaBackgroundPrivate *priv = self->priv; + + g_free (priv->filename); + priv->filename = g_strdup (filename); +} + +static Pixmap +get_still_frame_for_monitor (MetaScreen *screen, + int monitor) +{ + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdisplay = meta_display_get_xdisplay (display); + Window xroot = meta_screen_get_xroot (screen); + Pixmap pixmap; + GC gc; + XGCValues values; + MetaRectangle geometry; + int depth; + + meta_screen_get_monitor_geometry (screen, monitor, &geometry); + + depth = DefaultDepth (xdisplay, meta_screen_get_screen_number (screen)); + + pixmap = XCreatePixmap (xdisplay, + xroot, + geometry.width, geometry.height, depth); + + values.function = GXcopy; + values.plane_mask = AllPlanes; + values.fill_style = FillSolid; + values.subwindow_mode = IncludeInferiors; + + gc = XCreateGC (xdisplay, + xroot, + GCFunction | GCPlaneMask | GCFillStyle | GCSubwindowMode, + &values); + + XCopyArea (xdisplay, + xroot, pixmap, gc, + geometry.x, geometry.y, + geometry.width, geometry.height, + 0, 0); + + XFreeGC (xdisplay, gc); + + return pixmap; +} + +/** + * meta_background_load_still_frame: + * @self: the #MetaBackground + * + * Takes a screenshot of the desktop and uses it as the background + * source. + */ +void +meta_background_load_still_frame (MetaBackground *self) +{ + MetaBackgroundPrivate *priv = self->priv; + MetaDisplay *display = meta_screen_get_display (priv->screen); + Pixmap still_frame; + CoglHandle texture; + CoglContext *context = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + GError *error = NULL; + + ensure_pipeline (self); + + unset_texture (self); + set_style (self, G_DESKTOP_BACKGROUND_STYLE_STRETCHED); + + still_frame = get_still_frame_for_monitor (priv->screen, priv->monitor); + XSync (meta_display_get_xdisplay (display), False); + + meta_error_trap_push (display); + texture = cogl_texture_pixmap_x11_new (context, still_frame, FALSE, &error); + meta_error_trap_pop (display); + + if (error != NULL) + { + g_warning ("Failed to create background texture from pixmap: %s", + error->message); + g_error_free (error); + return; + } + + set_texture (self, COGL_TEXTURE (texture)); +} + +/** + * meta_background_load_gradient: + * @self: the #MetaBackground + * @shading_direction: the orientation of the gradient + * @color: the start color of the gradient + * @second_color: the end color of the gradient + * + * Clears any previously set background, and sets the background gradient. + * The gradient starts with @color and + * progresses toward @second_color in the direction of @shading_direction. + */ +void +meta_background_load_gradient (MetaBackground *self, + GDesktopBackgroundShading shading_direction, + ClutterColor *color, + ClutterColor *second_color) +{ + MetaBackgroundPrivate *priv = self->priv; + CoglHandle texture; + guint width, height; + uint8_t pixels[8]; + + ensure_pipeline (self); + + unset_texture (self); + set_style (self, G_DESKTOP_BACKGROUND_STYLE_NONE); + + priv->shading_direction = shading_direction; + + switch (priv->shading_direction) + { + case G_DESKTOP_BACKGROUND_SHADING_VERTICAL: + width = 1; + height = 2; + break; + case G_DESKTOP_BACKGROUND_SHADING_HORIZONTAL: + width = 2; + height = 1; + break; + default: + g_return_if_reached (); + } + + pixels[0] = color->red; + pixels[1] = color->green; + pixels[2] = color->blue; + pixels[3] = color->alpha; + pixels[4] = second_color->red; + pixels[5] = second_color->green; + pixels[6] = second_color->blue; + pixels[7] = second_color->alpha; + texture = cogl_texture_new_from_data (width, height, + COGL_TEXTURE_NO_SLICING, + TEXTURE_FORMAT, + COGL_PIXEL_FORMAT_ANY, + 4, + pixels); + set_texture (self, COGL_TEXTURE (texture)); +} + +/** + * meta_background_load_color: + * @self: the #MetaBackground + * @color: a #ClutterColor to solid fill background with + * + * Clears any previously set background, and sets the + * background to a solid color + * + * If @color is %NULL the stage color will be used. + */ +void +meta_background_load_color (MetaBackground *self, + ClutterColor *color) +{ + MetaBackgroundPrivate *priv = self->priv; + CoglHandle texture; + ClutterActor *stage = meta_get_stage_for_screen (priv->screen); + ClutterColor stage_color; + + ensure_pipeline (self); + + unset_texture (self); + set_style (self, G_DESKTOP_BACKGROUND_STYLE_NONE); + + if (color == NULL) + { + clutter_actor_get_background_color (stage, &stage_color); + color = &stage_color; + } + + texture = meta_create_color_texture_4ub (color->red, + color->green, + color->blue, + 0xff, + COGL_TEXTURE_NO_SLICING); + set_texture (self, COGL_TEXTURE (texture)); +} + +/** + * meta_background_load_file: + * @self: the #MetaBackground + * @filename: the image file to load + * @style: a #GDesktopBackgroundStyle to specify how background is laid out + * + * Loads the specified image and uses it as the background source. + * + * Returns whether or not the image was loaded + */ +gboolean +meta_background_load_file (MetaBackground *self, + const char *filename, + GDesktopBackgroundStyle style) +{ + CoglHandle texture; + GError *error = NULL; + + ensure_pipeline (self); + + unset_texture (self); + set_style (self, style); + set_filename (self, filename); + + texture = cogl_texture_new_from_file (filename, + COGL_TEXTURE_NO_SLICING, + TEXTURE_FORMAT, + &error); + + if (error != NULL) + return FALSE; + + set_texture (self, COGL_TEXTURE (texture)); + + return TRUE; +} + +/** + * meta_background_copy: + * @self: a #MetaBackground to copy + * @monitor: a monitor + * @effects: effects to use on copy of @self + * + * Creates a new #MetaBackground to draw the background for the given monitor. + * Background will be loaded from @self and will share state + * with @self, but may have different effects applied to it. + * + * Return value: (transfer full): the newly created background content + */ +MetaBackground * +meta_background_copy (MetaBackground *self, + int monitor, + MetaBackgroundEffects effects) +{ + MetaBackground *background; + + background = META_BACKGROUND (g_object_new (META_TYPE_BACKGROUND, + "meta-screen", self->priv->screen, + "monitor", monitor, + NULL)); + + background->priv->dim_factor = self->priv->dim_factor; + + background->priv->shading_direction = self->priv->shading_direction; + background->priv->color = self->priv->color; + background->priv->second_color = self->priv->second_color; + + /* we can reuse the pipeline if it has no effects applied, or + * if it has the same effects applied + */ + if (effects == self->priv->effects || + self->priv->effects == META_BACKGROUND_EFFECTS_NONE) + { + ensure_pipeline (self); + background->priv->pipeline = cogl_pipeline_copy (self->priv->pipeline); + background->priv->texture = cogl_object_ref (self->priv->texture); + background->priv->style = self->priv->style; + background->priv->saturation = self->priv->saturation; + + if (effects != self->priv->effects) + { + set_effects (background, effects); + + if (effects & META_BACKGROUND_EFFECTS_DESATURATE) + set_saturation (background, self->priv->saturation); + } + else + { + background->priv->effects = self->priv->effects; + } + + } + else + { + ensure_pipeline (background); + if (self->priv->texture != NULL) + set_texture (background, cogl_object_ref (self->priv->texture)); + set_style (background, self->priv->style); + set_effects (background, effects); + + if (effects & META_BACKGROUND_EFFECTS_DESATURATE) + set_saturation (background, self->priv->saturation); + } + + clutter_content_invalidate (CLUTTER_CONTENT (background)); + + return background; +} +/** + * meta_background_new: + * @screen: the #MetaScreen + * @monitor: a monitor in @screen + * @effects: which effect flags to enable + * + * Creates a new #MetaBackground to draw the background for the given monitor. + * The returned object should be set on a #MetaBackgroundActor with + * clutter_actor_set_content(). + * + * The background may be desaturated, blurred, or given a vignette depending + * on @effects. + * + * Return value: the newly created background content + */ +MetaBackground * +meta_background_new (MetaScreen *screen, + int monitor, + MetaBackgroundEffects effects) +{ + MetaBackground *background; + + background = META_BACKGROUND (g_object_new (META_TYPE_BACKGROUND, + "meta-screen", screen, + "monitor", monitor, + "effects", effects, + NULL)); + return background; +} + +/** + * meta_background_get_style: + * @self: a #MetaBackground + * + * Returns the current background style. + * + * Return value: a #GDesktopBackgroundStyle + */ +GDesktopBackgroundStyle +meta_background_get_style (MetaBackground *self) +{ + return self->priv->style; +} + +/** + * meta_background_get_shading: + * @self: a #MetaBackground + * + * Returns whether @self is a solid color, + * vertical gradient, horizontal gradient, + * or none of the above. + * + * Return value: a #GDesktopBackgroundShading + */ +GDesktopBackgroundShading +meta_background_get_shading (MetaBackground *self) +{ + return self->priv->shading_direction; +} + +/** + * meta_background_get_color: + * @self: a #MetaBackground + * + * Returns the first color of @self. If self + * is a gradient, the second color can be returned + * with meta_background_get_second_color(). + * + * Return value: (transfer none): a #ClutterColor + */ +const ClutterColor * +meta_background_get_color (MetaBackground *self) +{ + return &self->priv->color; +} + +/** + * meta_background_get_second_color: + * @self: a #MetaBackground + * + * Returns the second color of @self. If @self + * is not a gradient this function is undefined. + * + * Return value: (transfer none): a #ClutterColor + */ +const ClutterColor * +meta_background_get_second_color (MetaBackground *self) +{ + return &self->priv->second_color; +} + +/** + * meta_background_get_filename: + * @self: a #MetaBackground + * + * Returns the filename of the currently loaded file. + * IF @self is not loaded from a file this function is + * undefined. + * + * Return value: (transfer none): the filename + */ +const char * +meta_background_get_filename (MetaBackground *self) +{ + return self->priv->filename; +} diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index 2b423ea05..4f32dc8cd 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -11,6 +11,7 @@ #include "meta-window-actor-private.h" #include "meta-window-group.h" #include "meta-background-actor-private.h" +#include "meta-background-group-private.h" struct _MetaWindowGroupClass { @@ -219,7 +220,7 @@ meta_window_group_paint (ClutterActor *actor) * and subtract the opaque area of each window out of the visible * region that we pass to the windows below. */ - children = clutter_container_get_children (CLUTTER_CONTAINER (actor)); + children = clutter_actor_get_children (actor); children = g_list_reverse (children); /* Get the clipped redraw bounds from Clutter so that we can avoid @@ -296,19 +297,24 @@ meta_window_group_paint (ClutterActor *actor) meta_window_actor_set_visible_region_beneath (window_actor, visible_region); cairo_region_translate (visible_region, x, y); } - else if (META_IS_BACKGROUND_ACTOR (l->data)) + else if (META_IS_BACKGROUND_ACTOR (l->data) || + META_IS_BACKGROUND_GROUP (l->data)) { - MetaBackgroundActor *background_actor = l->data; + ClutterActor *background_actor = l->data; int x, y; - if (!actor_is_untransformed (CLUTTER_ACTOR (background_actor), &x, &y)) + if (!actor_is_untransformed (background_actor, &x, &y)) continue; x += paint_x_offset; y += paint_y_offset; cairo_region_translate (visible_region, - x, - y); - meta_background_actor_set_visible_region (background_actor, visible_region); + + if (META_IS_BACKGROUND_GROUP (background_actor)) + meta_background_group_set_visible_region (META_BACKGROUND_GROUP (background_actor), visible_region); + else + meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (background_actor), visible_region); cairo_region_translate (visible_region, x, y); } } diff --git a/src/meta/compositor-mutter.h b/src/meta/compositor-mutter.h index e196c655f..0527251b2 100644 --- a/src/meta/compositor-mutter.h +++ b/src/meta/compositor-mutter.h @@ -43,7 +43,6 @@ ClutterActor *meta_get_window_group_for_screen (MetaScreen *screen); void meta_disable_unredirect_for_screen (MetaScreen *screen); void meta_enable_unredirect_for_screen (MetaScreen *screen); -ClutterActor *meta_get_background_actor_for_screen (MetaScreen *screen); void meta_set_stage_input_region (MetaScreen *screen, XserverRegion region); void meta_empty_stage_input_region (MetaScreen *screen); diff --git a/src/meta/meta-background-actor.h b/src/meta/meta-background-actor.h index 71831af25..69ec37764 100644 --- a/src/meta/meta-background-actor.h +++ b/src/meta/meta-background-actor.h @@ -24,9 +24,13 @@ #define META_BACKGROUND_ACTOR_H #include <clutter/clutter.h> +#include <cogl/cogl.h> +#include <meta/gradient.h> #include <meta/screen.h> +#include <gsettings-desktop-schemas/gdesktop-enums.h> + /** * MetaBackgroundActor: * @@ -60,41 +64,6 @@ struct _MetaBackgroundActor GType meta_background_actor_get_type (void); -ClutterActor *meta_background_actor_new_for_screen (MetaScreen *screen); - -/** - * MetaSnippetHook: - * Temporary hack to work around Cogl not exporting CoglSnippetHook in - * the 1.0 API. Don't use. - */ -typedef enum { - /* Per pipeline vertex hooks */ - META_SNIPPET_HOOK_VERTEX = 0, - META_SNIPPET_HOOK_VERTEX_TRANSFORM, - - /* Per pipeline fragment hooks */ - META_SNIPPET_HOOK_FRAGMENT = 2048, - - /* Per layer vertex hooks */ - META_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM = 4096, - - /* Per layer fragment hooks */ - META_SNIPPET_HOOK_LAYER_FRAGMENT = 6144, - META_SNIPPET_HOOK_TEXTURE_LOOKUP -} MetaSnippetHook; - - -void meta_background_actor_add_glsl_snippet (MetaBackgroundActor *actor, - MetaSnippetHook hook, - const char *declarations, - const char *code, - gboolean is_replace); - -void meta_background_actor_set_uniform_float (MetaBackgroundActor *actor, - const char *uniform_name, - int n_components, - int count, - const float *uniform, - int uniform_length); +ClutterActor *meta_background_actor_new (void); #endif /* META_BACKGROUND_ACTOR_H */ diff --git a/src/meta/meta-background-group.h b/src/meta/meta-background-group.h new file mode 100644 index 000000000..cddc1c5f3 --- /dev/null +++ b/src/meta/meta-background-group.h @@ -0,0 +1,46 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +#ifndef META_BACKGROUND_GROUP_H +#define META_BACKGROUND_GROUP_H + +#include <clutter/clutter.h> + +/** + * MetaBackgroundGroup: + * + * This class is a subclass of ClutterGroup with special handling for + * MetaBackgroundActor when painting the group. It makes sure to only + * draw the parts of the backgrounds not occluded by opaque windows. + * + * See #MetaWindowGroup for more information behind the motivation, + * and details on implementation. + */ + +#define META_TYPE_BACKGROUND_GROUP (meta_background_group_get_type ()) +#define META_BACKGROUND_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND_GROUP, MetaBackgroundGroup)) +#define META_BACKGROUND_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND_GROUP, MetaBackgroundGroupClass)) +#define META_IS_BACKGROUND_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND_GROUP)) +#define META_IS_BACKGROUND_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND_GROUP)) +#define META_BACKGROUND_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND_GROUP, MetaBackgroundGroupClass)) + +typedef struct _MetaBackgroundGroup MetaBackgroundGroup; +typedef struct _MetaBackgroundGroupClass MetaBackgroundGroupClass; +typedef struct _MetaBackgroundGroupPrivate MetaBackgroundGroupPrivate; + +struct _MetaBackgroundGroupClass +{ + ClutterGroupClass parent_class; +}; + +struct _MetaBackgroundGroup +{ + ClutterGroup parent; + + MetaBackgroundGroupPrivate *priv; +}; + +GType meta_background_group_get_type (void); + +ClutterActor *meta_background_group_new (void); + +#endif /* META_BACKGROUND_GROUP_H */ diff --git a/src/meta/meta-background.h b/src/meta/meta-background.h new file mode 100644 index 000000000..130f6c129 --- /dev/null +++ b/src/meta/meta-background.h @@ -0,0 +1,104 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* + * meta-background.h: CoglTexture for paintnig the system background + * + * Copyright 2013 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#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> + +/** + * 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. + */ + +#define META_TYPE_BACKGROUND (meta_background_get_type ()) +#define META_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_BACKGROUND, MetaBackground)) +#define META_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_BACKGROUND, MetaBackgroundClass)) +#define META_IS_BACKGROUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_TYPE_BACKGROUND)) +#define META_IS_BACKGROUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_BACKGROUND)) +#define META_BACKGROUND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_BACKGROUND, MetaBackgroundClass)) + +typedef struct _MetaBackground MetaBackground; +typedef struct _MetaBackgroundClass MetaBackgroundClass; +typedef struct _MetaBackgroundPrivate MetaBackgroundPrivate; + +/** + * MetaBackgroundEffects: + * Which effects to enable on the background + */ + +typedef enum +{ + META_BACKGROUND_EFFECTS_NONE = 0, + META_BACKGROUND_EFFECTS_DESATURATE = 1 << 0, + META_BACKGROUND_EFFECTS_BLUR = 1 << 1, + META_BACKGROUND_EFFECTS_VIGNETTE = 1 << 2, +} MetaBackgroundEffects; + +struct _MetaBackgroundClass +{ + GObjectClass parent_class; +}; + +struct _MetaBackground +{ + GObject parent; + + MetaBackgroundPrivate *priv; +}; + +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); + +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_still_frame (MetaBackground *self); +gboolean meta_background_load_file (MetaBackground *self, + const char *filename, + GDesktopBackgroundStyle style); + +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); + +#endif /* META_BACKGROUND_H */ |