2009-08-04 16:08:59 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:shell-generic-container
|
|
|
|
* @short_description: A container class with signals for allocation
|
|
|
|
*
|
|
|
|
* #ShellGenericContainer is mainly a workaround for the current
|
|
|
|
* lack of GObject subclassing + vfunc overrides in gjs. We
|
|
|
|
* implement the container interface, but proxy the virtual functions
|
|
|
|
* into signals, which gjs can catch.
|
|
|
|
*/
|
|
|
|
|
2009-11-24 09:07:40 -05:00
|
|
|
#include "config.h"
|
|
|
|
|
2009-08-04 16:08:59 -04:00
|
|
|
#include "shell-generic-container.h"
|
|
|
|
|
|
|
|
#include <clutter/clutter.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <girepository.h>
|
|
|
|
|
2010-02-02 19:21:30 -05:00
|
|
|
static void shell_generic_container_iface_init (ClutterContainerIface *iface);
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE(ShellGenericContainer,
|
|
|
|
shell_generic_container,
|
|
|
|
CLUTTER_TYPE_GROUP,
|
|
|
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
|
|
|
|
shell_generic_container_iface_init));
|
2009-08-04 16:08:59 -04:00
|
|
|
|
|
|
|
struct _ShellGenericContainerPrivate {
|
2009-11-26 12:13:16 -05:00
|
|
|
GHashTable *skip_paint;
|
2009-08-04 16:08:59 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Signals */
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
GET_PREFERRED_WIDTH,
|
|
|
|
GET_PREFERRED_HEIGHT,
|
|
|
|
ALLOCATE,
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint shell_generic_container_signals [LAST_SIGNAL] = { 0 };
|
|
|
|
|
2010-02-02 19:21:30 -05:00
|
|
|
static ClutterContainerIface *parent_container_iface;
|
2009-08-04 16:08:59 -04:00
|
|
|
|
|
|
|
static gpointer
|
|
|
|
shell_generic_container_allocation_ref (ShellGenericContainerAllocation *alloc)
|
|
|
|
{
|
|
|
|
alloc->_refcount++;
|
|
|
|
return alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
shell_generic_container_allocation_unref (ShellGenericContainerAllocation *alloc)
|
|
|
|
{
|
|
|
|
if (--alloc->_refcount == 0)
|
|
|
|
{
|
|
|
|
g_slice_free1 (sizeof (ShellGenericContainerAllocation), alloc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
shell_generic_container_allocate (ClutterActor *self,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
ClutterAllocationFlags flags)
|
|
|
|
{
|
|
|
|
/* chain up to set actor->allocation */
|
|
|
|
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (self, box, flags);
|
|
|
|
|
|
|
|
g_signal_emit (G_OBJECT (self), shell_generic_container_signals[ALLOCATE], 0,
|
|
|
|
box, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
shell_generic_container_get_preferred_width (ClutterActor *actor,
|
|
|
|
gfloat for_height,
|
|
|
|
gfloat *min_width_p,
|
|
|
|
gfloat *natural_width_p)
|
|
|
|
{
|
|
|
|
ShellGenericContainerAllocation *alloc = g_slice_alloc0 (sizeof (ShellGenericContainerAllocation));
|
|
|
|
alloc->_refcount = 1;
|
|
|
|
g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_WIDTH], 0,
|
|
|
|
for_height, alloc);
|
|
|
|
if (min_width_p)
|
|
|
|
*min_width_p = alloc->min_size;
|
|
|
|
if (natural_width_p)
|
|
|
|
*natural_width_p = alloc->natural_size;
|
|
|
|
shell_generic_container_allocation_unref (alloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
shell_generic_container_get_preferred_height (ClutterActor *actor,
|
|
|
|
gfloat for_width,
|
|
|
|
gfloat *min_height_p,
|
|
|
|
gfloat *natural_height_p)
|
|
|
|
{
|
|
|
|
ShellGenericContainerAllocation *alloc = g_slice_alloc0 (sizeof (ShellGenericContainerAllocation));
|
|
|
|
alloc->_refcount = 1;
|
|
|
|
g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_HEIGHT], 0,
|
|
|
|
for_width, alloc);
|
|
|
|
if (min_height_p)
|
|
|
|
*min_height_p = alloc->min_size;
|
|
|
|
if (natural_height_p)
|
|
|
|
*natural_height_p = alloc->natural_size;
|
|
|
|
shell_generic_container_allocation_unref (alloc);
|
|
|
|
}
|
|
|
|
|
2009-11-26 12:13:16 -05:00
|
|
|
static void
|
|
|
|
shell_generic_container_paint (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
ShellGenericContainer *self = (ShellGenericContainer*) actor;
|
|
|
|
GList *iter, *children;
|
|
|
|
|
|
|
|
children = clutter_container_get_children ((ClutterContainer*) actor);
|
|
|
|
|
|
|
|
for (iter = children; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
ClutterActor *child = iter->data;
|
|
|
|
|
|
|
|
if (g_hash_table_lookup (self->priv->skip_paint, child))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
clutter_actor_paint (child);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (children);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
shell_generic_container_pick (ClutterActor *actor,
|
|
|
|
const ClutterColor *color)
|
|
|
|
{
|
|
|
|
ShellGenericContainer *self = (ShellGenericContainer*) actor;
|
|
|
|
GList *iter, *children;
|
|
|
|
|
|
|
|
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->pick (actor, color);
|
|
|
|
|
|
|
|
children = clutter_container_get_children ((ClutterContainer*) actor);
|
|
|
|
|
|
|
|
for (iter = children; iter; iter = iter->next)
|
|
|
|
{
|
|
|
|
ClutterActor *child = iter->data;
|
|
|
|
|
|
|
|
if (g_hash_table_lookup (self->priv->skip_paint, child))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
clutter_actor_paint (child);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (children);
|
|
|
|
}
|
|
|
|
|
2010-02-22 16:22:38 -05:00
|
|
|
/**
|
|
|
|
* shell_generic_container_get_n_skip_paint:
|
|
|
|
* @container: A #ShellGenericContainer
|
|
|
|
*
|
|
|
|
* Returns: Number of children which will not be painted.
|
|
|
|
*/
|
|
|
|
guint
|
|
|
|
shell_generic_container_get_n_skip_paint (ShellGenericContainer *self)
|
|
|
|
{
|
|
|
|
return g_hash_table_size (self->priv->skip_paint);
|
|
|
|
}
|
|
|
|
|
2009-11-26 12:13:16 -05:00
|
|
|
/**
|
|
|
|
* shell_generic_container_set_skip_paint:
|
|
|
|
* @container: A #ShellGenericContainer
|
|
|
|
* @child: Child #ClutterActor
|
|
|
|
* @skip %TRUE if we should skip painting
|
|
|
|
*
|
|
|
|
* Set whether or not we should skip painting @actor. Workaround for
|
|
|
|
* lack of gjs ability to override _paint vfunc.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
shell_generic_container_set_skip_paint (ShellGenericContainer *self,
|
|
|
|
ClutterActor *child,
|
|
|
|
gboolean skip)
|
|
|
|
{
|
|
|
|
gboolean currently_skipping;
|
|
|
|
|
|
|
|
currently_skipping = g_hash_table_lookup (self->priv->skip_paint, child) != NULL;
|
|
|
|
if (!!skip == currently_skipping)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!skip)
|
2010-02-02 19:21:30 -05:00
|
|
|
g_hash_table_remove (self->priv->skip_paint, child);
|
2009-11-26 12:13:16 -05:00
|
|
|
else
|
2010-02-02 19:21:30 -05:00
|
|
|
g_hash_table_insert (self->priv->skip_paint, child, child);
|
2009-11-26 12:13:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2010-02-02 19:21:30 -05:00
|
|
|
shell_generic_container_finalize (GObject *object)
|
2009-11-26 12:13:16 -05:00
|
|
|
{
|
|
|
|
ShellGenericContainer *self = (ShellGenericContainer*) object;
|
|
|
|
|
2010-02-02 19:21:30 -05:00
|
|
|
g_hash_table_destroy (self->priv->skip_paint);
|
2009-11-26 12:13:16 -05:00
|
|
|
|
2010-02-02 19:21:30 -05:00
|
|
|
G_OBJECT_CLASS (shell_generic_container_parent_class)->finalize (object);
|
2009-11-26 12:13:16 -05:00
|
|
|
}
|
|
|
|
|
2009-08-04 16:08:59 -04:00
|
|
|
static void
|
|
|
|
shell_generic_container_class_init (ShellGenericContainerClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
|
|
|
|
2010-02-02 19:21:30 -05:00
|
|
|
gobject_class->finalize = shell_generic_container_finalize;
|
2009-11-26 12:13:16 -05:00
|
|
|
|
2009-08-04 16:08:59 -04:00
|
|
|
actor_class->get_preferred_width = shell_generic_container_get_preferred_width;
|
|
|
|
actor_class->get_preferred_height = shell_generic_container_get_preferred_height;
|
|
|
|
actor_class->allocate = shell_generic_container_allocate;
|
2009-11-26 12:13:16 -05:00
|
|
|
actor_class->paint = shell_generic_container_paint;
|
|
|
|
actor_class->pick = shell_generic_container_pick;
|
2009-08-04 16:08:59 -04:00
|
|
|
|
|
|
|
shell_generic_container_signals[GET_PREFERRED_WIDTH] =
|
|
|
|
g_signal_new ("get-preferred-width",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
gi_cclosure_marshal_generic,
|
|
|
|
G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);
|
|
|
|
|
|
|
|
shell_generic_container_signals[GET_PREFERRED_HEIGHT] =
|
|
|
|
g_signal_new ("get-preferred-height",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
gi_cclosure_marshal_generic,
|
|
|
|
G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);
|
|
|
|
|
|
|
|
shell_generic_container_signals[ALLOCATE] =
|
|
|
|
g_signal_new ("allocate",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL,
|
|
|
|
gi_cclosure_marshal_generic,
|
|
|
|
G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR_BOX, CLUTTER_TYPE_ALLOCATION_FLAGS);
|
|
|
|
|
|
|
|
g_type_class_add_private (gobject_class, sizeof (ShellGenericContainerPrivate));
|
|
|
|
}
|
|
|
|
|
2010-02-02 19:21:30 -05:00
|
|
|
static void
|
|
|
|
shell_generic_container_remove (ClutterContainer *container,
|
|
|
|
ClutterActor *actor)
|
|
|
|
{
|
|
|
|
ShellGenericContainer *self = SHELL_GENERIC_CONTAINER (container);
|
|
|
|
|
|
|
|
g_hash_table_remove (self->priv->skip_paint, actor);
|
|
|
|
|
|
|
|
parent_container_iface->remove (container, actor);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
shell_generic_container_iface_init (ClutterContainerIface *iface)
|
|
|
|
{
|
|
|
|
parent_container_iface = g_type_interface_peek_parent (iface);
|
|
|
|
|
|
|
|
iface->remove = shell_generic_container_remove;
|
|
|
|
}
|
|
|
|
|
2009-08-04 16:08:59 -04:00
|
|
|
static void
|
|
|
|
shell_generic_container_init (ShellGenericContainer *area)
|
|
|
|
{
|
|
|
|
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_GENERIC_CONTAINER,
|
|
|
|
ShellGenericContainerPrivate);
|
2010-02-02 19:21:30 -05:00
|
|
|
area->priv->skip_paint = g_hash_table_new (NULL, NULL);
|
2009-08-04 16:08:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
GType shell_generic_container_allocation_get_type (void)
|
|
|
|
{
|
|
|
|
static GType gtype = G_TYPE_INVALID;
|
|
|
|
if (gtype == G_TYPE_INVALID)
|
|
|
|
{
|
|
|
|
gtype = g_boxed_type_register_static ("ShellGenericContainerAllocation",
|
|
|
|
(GBoxedCopyFunc)shell_generic_container_allocation_ref,
|
|
|
|
(GBoxedFreeFunc)shell_generic_container_allocation_unref);
|
|
|
|
}
|
|
|
|
return gtype;
|
|
|
|
}
|