[mutter/wip/gcampax/background: 58/68] MetaBackgroundActor: import background rendering using libgnome-desktop
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/gcampax/background: 58/68] MetaBackgroundActor: import background rendering using libgnome-desktop
- Date: Wed, 13 Feb 2013 21:32:22 +0000 (UTC)
commit dbc9303efd1d6c6e4a8c4efd9013ab501ea32520
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sat Nov 10 20:49:23 2012 +0100
MetaBackgroundActor: import background rendering using libgnome-desktop
Instead of relying on gnome-settings-daemon to set up _XROOTPMAP_ID
properly, do rendering in process and stuff the background into a normal
texture.
This will allow to do more fancy transitions in the future, using
Clutter to drive them.
https://bugzilla.gnome.org/show_bug.cgi?id=682427
configure.ac | 1 +
src/Makefile.am | 1 +
src/compositor/meta-background-actor-private.h | 13 ++
src/compositor/meta-background-actor.c | 209 +++++++++++------------
src/compositor/meta-background.c | 131 +++++++++++++++
5 files changed, 246 insertions(+), 109 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index da68ff9..29deae9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,6 +75,7 @@ MUTTER_PC_MODULES="
xcomposite >= 0.2 xfixes xrender xdamage xi >= 1.6.0
$CLUTTER_PACKAGE >= 1.13.5
cogl-1.0 >= 1.13.3
+ gnome-desktop-3.0
"
GLIB_GSETTINGS
diff --git a/src/Makefile.am b/src/Makefile.am
index 51fc945..7b28750 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,6 +48,7 @@ libmutter_la_SOURCES = \
compositor/compositor-private.h \
compositor/meta-background-actor.c \
compositor/meta-background-actor-private.h \
+ compositor/meta-background.c \
compositor/meta-module.c \
compositor/meta-module.h \
compositor/meta-plugin.c \
diff --git a/src/compositor/meta-background-actor-private.h b/src/compositor/meta-background-actor-private.h
index f5d656e..d46691c 100644
--- a/src/compositor/meta-background-actor-private.h
+++ b/src/compositor/meta-background-actor-private.h
@@ -3,6 +3,9 @@
#ifndef META_BACKGROUND_ACTOR_PRIVATE_H
#define META_BACKGROUND_ACTOR_PRIVATE_H
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#include <libgnome-desktop/gnome-bg.h>
+
#include <meta/screen.h>
#include <meta/meta-background-actor.h>
@@ -12,4 +15,14 @@ void meta_background_actor_set_visible_region (MetaBackgroundActor *self,
void meta_background_actor_update (MetaScreen *screen);
void meta_background_actor_screen_size_changed (MetaScreen *screen);
+GTask *meta_background_draw_async (MetaScreen *screen,
+ GnomeBG *bg,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+CoglHandle meta_background_draw_finish (MetaScreen *screen,
+ GAsyncResult *result,
+ GError **error);
+
+
#endif /* META_BACKGROUND_ACTOR_PRIVATE_H */
diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c
index 41306b1..558e953 100644
--- a/src/compositor/meta-background-actor.c
+++ b/src/compositor/meta-background-actor.c
@@ -29,8 +29,6 @@
#include <clutter/clutter.h>
-#include <X11/Xatom.h>
-
#include "cogl-utils.h"
#include "compositor-private.h"
#include <meta/errors.h>
@@ -51,11 +49,16 @@ struct _MetaScreenBackground
MetaScreen *screen;
GSList *actors;
+ GSettings *settings;
+ GnomeBG *bg;
+ GCancellable *cancellable;
+
float texture_width;
float texture_height;
CoglTexture *texture;
CoglMaterialWrapMode wrap_mode;
- guint have_pixmap : 1;
+
+ GTask *rendering_task;
};
struct _MetaBackgroundActorPrivate
@@ -82,30 +85,26 @@ 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)
+free_screen_background (MetaScreenBackground *background)
{
- if (!background->have_pixmap)
- set_texture_to_stage_color (background);
+ set_texture (background, COGL_INVALID_HANDLE);
+
+ g_cancellable_cancel (background->cancellable);
+ g_object_unref (background->cancellable);
+
+ g_object_unref (background->bg);
+ g_object_unref (background->settings);
}
static void
-free_screen_background (MetaScreenBackground *background)
+on_settings_changed (GSettings *settings,
+ const char *key,
+ 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;
- }
+ gnome_bg_load_from_preferences (background->bg,
+ background->settings);
}
static MetaScreenBackground *
@@ -116,18 +115,34 @@ meta_screen_background_get (MetaScreen *screen)
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);
+ background->settings = g_settings_new ("org.gnome.desktop.background");
+ g_signal_connect (background->settings, "changed",
+ G_CALLBACK (on_settings_changed), background);
+ background->bg = gnome_bg_new ();
+ g_signal_connect_object (background->bg, "transitioned",
+ G_CALLBACK (meta_background_actor_update),
+ screen, G_CONNECT_SWAPPED);
+ g_signal_connect_object (background->bg, "changed",
+ G_CALLBACK (meta_background_actor_update),
+ screen, G_CONNECT_SWAPPED);
+
+ background->texture_width = -1;
+ background->texture_height = -1;
+ background->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
+
+ on_settings_changed (background->settings, NULL, background);
+
+ /* GnomeBG has queued a changed event, but we need to start rendering now,
+ or it will be too late when we paint the first frame.
+ */
+ g_object_set_data (G_OBJECT (background->bg), "ignore-pending-change", GINT_TO_POINTER (TRUE));
meta_background_actor_update (screen);
}
@@ -209,30 +224,14 @@ set_texture (MetaScreenBackground *background,
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)
+static inline void
+meta_background_ensure_rendered (MetaScreenBackground *background)
{
- ClutterActor *stage = meta_get_stage_for_screen (background->screen);
- ClutterColor color;
- CoglHandle texture;
-
- clutter_stage_get_color (CLUTTER_STAGE (stage), &color);
+ if (G_LIKELY (background->rendering_task == NULL ||
+ background->texture != COGL_INVALID_HANDLE))
+ return;
- /* 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);
+ g_task_wait_sync (background->rendering_task);
}
static void
@@ -300,6 +299,8 @@ meta_background_actor_paint (ClutterActor *actor)
guint8 color_component;
int width, height;
+ meta_background_ensure_rendered (priv->background);
+
meta_screen_get_size (priv->background->screen, &width, &height);
color_component = (int)(0.5 + opacity * priv->dim_factor);
@@ -487,82 +488,72 @@ meta_background_actor_new_for_screen (MetaScreen *screen)
return CLUTTER_ACTOR (self);
}
+static void
+on_background_drawn (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ MetaScreen *screen = META_SCREEN (object);
+ MetaScreenBackground *background;
+ CoglHandle texture;
+ GError *error;
+
+ background = meta_screen_background_get (screen);
+
+ g_clear_object (&background->rendering_task);
+ g_clear_object (&background->cancellable);
+
+ error = NULL;
+ texture = meta_background_draw_finish (screen, result, &error);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ {
+ g_error_free (error);
+ return;
+ }
+
+ if (texture != COGL_INVALID_HANDLE)
+ {
+ set_texture (background, texture);
+ cogl_handle_unref (texture);
+ return;
+ }
+ else
+ {
+ g_warning ("Failed to create background texture from pixmap: %s",
+ error->message);
+ g_error_free (error);
+ }
+}
+
/**
* 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.
+ * Forces a redraw of the background. The redraw happens asynchronously in
+ * a thread, and the actual on screen change is therefore delayed until
+ * the redraw is finished.
*/
void
meta_background_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);
- }
+ if (background->cancellable)
+ {
+ g_cancellable_cancel (background->cancellable);
+ g_object_unref (background->cancellable);
}
- background->have_pixmap = False;
- set_texture_to_stage_color (background);
+ g_clear_object (&background->rendering_task);
+
+ background->cancellable = g_cancellable_new ();
+ background->rendering_task = meta_background_draw_async (screen,
+ background->bg,
+ background->cancellable,
+ on_background_drawn, NULL);
}
/**
diff --git a/src/compositor/meta-background.c b/src/compositor/meta-background.c
new file mode 100644
index 0000000..080dcef
--- /dev/null
+++ b/src/compositor/meta-background.c
@@ -0,0 +1,131 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * meta-background.c: Utilities for drawing the background
+ *
+ * Copyright 2012 Giovanni Campagna <scampa giovanni gmail com>
+ *
+ * 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"
+
+#include <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "meta-background-actor-private.h"
+#include <core/screen-private.h>
+
+typedef struct {
+ GnomeBG *bg;
+ GdkPixbuf *pixbuf;
+
+ GdkRectangle *monitors;
+ int num_monitors;
+} TaskData;
+
+static void
+task_data_free (gpointer task_data)
+{
+ TaskData *td = task_data;
+
+ g_object_unref (td->bg);
+ g_object_unref (td->pixbuf);
+
+ g_free (td->monitors);
+
+ g_slice_free (TaskData, td);
+}
+
+static void
+meta_background_draw_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ TaskData *td = task_data;
+
+ gnome_bg_draw_areas (td->bg,
+ td->pixbuf,
+ TRUE,
+ td->monitors,
+ td->num_monitors);
+
+ g_task_return_pointer (task, g_object_ref (td->pixbuf), g_object_unref);
+}
+
+GTask *
+meta_background_draw_async (MetaScreen *screen,
+ GnomeBG *bg,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ TaskData *td;
+ int i;
+
+ g_return_val_if_fail (META_IS_SCREEN (screen), NULL);
+ g_return_val_if_fail (GNOME_IS_BG (bg), NULL);
+
+ task = g_task_new (screen, cancellable, callback, user_data);
+ g_task_set_source_tag (task, meta_background_draw_async);
+ g_task_set_return_on_cancel (task, TRUE);
+ g_task_set_check_cancellable (task, TRUE);
+
+ td = g_slice_new (TaskData);
+ td->bg = g_object_ref (bg);
+ td->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ FALSE, /* has alpha */
+ 8, /* bits per sample */
+ screen->rect.width,
+ screen->rect.height);
+
+ td->num_monitors = meta_screen_get_n_monitors (screen);
+ td->monitors = g_new (GdkRectangle, td->num_monitors);
+ for (i = 0; i < td->num_monitors; i++)
+ meta_screen_get_monitor_geometry (screen, i, (MetaRectangle*)(td->monitors + i));
+
+ g_task_set_task_data (task, td, task_data_free);
+
+ g_task_run_in_thread (task, meta_background_draw_thread);
+
+ return task;
+}
+
+CoglHandle
+meta_background_draw_finish (MetaScreen *screen,
+ GAsyncResult *result,
+ GError **error)
+{
+ GdkPixbuf *pixbuf;
+ CoglHandle handle;
+
+ pixbuf = g_task_propagate_pointer (G_TASK (result), error);
+ if (pixbuf == NULL)
+ return COGL_INVALID_HANDLE;
+
+ handle = cogl_texture_new_from_data (gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf),
+ COGL_TEXTURE_NO_ATLAS | COGL_TEXTURE_NO_SLICING,
+ COGL_PIXEL_FORMAT_RGB_888,
+ COGL_PIXEL_FORMAT_RGB_888,
+ gdk_pixbuf_get_rowstride (pixbuf),
+ gdk_pixbuf_get_pixels (pixbuf));
+
+ g_object_unref (pixbuf);
+ return handle;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]