2010-11-14 12:37:17 -05:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
/*
|
|
|
|
* meta-background-actor.c: Actor for painting the root window background
|
|
|
|
*
|
|
|
|
* Copyright 2009 Sander Dijkhuis
|
|
|
|
* Copyright 2010 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Portions adapted from gnome-shell/src/shell-global.c
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#define COGL_ENABLE_EXPERIMENTAL_API
|
|
|
|
#include <cogl/cogl-texture-pixmap-x11.h>
|
|
|
|
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
|
|
|
|
#include "cogl-utils.h"
|
|
|
|
#include "compositor-private.h"
|
2011-03-05 19:29:12 -05:00
|
|
|
#include <meta/errors.h>
|
2011-08-28 21:20:29 -04:00
|
|
|
#include "meta-background-actor-private.h"
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
/* 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;
|
|
|
|
};
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
struct _MetaBackgroundActorPrivate
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 14:09:42 -04:00
|
|
|
MetaScreenBackground *background;
|
2010-11-14 12:37:17 -05:00
|
|
|
CoglHandle material;
|
|
|
|
cairo_region_t *visible_region;
|
2011-08-26 14:01:00 -04:00
|
|
|
float dim_factor;
|
2010-11-14 12:37:17 -05:00
|
|
|
};
|
|
|
|
|
2011-08-26 14:01:00 -04:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
|
|
|
|
PROP_DIM_FACTOR,
|
|
|
|
|
|
|
|
PROP_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *obj_props[PROP_LAST];
|
|
|
|
|
2010-11-14 12:37:17 -05:00
|
|
|
G_DEFINE_TYPE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYPE_ACTOR);
|
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-11-15 16:19:28 -05:00
|
|
|
static void
|
2011-08-28 14:09:42 -04:00
|
|
|
free_screen_background (MetaScreenBackground *background)
|
2010-11-15 16:19:28 -05:00
|
|
|
{
|
2011-08-28 14:09:42 -04:00
|
|
|
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)
|
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
cogl_material_set_layer_wrap_mode (priv->material, 0, priv->background->wrap_mode);
|
2011-08-28 14:09:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_wrap_mode (MetaScreenBackground *background)
|
|
|
|
{
|
|
|
|
GSList *l;
|
2010-11-15 16:19:28 -05:00
|
|
|
int width, height;
|
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
meta_screen_get_size (background->screen, &width, &height);
|
2010-11-15 16:19:28 -05:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2011-08-28 14:09:42 -04:00
|
|
|
if (width == background->texture_width && height == background->texture_height)
|
|
|
|
background->wrap_mode = COGL_MATERIAL_WRAP_MODE_CLAMP_TO_EDGE;
|
2010-11-15 16:19:28 -05:00
|
|
|
else
|
2011-08-28 14:09:42 -04:00
|
|
|
background->wrap_mode = COGL_MATERIAL_WRAP_MODE_REPEAT;
|
2010-11-15 16:19:28 -05:00
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
for (l = background->actors; l; l = l->next)
|
|
|
|
update_wrap_mode_of_actor (l->data);
|
2010-11-15 16:19:28 -05:00
|
|
|
}
|
|
|
|
|
2010-11-14 12:37:17 -05:00
|
|
|
static void
|
2011-08-28 14:09:42 -04:00
|
|
|
set_texture_on_actor (MetaBackgroundActor *self)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
|
|
|
MetaDisplay *display = meta_screen_get_display (priv->background->screen);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
/* 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);
|
2011-08-28 21:20:29 -04:00
|
|
|
cogl_material_set_layer (priv->material, 0, priv->background->texture);
|
2011-08-28 14:09:42 -04:00
|
|
|
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;
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
/* 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);
|
2011-08-28 14:09:42 -04:00
|
|
|
if (background->texture != COGL_INVALID_HANDLE)
|
|
|
|
{
|
|
|
|
cogl_handle_unref (background->texture);
|
|
|
|
background->texture = COGL_INVALID_HANDLE;
|
|
|
|
}
|
2010-11-14 12:37:17 -05:00
|
|
|
meta_error_trap_pop (display);
|
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
if (texture != COGL_INVALID_HANDLE)
|
|
|
|
background->texture = cogl_handle_ref (texture);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
background->texture_width = cogl_texture_get_width (background->texture);
|
|
|
|
background->texture_height = cogl_texture_get_height (background->texture);
|
2010-11-15 16:19:28 -05:00
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
for (l = background->actors; l; l = l->next)
|
|
|
|
set_texture_on_actor (l->data);
|
|
|
|
|
|
|
|
update_wrap_mode (background);
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Sets our material 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
|
2011-08-28 14:09:42 -04:00
|
|
|
set_texture_to_stage_color (MetaScreenBackground *background)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 14:09:42 -04:00
|
|
|
ClutterActor *stage = meta_get_stage_for_screen (background->screen);
|
2010-11-14 12:37:17 -05:00
|
|
|
ClutterColor color;
|
|
|
|
CoglHandle texture;
|
|
|
|
|
|
|
|
clutter_stage_get_color (CLUTTER_STAGE (stage), &color);
|
2011-06-13 17:18:27 -04:00
|
|
|
|
|
|
|
/* 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 */
|
2010-11-14 12:37:17 -05:00
|
|
|
texture = meta_create_color_texture_4ub (color.red, color.green,
|
2011-06-13 17:18:27 -04:00
|
|
|
color.blue, 0xff,
|
|
|
|
COGL_TEXTURE_NO_SLICING);
|
2011-08-28 14:09:42 -04:00
|
|
|
set_texture (background, texture);
|
2010-11-14 12:37:17 -05:00
|
|
|
cogl_handle_unref (texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_background_actor_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
meta_background_actor_set_visible_region (self, NULL);
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
if (priv->background != NULL)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
priv->background->actors = g_slist_remove (priv->background->actors, self);
|
|
|
|
priv->background = NULL;
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
if (priv->material != COGL_INVALID_HANDLE)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
cogl_handle_unref (priv->material);
|
|
|
|
priv->material = COGL_INVALID_HANDLE;
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
2012-02-16 15:53:21 -05:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_background_actor_get_preferred_width (ClutterActor *actor,
|
|
|
|
gfloat for_height,
|
|
|
|
gfloat *min_width_p,
|
|
|
|
gfloat *natural_width_p)
|
|
|
|
{
|
|
|
|
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
2010-11-14 12:37:17 -05:00
|
|
|
int width, height;
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
meta_screen_get_size (priv->background->screen, &width, &height);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
if (min_width_p)
|
|
|
|
*min_width_p = width;
|
|
|
|
if (natural_width_p)
|
2011-08-28 22:03:57 -04:00
|
|
|
*natural_width_p = width;
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_background_actor_get_preferred_height (ClutterActor *actor,
|
|
|
|
gfloat for_width,
|
|
|
|
gfloat *min_height_p,
|
|
|
|
gfloat *natural_height_p)
|
|
|
|
|
|
|
|
{
|
|
|
|
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
2010-11-14 12:37:17 -05:00
|
|
|
int width, height;
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
meta_screen_get_size (priv->background->screen, &width, &height);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
if (min_height_p)
|
|
|
|
*min_height_p = height;
|
|
|
|
if (natural_height_p)
|
|
|
|
*natural_height_p = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_background_actor_paint (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
2011-08-26 14:01:00 -04:00
|
|
|
guint8 opacity = clutter_actor_get_paint_opacity (actor);
|
|
|
|
guint8 color_component;
|
2010-11-14 12:37:17 -05:00
|
|
|
int width, height;
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
meta_screen_get_size (priv->background->screen, &width, &height);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
color_component = (int)(0.5 + opacity * priv->dim_factor);
|
2011-08-26 14:01:00 -04:00
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
cogl_material_set_color4ub (priv->material,
|
2011-08-26 14:01:00 -04:00
|
|
|
color_component,
|
|
|
|
color_component,
|
|
|
|
color_component,
|
|
|
|
opacity);
|
2011-02-12 17:41:07 -05:00
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
cogl_set_source (priv->material);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
if (priv->visible_region)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
int n_rectangles = cairo_region_num_rectangles (priv->visible_region);
|
2010-11-14 12:37:17 -05:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < n_rectangles; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_int_t rect;
|
2011-08-28 21:20:29 -04:00
|
|
|
cairo_region_get_rectangle (priv->visible_region, i, &rect);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
cogl_rectangle_with_texture_coords (rect.x, rect.y,
|
|
|
|
rect.x + rect.width, rect.y + rect.height,
|
2011-08-28 21:20:29 -04:00
|
|
|
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);
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cogl_rectangle_with_texture_coords (0.0f, 0.0f,
|
|
|
|
width, height,
|
|
|
|
0.0f, 0.0f,
|
2011-08-28 21:20:29 -04:00
|
|
|
width / priv->background->texture_width,
|
|
|
|
height / priv->background->texture_height);
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
meta_background_actor_get_paint_volume (ClutterActor *actor,
|
|
|
|
ClutterPaintVolume *volume)
|
|
|
|
{
|
|
|
|
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
2010-11-14 12:37:17 -05:00
|
|
|
int width, height;
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
meta_screen_get_size (priv->background->screen, &width, &height);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
clutter_paint_volume_set_width (volume, width);
|
|
|
|
clutter_paint_volume_set_height (volume, height);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-08-26 14:01:00 -04:00
|
|
|
static void
|
|
|
|
meta_background_actor_set_dim_factor (MetaBackgroundActor *self,
|
|
|
|
gfloat dim_factor)
|
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->dim_factor == dim_factor)
|
2011-08-26 14:01:00 -04:00
|
|
|
return;
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
priv->dim_factor = dim_factor;
|
2011-08-26 14:01:00 -04:00
|
|
|
|
|
|
|
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);
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv = self->priv;
|
2011-08-26 14:01:00 -04:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_DIM_FACTOR:
|
2011-08-28 21:20:29 -04:00
|
|
|
g_value_set_float (value, priv->dim_factor);
|
2011-08-26 14:01:00 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-14 12:37:17 -05:00
|
|
|
static void
|
|
|
|
meta_background_actor_class_init (MetaBackgroundActorClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
2011-08-26 14:01:00 -04:00
|
|
|
GParamSpec *pspec;
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
g_type_class_add_private (klass, sizeof (MetaBackgroundActorPrivate));
|
|
|
|
|
2010-11-14 12:37:17 -05:00
|
|
|
object_class->dispose = meta_background_actor_dispose;
|
2011-08-26 14:01:00 -04:00
|
|
|
object_class->get_property = meta_background_actor_get_property;
|
|
|
|
object_class->set_property = meta_background_actor_set_property;
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
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;
|
2011-08-26 14:01:00 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-08-26 14:01:00 -04:00
|
|
|
meta_background_actor_init (MetaBackgroundActor *self)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv;
|
|
|
|
|
|
|
|
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
|
|
|
META_TYPE_BACKGROUND_ACTOR,
|
|
|
|
MetaBackgroundActorPrivate);
|
|
|
|
priv->dim_factor = 1.0;
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_background_actor_new:
|
2011-08-28 21:20:29 -04:00
|
|
|
* @screen: the #MetaScreen
|
2010-11-14 12:37:17 -05:00
|
|
|
*
|
|
|
|
* Creates a new actor to draw the background for the given screen.
|
|
|
|
*
|
2011-08-28 21:20:29 -04:00
|
|
|
* Return value: the newly created background actor
|
2010-11-14 12:37:17 -05:00
|
|
|
*/
|
|
|
|
ClutterActor *
|
2011-08-28 21:20:29 -04:00
|
|
|
meta_background_actor_new_for_screen (MetaScreen *screen)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
|
|
|
MetaBackgroundActor *self;
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv;
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
g_return_val_if_fail (META_IS_SCREEN (screen), NULL);
|
|
|
|
|
|
|
|
self = g_object_new (META_TYPE_BACKGROUND_ACTOR, NULL);
|
2011-08-28 21:20:29 -04:00
|
|
|
priv = self->priv;
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
priv->background = meta_screen_background_get (screen);
|
|
|
|
priv->background->actors = g_slist_prepend (priv->background->actors, self);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
priv->material = meta_create_texture_material (NULL);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
set_texture_on_actor (self);
|
|
|
|
update_wrap_mode_of_actor (self);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
return CLUTTER_ACTOR (self);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_background_actor_update:
|
2011-08-28 14:09:42 -04:00
|
|
|
* @screen: a #MetaScreen
|
2010-11-14 12:37:17 -05:00
|
|
|
*
|
|
|
|
* 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
|
2011-08-28 14:09:42 -04:00
|
|
|
meta_background_actor_update (MetaScreen *screen)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 14:09:42 -04:00
|
|
|
MetaScreenBackground *background;
|
2010-11-14 12:37:17 -05:00
|
|
|
MetaDisplay *display;
|
|
|
|
MetaCompositor *compositor;
|
|
|
|
Atom type;
|
|
|
|
int format;
|
|
|
|
gulong nitems;
|
|
|
|
gulong bytes_after;
|
|
|
|
guchar *data;
|
|
|
|
Pixmap root_pixmap_id;
|
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
background = meta_screen_background_get (screen);
|
|
|
|
display = meta_screen_get_display (screen);
|
2010-11-14 12:37:17 -05:00
|
|
|
compositor = meta_display_get_compositor (display);
|
|
|
|
|
|
|
|
root_pixmap_id = None;
|
|
|
|
if (!XGetWindowProperty (meta_display_get_xdisplay (display),
|
2011-08-28 14:09:42 -04:00
|
|
|
meta_screen_get_xroot (screen),
|
2010-11-14 12:37:17 -05:00
|
|
|
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;
|
|
|
|
|
|
|
|
meta_error_trap_push (display);
|
|
|
|
texture = cogl_texture_pixmap_x11_new (root_pixmap_id, FALSE);
|
|
|
|
meta_error_trap_pop (display);
|
|
|
|
|
|
|
|
if (texture != COGL_INVALID_HANDLE)
|
|
|
|
{
|
2011-08-28 14:09:42 -04:00
|
|
|
set_texture (background, texture);
|
2010-11-14 12:37:17 -05:00
|
|
|
cogl_handle_unref (texture);
|
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
background->have_pixmap = True;
|
2010-11-14 12:37:17 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-28 14:09:42 -04:00
|
|
|
background->have_pixmap = False;
|
|
|
|
set_texture_to_stage_color (background);
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* meta_background_actor_set_visible_region:
|
|
|
|
* @self: a #MetaBackgroundActor
|
|
|
|
* @visible_region: (allow-none): the area of the actor (in allocate-relative
|
|
|
|
* coordinates) that is visible.
|
|
|
|
*
|
|
|
|
* Sets the area of the background that is unobscured by overlapping windows.
|
|
|
|
* This is used to optimize and only paint the visible portions.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_background_actor_set_visible_region (MetaBackgroundActor *self,
|
|
|
|
cairo_region_t *visible_region)
|
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
MetaBackgroundActorPrivate *priv;
|
|
|
|
|
2010-11-14 12:37:17 -05:00
|
|
|
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
|
|
|
|
|
2011-08-28 21:20:29 -04:00
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->visible_region)
|
2010-11-14 12:37:17 -05:00
|
|
|
{
|
2011-08-28 21:20:29 -04:00
|
|
|
cairo_region_destroy (priv->visible_region);
|
|
|
|
priv->visible_region = NULL;
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (visible_region)
|
|
|
|
{
|
|
|
|
cairo_rectangle_int_t screen_rect = { 0 };
|
2011-08-28 21:20:29 -04:00
|
|
|
meta_screen_get_size (priv->background->screen, &screen_rect.width, &screen_rect.height);
|
2010-11-14 12:37:17 -05:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2011-08-28 21:20:29 -04:00
|
|
|
priv->visible_region = cairo_region_create_rectangle (&screen_rect);
|
|
|
|
cairo_region_intersect (priv->visible_region, visible_region);
|
2010-11-14 12:37:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-15 16:19:28 -05:00
|
|
|
/**
|
|
|
|
* meta_background_actor_screen_size_changed:
|
2011-08-28 14:09:42 -04:00
|
|
|
* @screen: a #MetaScreen
|
2010-11-15 16:19:28 -05:00
|
|
|
*
|
|
|
|
* Called by the compositor when the size of the #MetaScreen changes
|
|
|
|
*/
|
|
|
|
void
|
2011-08-28 14:09:42 -04:00
|
|
|
meta_background_actor_screen_size_changed (MetaScreen *screen)
|
2010-11-15 16:19:28 -05:00
|
|
|
{
|
2011-08-28 14:09:42 -04:00
|
|
|
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);
|
2010-11-15 16:19:28 -05:00
|
|
|
}
|