[mutter] MetaBackgroundActor: allow creating multiple instances
- From: Owen Taylor <otaylor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] MetaBackgroundActor: allow creating multiple instances
- Date: Mon, 29 Aug 2011 11:52:38 +0000 (UTC)
commit c630046858299035e62be06acb01ef0ab460343e
Author: Owen W. Taylor <otaylor fishsoup net>
Date: Sun Aug 28 14:09:42 2011 -0400
MetaBackgroundActor: allow creating multiple instances
Instead of requiring a singleton MetaBackgroundActor for the screen,
allow creating multiple copies that internally share a single
CoglTexture behind the scenes. This will be useful for allowing
multiple views of the screen background with different rendering
options.
https://bugzilla.gnome.org/show_bug.cgi?id=656433
src/compositor/compositor.c | 5 +-
src/compositor/meta-background-actor.c | 241 ++++++++++++++++++++++----------
src/compositor/meta-background-actor.h | 5 +-
3 files changed, 170 insertions(+), 81 deletions(-)
---
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index 65e2b01..1ca59e1 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -125,8 +125,7 @@ process_property_notify (MetaCompositor *compositor,
MetaScreen *screen = l->data;
if (event->window == meta_screen_get_xroot (screen))
{
- MetaCompScreen *info = meta_screen_get_compositor_data (screen);
- meta_background_actor_update (META_BACKGROUND_ACTOR (info->background_actor));
+ meta_background_actor_update (screen);
return;
}
}
@@ -1087,7 +1086,7 @@ meta_compositor_sync_screen_size (MetaCompositor *compositor,
clutter_actor_set_size (info->stage, width, height);
- meta_background_actor_screen_size_changed (META_BACKGROUND_ACTOR (info->background_actor));
+ 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),
diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c
index 0ff2e84..d1ca421 100644
--- a/src/compositor/meta-background-actor.c
+++ b/src/compositor/meta-background-actor.c
@@ -35,6 +35,28 @@
#include <meta/errors.h>
#include "meta-background-actor.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;
+ CoglHandle texture;
+ CoglMaterialWrapMode wrap_mode;
+ guint have_pixmap : 1;
+};
+
struct _MetaBackgroundActorClass
{
ClutterActorClass parent_class;
@@ -44,58 +66,137 @@ struct _MetaBackgroundActor
{
ClutterActor parent;
+ MetaScreenBackground *background;
CoglHandle material;
- MetaScreen *screen;
cairo_region_t *visible_region;
- float texture_width;
- float texture_height;
-
- guint have_pixmap : 1;
};
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
-update_wrap_mode (MetaBackgroundActor *self)
+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)
+{
+ cogl_material_set_layer_wrap_mode (self->material, 0, self->background->wrap_mode);
+}
+
+static void
+update_wrap_mode (MetaScreenBackground *background)
+{
+ GSList *l;
int width, height;
- CoglMaterialWrapMode wrap_mode;
- meta_screen_get_size (self->screen, &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 == self->texture_width && height == self->texture_height)
- wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
+ if (width == background->texture_width && height == background->texture_height)
+ background->wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
else
- wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
+ background->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
- cogl_material_set_layer_wrap_mode (self->material, 0, wrap_mode);
+ for (l = background->actors; l; l = l->next)
+ update_wrap_mode_of_actor (l->data);
}
static void
-set_texture (MetaBackgroundActor *self,
- CoglHandle texture)
+set_texture_on_actor (MetaBackgroundActor *self)
{
- MetaDisplay *display;
+ MetaDisplay *display = meta_screen_get_display (self->background->screen);
- display = meta_screen_get_display (self->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_material_set_layer (self->material, 0, self->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);
- cogl_material_set_layer (self->material, 0, texture);
+ if (background->texture != COGL_INVALID_HANDLE)
+ {
+ cogl_handle_unref (background->texture);
+ background->texture = COGL_INVALID_HANDLE;
+ }
meta_error_trap_pop (display);
- self->texture_width = cogl_texture_get_width (texture);
- self->texture_height = cogl_texture_get_height (texture);
+ if (texture != COGL_INVALID_HANDLE)
+ background->texture = cogl_handle_ref (texture);
- update_wrap_mode (self);
+ background->texture_width = cogl_texture_get_width (background->texture);
+ background->texture_height = cogl_texture_get_height (background->texture);
- clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+ for (l = background->actors; l; l = l->next)
+ set_texture_on_actor (l->data);
+
+ update_wrap_mode (background);
}
/* Sets our material to paint with a 1x1 texture of the stage's background
@@ -106,9 +207,9 @@ set_texture (MetaBackgroundActor *self,
* actually pick up the (small?) performance win. This is just a fallback.
*/
static void
-set_texture_to_stage_color (MetaBackgroundActor *self)
+set_texture_to_stage_color (MetaScreenBackground *background)
{
- ClutterActor *stage = meta_get_stage_for_screen (self->screen);
+ ClutterActor *stage = meta_get_stage_for_screen (background->screen);
ClutterColor color;
CoglHandle texture;
@@ -120,39 +221,27 @@ set_texture_to_stage_color (MetaBackgroundActor *self)
texture = meta_create_color_texture_4ub (color.red, color.green,
color.blue, 0xff,
COGL_TEXTURE_NO_SLICING);
- set_texture (self, texture);
+ set_texture (background, texture);
cogl_handle_unref (texture);
}
static void
-on_notify_stage_color (GObject *stage,
- GParamSpec *pspec,
- MetaBackgroundActor *self)
-{
- if (!self->have_pixmap)
- set_texture_to_stage_color (self);
-}
-
-static void
meta_background_actor_dispose (GObject *object)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
meta_background_actor_set_visible_region (self, NULL);
- if (self->material != COGL_INVALID_HANDLE)
+ if (self->background != NULL)
{
- cogl_handle_unref (self->material);
- self->material = COGL_INVALID_HANDLE;
+ self->background->actors = g_slist_remove (self->background->actors, self);
+ self->background = NULL;
}
- if (self->screen != NULL)
+ if (self->material != COGL_INVALID_HANDLE)
{
- ClutterActor *stage = meta_get_stage_for_screen (self->screen);
- g_signal_handlers_disconnect_by_func (stage,
- (gpointer) on_notify_stage_color,
- self);
- self->screen = NULL;
+ cogl_handle_unref (self->material);
+ self->material = COGL_INVALID_HANDLE;
}
}
@@ -165,7 +254,7 @@ meta_background_actor_get_preferred_width (ClutterActor *actor,
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
int width, height;
- meta_screen_get_size (self->screen, &width, &height);
+ meta_screen_get_size (self->background->screen, &width, &height);
if (min_width_p)
*min_width_p = width;
@@ -183,7 +272,7 @@ meta_background_actor_get_preferred_height (ClutterActor *actor,
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
int width, height;
- meta_screen_get_size (self->screen, &width, &height);
+ meta_screen_get_size (self->background->screen, &width, &height);
if (min_height_p)
*min_height_p = height;
@@ -198,7 +287,7 @@ meta_background_actor_paint (ClutterActor *actor)
guchar opacity = clutter_actor_get_paint_opacity (actor);
int width, height;
- meta_screen_get_size (self->screen, &width, &height);
+ meta_screen_get_size (self->background->screen, &width, &height);
cogl_material_set_color4ub (self->material,
opacity, opacity, opacity, opacity);
@@ -217,10 +306,10 @@ meta_background_actor_paint (ClutterActor *actor)
cogl_rectangle_with_texture_coords (rect.x, rect.y,
rect.x + rect.width, rect.y + rect.height,
- rect.x / self->texture_width,
- rect.y / self->texture_height,
- (rect.x + rect.width) / self->texture_width,
- (rect.y + rect.height) / self->texture_height);
+ rect.x / self->background->texture_width,
+ rect.y / self->background->texture_height,
+ (rect.x + rect.width) / self->background->texture_width,
+ (rect.y + rect.height) / self->background->texture_height);
}
}
else
@@ -228,8 +317,8 @@ meta_background_actor_paint (ClutterActor *actor)
cogl_rectangle_with_texture_coords (0.0f, 0.0f,
width, height,
0.0f, 0.0f,
- width / self->texture_width,
- height / self->texture_height);
+ width / self->background->texture_width,
+ height / self->background->texture_height);
}
}
@@ -240,7 +329,7 @@ meta_background_actor_get_paint_volume (ClutterActor *actor,
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
int width, height;
- meta_screen_get_size (self->screen, &width, &height);
+ meta_screen_get_size (self->background->screen, &width, &height);
clutter_paint_volume_set_width (volume, width);
clutter_paint_volume_set_height (volume, height);
@@ -279,30 +368,25 @@ ClutterActor *
meta_background_actor_new (MetaScreen *screen)
{
MetaBackgroundActor *self;
- ClutterActor *stage;
g_return_val_if_fail (META_IS_SCREEN (screen), NULL);
self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL);
- self->screen = screen;
+ self->background = meta_screen_background_get (screen);
+ self->background->actors = g_slist_prepend (self->background->actors, self);
self->material = meta_create_texture_material (NULL);
- cogl_material_set_layer_wrap_mode (self->material, 0,
- COGL_MATERIAL_WRAP_MODE_REPEAT);
- stage = meta_get_stage_for_screen (self->screen);
- g_signal_connect (stage, "notify::color",
- G_CALLBACK (on_notify_stage_color), self);
-
- meta_background_actor_update (self);
+ set_texture_on_actor (self);
+ update_wrap_mode_of_actor (self);
return CLUTTER_ACTOR (self);
}
/**
* meta_background_actor_update:
- * @self: a #MetaBackgroundActor
+ * @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
@@ -312,8 +396,9 @@ meta_background_actor_new (MetaScreen *screen)
* a PropertyNotify event for the property.
*/
void
-meta_background_actor_update (MetaBackgroundActor *self)
+meta_background_actor_update (MetaScreen *screen)
{
+ MetaScreenBackground *background;
MetaDisplay *display;
MetaCompositor *compositor;
Atom type;
@@ -323,14 +408,13 @@ meta_background_actor_update (MetaBackgroundActor *self)
guchar *data;
Pixmap root_pixmap_id;
- g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
-
- display = meta_screen_get_display (self->screen);
+ 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 (self->screen),
+ meta_screen_get_xroot (screen),
compositor->atom_x_root_pixmap,
0, LONG_MAX,
False,
@@ -358,16 +442,16 @@ meta_background_actor_update (MetaBackgroundActor *self)
if (texture != COGL_INVALID_HANDLE)
{
- set_texture (self, texture);
+ set_texture (background, texture);
cogl_handle_unref (texture);
- self->have_pixmap = True;
+ background->have_pixmap = True;
return;
}
}
- self->have_pixmap = False;
- set_texture_to_stage_color (self);
+ background->have_pixmap = False;
+ set_texture_to_stage_color (background);
}
/**
@@ -394,7 +478,7 @@ meta_background_actor_set_visible_region (MetaBackgroundActor *self,
if (visible_region)
{
cairo_rectangle_int_t screen_rect = { 0 };
- meta_screen_get_size (self->screen, &screen_rect.width, &screen_rect.height);
+ meta_screen_get_size (self->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!
@@ -407,13 +491,18 @@ meta_background_actor_set_visible_region (MetaBackgroundActor *self,
/**
* meta_background_actor_screen_size_changed:
- * @self: a #MetaBackgroundActor
+ * @screen: a #MetaScreen
*
* Called by the compositor when the size of the #MetaScreen changes
*/
void
-meta_background_actor_screen_size_changed (MetaBackgroundActor *self)
+meta_background_actor_screen_size_changed (MetaScreen *screen)
{
- update_wrap_mode (self);
- clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+ 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);
}
diff --git a/src/compositor/meta-background-actor.h b/src/compositor/meta-background-actor.h
index d16a0f9..f34b778 100644
--- a/src/compositor/meta-background-actor.h
+++ b/src/compositor/meta-background-actor.h
@@ -50,9 +50,10 @@ GType meta_background_actor_get_type (void);
ClutterActor *meta_background_actor_new (MetaScreen *screen);
-void meta_background_actor_update (MetaBackgroundActor *actor);
void meta_background_actor_set_visible_region (MetaBackgroundActor *self,
cairo_region_t *visible_region);
-void meta_background_actor_screen_size_changed (MetaBackgroundActor *self);
+
+void meta_background_actor_update (MetaScreen *screen);
+void meta_background_actor_screen_size_changed (MetaScreen *screen);
#endif /* META_BACKGROUND_ACTOR_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]