Experimentally add build infrastructure and a few Tidy widgets

For experimenting with using tidy, import TidyButton and TidyGrid
(+ dependencies) into our source tree and set up build machinery
to build them and build a typelib for them.

The sources are build right into libgnome-shell.so, so the Shell.gir
and Tidy.gir actually point to the same shared library.

src/Makefile-tidy.am: Build libtidy-1.0.la
src/Makefile.am: Include built tidy into gnome-shell.la and
  build Tidy-1.0.typelib

src/tidy/*: Add some source files from Tidy

svn path=/trunk/; revision=42
This commit is contained in:
Owen Taylor 2008-11-12 21:09:27 +00:00
parent 536bc24f61
commit f8db7689af
22 changed files with 4661 additions and 7 deletions

109
src/Makefile-tidy.am Normal file
View File

@ -0,0 +1,109 @@
NULL =
GLIB_GENMARSHAL = `pkg-config --variable=glib_genmarshal glib-2.0`
GLIB_MKENUMS = `pkg-config --variable=glib_mkenums glib-2.0`
tidy_cflags = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DG_DISABLE_DEPRECATED \
-DG_LOG_DOMAIN=\"Tidy\" \
$(MUTTER_PLUGIN_CFLAGS) \
$(NULL)
tidy_built_sources = \
tidy-enum-types.h \
tidy-enum-types.c \
tidy-marshal.h \
tidy-marshal.c
BUILT_SOURCES += $(tidy_built_sources)
STAMP_FILES = stamp-tidy-marshal.h stamp-tidy-enum-types.h
# please, keep this sorted alphabetically
tidy_source_h = \
tidy/tidy-actor.h \
tidy/tidy-button.h \
tidy/tidy-frame.h \
tidy/tidy-grid.h \
tidy/tidy-stylable.h \
tidy/tidy-style.h \
tidy/tidy-types.h \
tidy/tidy-util.h \
$(NULL)
tidy_source_h_private = \
tidy/tidy-debug.h \
$(NULL)
# please, keep this sorted alphabetically
tidy_source_c = \
tidy/tidy-actor.c \
tidy/tidy-button.c \
tidy/tidy-frame.c \
tidy/tidy-grid.c \
tidy/tidy-stylable.c \
tidy/tidy-style.c \
tidy/tidy-util.c \
$(NULL)
tidy-marshal.h: stamp-tidy-marshal.h
@true
stamp-tidy-marshal.h: Makefile tidy/tidy-marshal.list
$(GLIB_GENMARSHAL) \
--prefix=_tidy_marshal \
--header \
$(srcdir)/tidy/tidy-marshal.list > xgen-tmh && \
(cmp -s xgen-tmh tidy-marshal.h || cp -f xgen-tmh tidy-marshal.h) && \
rm -f xgen-tmh && \
echo timestamp > $(@F)
tidy-marshal.c: Makefile tidy/tidy-marshal.list
(echo "#include \"tidy-marshal.h\"" ; \
$(GLIB_GENMARSHAL) \
--prefix=_tidy_marshal \
--body \
$(srcdir)/tidy/tidy-marshal.list ) > xgen-tmc && \
cp -f xgen-tmc tidy-marshal.c && \
rm -f xgen-tmc
tidy-enum-types.h: stamp-tidy-enum-types.h Makefile
@true
stamp-tidy-enum-types.h: $(tidy_source_h) tidy/tidy-enum-types.h.in
( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/tidy/tidy-enum-types.h.in \
$(tidy_source_h) ) >> xgen-teth && \
(cmp xgen-teth tidy-enum-types.h || cp xgen-teth tidy-enum-types.h) && \
rm -f xgen-teth && \
echo timestamp > $(@F)
tidy-enum-types.c: stamp-tidy-enum-types.h tidy/tidy-enum-types.c.in
( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/tidy/tidy-enum-types.c.in \
$(tidy_source_h) ) >> xgen-tetc && \
cp xgen-tetc tidy-enum-types.c && \
rm -f xgen-tetc
lib_LTLIBRARIES = libtidy-1.0.la
libtidy_1_0_la_LIBADD = $(TIDY_LIBS)
libtidy_1_0_la_SOURCES = \
$(tidy_source_c) \
$(tidy_source_h) \
$(tidy_source_h_priv) \
$(tidy_built_sources) \
$(NULL)
libtidy_1_0_la_CPPFLAGS = $(tidy_cflags)
libtidy_1_0_la_LDFLAGS = $(LDADD)
CLEANFILES += $(STAMP_FILES) $(BUILT_SOURCES)
EXTRA_DIST = \
tidy/tidy-enum-types.h.in \
tidy/tidy-enum-types.c.in \
tidy/tidy-private.h \
tidy/tidy-marshal.list

View File

@ -1,4 +1,9 @@
INCLUDES = \ BUILT_SOURCES =
CLEANFILES =
include Makefile-tidy.am
gnome_shell_cflags = \
$(MUTTER_PLUGIN_CFLAGS) \ $(MUTTER_PLUGIN_CFLAGS) \
-DGETTEXT_PACKAGE=gnome-shell \ -DGETTEXT_PACKAGE=gnome-shell \
-DJSDIR=\"$(pkgdatadir)/js\" -DJSDIR=\"$(pkgdatadir)/js\"
@ -14,7 +19,8 @@ libgnome_shell_la_SOURCES = \
shell-global.h shell-global.h
libgnome_shell_la_LDFLAGS = -avoid-version -module libgnome_shell_la_LDFLAGS = -avoid-version -module
libgnome_shell_la_LIBADD = $(MUTTER_PLUGIN_LIBS) libgnome_shell_la_LIBADD = $(MUTTER_PLUGIN_LIBS) libtidy-1.0.la
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
# We can't have any undefined symbols when g-ir-scanner dlopens the library # We can't have any undefined symbols when g-ir-scanner dlopens the library
# to introspect it, so we link everything a _second_ time, including a # to introspect it, so we link everything a _second_ time, including a
@ -27,14 +33,15 @@ libgnome_shell_introspect_la_SOURCES = \
# The dummy -rpath here is needed to convince libtool to build a # The dummy -rpath here is needed to convince libtool to build a
# noinst_LTLIBRARY shared # noinst_LTLIBRARY shared
libgnome_shell_introspect_la_LDFLAGS = -avoid-version -module -rpath $(libdir) libgnome_shell_introspect_la_LDFLAGS = -avoid-version -module -rpath $(libdir)
libgnome_shell_introspect_la_LIBADD = $(MUTTER_PLUGIN_LIBS) libgnome_shell_introspect_la_LIBADD = $(MUTTER_PLUGIN_LIBS) libtidy-1.0.la
libgnome_shell_introspect_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)/girepository typelibdir = $(pkglibdir)/girepository
typelib_DATA = Shell-0.1.typelib typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib
# After we run g-ir-scanner, we need to change the library name written in # After we run g-ir-scanner, we need to change the library name written in
# the .gir file from the "fake" second copy of the library to the real name # the .gir file from the "fake" second copy of the library to the real name
Shell-0.1.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES) Shell-0.1.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES) Makefile
g-ir-scanner \ g-ir-scanner \
--namespace=Shell \ --namespace=Shell \
--nsversion=0.1 \ --nsversion=0.1 \
@ -42,8 +49,8 @@ Shell-0.1.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES)
--include=Clutter-0.8 \ --include=Clutter-0.8 \
--include=Meta-2.25 \ --include=Meta-2.25 \
--library=gnome-shell-introspect \ --library=gnome-shell-introspect \
$(libgnome_shell_la_SOURCES) \ - $(libgnome_shell_la_SOURCES) \
$(INCLUDES) \ $(libgnome_shell_la_CPPFLAGS) \
-o $@.tmp -o $@.tmp
sed 's/gnome-shell-introspect/gnome-shell/' < $@.tmp > $@ && rm $@.tmp sed 's/gnome-shell-introspect/gnome-shell/' < $@.tmp > $@ && rm $@.tmp
@ -51,3 +58,23 @@ Shell-0.1.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES)
# (not the fake library, since we've already done the rewriting) # (not the fake library, since we've already done the rewriting)
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Shell-0.1.gir -o $@ LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Shell-0.1.gir -o $@
# After we run g-ir-scanner, we need to change the library name written in
# the .gir file from the "fake" second copy of the library to the real name
Tidy-1.0.gir: libgnome-shell-introspect.la $(libgnome_shell_la_SOURCES) Makefile
g-ir-scanner \
--namespace=Tidy \
--nsversion=1.0 \
--include=GObject-2.0 \
--include=Clutter-0.8 \
--library=gnome-shell-introspect \
$(tidy_source_h) \
$(tidy_source_c) \
$(tidy_cflags) \
-o $@.tmp
sed 's/gnome-shell-introspect/gnome-shell/' < $@.tmp > $@ && rm $@.tmp
# The dependency on libgnome-shell.la here is because g-ir-compiler opens it
# (not the fake library, since we've already done the rewriting)
Tidy-1.0.typelib: libgnome-shell.la Tidy-1.0.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Tidy-1.0.gir -o $@

529
src/tidy/tidy-actor.c Normal file
View File

@ -0,0 +1,529 @@
/* tidy-actor.c: Base class for Tidy actors
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:tidy-actor
* @short_description: Base class for stylable actors
*
* #TidyActor is a simple abstract class on top of #ClutterActor. It
* provides basic themeing properties, support for padding and alignment.
*
* Actors in the Tidy library should subclass #TidyActor if they plan
* to obey to a certain #TidyStyle or if they implement #ClutterContainer
* and want to offer basic layout capabilities.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include "tidy-actor.h"
#include "tidy-debug.h"
#include "tidy-marshal.h"
#include "tidy-private.h"
#include "tidy-stylable.h"
enum
{
PROP_0,
PROP_STYLE,
PROP_PADDING,
PROP_X_ALIGN,
PROP_Y_ALIGN
};
enum
{
LAST_SIGNAL
};
static void tidy_stylable_iface_init (TidyStylableIface *iface);
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (TidyActor, tidy_actor, CLUTTER_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (TIDY_TYPE_STYLABLE,
tidy_stylable_iface_init));
#define TIDY_ACTOR_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_ACTOR, TidyActorPrivate))
struct _TidyActorPrivate
{
TidyStyle *style;
TidyPadding padding;
ClutterFixed x_align;
ClutterFixed y_align;
};
static void
tidy_actor_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
TidyActor *actor = TIDY_ACTOR (gobject);
switch (prop_id)
{
case PROP_PADDING:
tidy_actor_set_padding (actor, g_value_get_boxed (value));
break;
case PROP_X_ALIGN:
actor->priv->x_align =
CLUTTER_FIXED_TO_FLOAT (g_value_get_double (value));
break;
case PROP_Y_ALIGN:
actor->priv->y_align =
CLUTTER_FIXED_TO_FLOAT (g_value_get_double (value));
break;
case PROP_STYLE:
tidy_stylable_set_style (TIDY_STYLABLE (actor),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_actor_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
TidyActor *actor = TIDY_ACTOR (gobject);
TidyActorPrivate *priv = actor->priv;
switch (prop_id)
{
case PROP_PADDING:
{
TidyPadding padding = { 0, };
tidy_actor_get_padding (actor, &padding);
g_value_set_boxed (value, &padding);
}
break;
case PROP_X_ALIGN:
g_value_set_double (value, CLUTTER_FIXED_TO_FLOAT (priv->x_align));
break;
case PROP_Y_ALIGN:
g_value_set_double (value, CLUTTER_FIXED_TO_FLOAT (priv->y_align));
break;
case PROP_STYLE:
g_value_set_object (value, priv->style);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_actor_dispose (GObject *gobject)
{
TidyActor *actor = TIDY_ACTOR (gobject);
if (actor->priv->style)
{
g_object_unref (actor->priv->style);
actor->priv->style = NULL;
}
G_OBJECT_CLASS (tidy_actor_parent_class)->dispose (gobject);
}
static void
tidy_actor_class_init (TidyActorClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (TidyActorPrivate));
gobject_class->set_property = tidy_actor_set_property;
gobject_class->get_property = tidy_actor_get_property;
gobject_class->dispose = tidy_actor_dispose;
/**
* TidyActor:padding:
*
* Padding around an actor, expressed in #ClutterUnit<!-- -->s. Padding
* is the internal space between an actors bounding box and its internal
* children.
*/
g_object_class_install_property (gobject_class,
PROP_PADDING,
g_param_spec_boxed ("padding",
"Padding",
"Units of padding around an actor",
TIDY_TYPE_PADDING,
TIDY_PARAM_READWRITE));
/**
* TidyActor:x-align:
*
* Alignment of internal children along the X axis, relative to the
* actor's bounding box origin, and in relative units (1.0 is the
* current width of the actor).
*
* A value of 0.0 will left-align the children; 0.5 will align them at
* the middle of the actor's width; 1.0 will right align the children.
*/
g_object_class_install_property (gobject_class,
PROP_X_ALIGN,
g_param_spec_double ("x-align",
"X Alignment",
"Alignment (between 0.0 and 1.0) on the X axis",
0.0, 1.0, 0.5,
TIDY_PARAM_READWRITE));
/**
* TidyActor:y-align:
*
* Alignment of internal children along the Y axis, relative to the
* actor's bounding box origin, and in relative units (1.0 is the
* current height of the actor).
*
* A value of 0.0 will top-align the children; 0.5 will align them at
* the middle of the actor's height; 1.0 will bottom align the children.
*/
g_object_class_install_property (gobject_class,
PROP_Y_ALIGN,
g_param_spec_double ("y-align",
"Y Alignement",
"Alignment (between 0.0 and 1.0) on the Y axis",
0.0, 1.0, 0.5,
TIDY_PARAM_READWRITE));
g_object_class_override_property (gobject_class, PROP_STYLE, "style");
}
static TidyStyle *
tidy_actor_get_style (TidyStylable *stylable)
{
TidyActorPrivate *priv = TIDY_ACTOR (stylable)->priv;
if (!priv->style)
priv->style = g_object_ref (tidy_style_get_default ());
return priv->style;
}
static void
tidy_actor_set_style (TidyStylable *stylable,
TidyStyle *style)
{
TidyActorPrivate *priv = TIDY_ACTOR (stylable)->priv;
if (priv->style)
g_object_unref (priv->style);
priv->style = g_object_ref_sink (style);
}
static void
tidy_stylable_iface_init (TidyStylableIface *iface)
{
static gboolean is_initialized = FALSE;
if (!is_initialized)
{
GParamSpec *pspec;
pspec = g_param_spec_string ("font-name",
"Font Name",
"The font to use for displaying text",
"Sans 12px",
G_PARAM_READWRITE);
tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
pspec = g_param_spec_boxed ("bg-color",
"Background Color",
"The background color of an actor",
CLUTTER_TYPE_COLOR,
G_PARAM_READWRITE);
tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
pspec = g_param_spec_boxed ("active-color",
"Active Color",
"The color of an active actor",
CLUTTER_TYPE_COLOR,
G_PARAM_READWRITE);
tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
pspec = g_param_spec_boxed ("text-color",
"Text Color",
"The color of the text of an actor",
CLUTTER_TYPE_COLOR,
G_PARAM_READWRITE);
tidy_stylable_iface_install_property (iface, TIDY_TYPE_ACTOR, pspec);
iface->get_style = tidy_actor_get_style;
iface->set_style = tidy_actor_set_style;
}
}
static void
tidy_actor_init (TidyActor *actor)
{
TidyActorPrivate *priv;
actor->priv = priv = TIDY_ACTOR_GET_PRIVATE (actor);
/* no padding */
priv->padding.top = priv->padding.bottom = 0;
priv->padding.right = priv->padding.left = 0;
/* middle align */
priv->x_align = priv->y_align = CLUTTER_FLOAT_TO_FIXED (0.5);
clutter_actor_set_reactive (CLUTTER_ACTOR (actor), TRUE);
}
/**
* tidy_actor_set_padding:
* @actor: a #TidyActor
* @padding: padding for internal children
*
* Sets @padding around @actor.
*/
void
tidy_actor_set_padding (TidyActor *actor,
const TidyPadding *padding)
{
g_return_if_fail (TIDY_IS_ACTOR (actor));
g_return_if_fail (padding != NULL);
actor->priv->padding = *padding;
g_object_notify (G_OBJECT (actor), "padding");
if (CLUTTER_ACTOR_IS_VISIBLE (actor))
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
}
/**
* tidy_actor_get_padding:
* @actor: a #TidyActor
* @padding: return location for the padding
*
* Retrieves the padding aound @actor.
*/
void
tidy_actor_get_padding (TidyActor *actor,
TidyPadding *padding)
{
g_return_if_fail (TIDY_IS_ACTOR (actor));
g_return_if_fail (padding != NULL);
*padding = actor->priv->padding;
}
/**
* tidy_actor_set_alignment:
* @actor: a #TidyActor
* @x_align: relative alignment on the X axis
* @y_align: relative alignment on the Y axis
*
* Sets the alignment, relative to the @actor's width and height, of
* the internal children.
*/
void
tidy_actor_set_alignment (TidyActor *actor,
gdouble x_align,
gdouble y_align)
{
TidyActorPrivate *priv;
g_return_if_fail (TIDY_IS_ACTOR (actor));
g_object_ref (actor);
g_object_freeze_notify (G_OBJECT (actor));
priv = actor->priv;
x_align = CLAMP (x_align, 0.0, 1.0);
y_align = CLAMP (y_align, 0.0, 1.0);
priv->x_align = CLUTTER_FLOAT_TO_FIXED (x_align);
g_object_notify (G_OBJECT (actor), "x-align");
priv->y_align = CLUTTER_FLOAT_TO_FIXED (y_align);
g_object_notify (G_OBJECT (actor), "y-align");
if (CLUTTER_ACTOR_IS_VISIBLE (actor))
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
g_object_thaw_notify (G_OBJECT (actor));
g_object_unref (actor);
}
/**
* tidy_actor_get_alignment:
* @actor: a #TidyActor
* @x_align: return location for the relative alignment on the X axis,
* or %NULL
* @y_align: return location for the relative alignment on the Y axis,
* or %NULL
*
* Retrieves the alignment, relative to the @actor's width and height, of
* the internal children.
*/
void
tidy_actor_get_alignment (TidyActor *actor,
gdouble *x_align,
gdouble *y_align)
{
TidyActorPrivate *priv;
g_return_if_fail (TIDY_IS_ACTOR (actor));
priv = actor->priv;
if (x_align)
*x_align = CLUTTER_FIXED_TO_FLOAT (priv->x_align);
if (y_align)
*y_align = CLUTTER_FIXED_TO_FLOAT (priv->y_align);
}
/**
* tidy_actor_set_alignmentx:
* @actor: a #TidyActor
* @x_align: relative alignment on the X axis
* @y_align: relative alignment on the Y axis
*
* Fixed point version of tidy_actor_set_alignment().
*
* Sets the alignment, relative to the @actor's width and height, of
* the internal children.
*/
void
tidy_actor_set_alignmentx (TidyActor *actor,
ClutterFixed x_align,
ClutterFixed y_align)
{
TidyActorPrivate *priv;
g_return_if_fail (TIDY_IS_ACTOR (actor));
g_object_ref (actor);
g_object_freeze_notify (G_OBJECT (actor));
priv = actor->priv;
x_align = CLAMP (x_align, 0, CFX_ONE);
y_align = CLAMP (y_align, 0, CFX_ONE);
if (priv->x_align != x_align)
{
priv->x_align = x_align;
g_object_notify (G_OBJECT (actor), "x-align");
}
if (priv->y_align != y_align)
{
priv->y_align = y_align;
g_object_notify (G_OBJECT (actor), "y-align");
}
if (CLUTTER_ACTOR_IS_VISIBLE (actor))
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
g_object_thaw_notify (G_OBJECT (actor));
g_object_unref (actor);
}
/**
* tidy_actor_get_alignmentx:
* @actor: a #TidyActor
* @x_align: return location for the relative alignment on the X axis,
* or %NULL
* @y_align: return location for the relative alignment on the Y axis,
* or %NULL
*
* Fixed point version of tidy_actor_get_alignment().
*
* Retrieves the alignment, relative to the @actor's width and height, of
* the internal children.
*/
void
tidy_actor_get_alignmentx (TidyActor *actor,
ClutterFixed *x_align,
ClutterFixed *y_align)
{
TidyActorPrivate *priv;
g_return_if_fail (TIDY_IS_ACTOR (actor));
priv = actor->priv;
if (x_align)
*x_align = priv->x_align;
if (y_align)
*y_align = priv->y_align;
}
static TidyPadding *
tidy_padding_copy (const TidyPadding *padding)
{
TidyPadding *copy;
g_return_val_if_fail (padding != NULL, NULL);
copy = g_slice_new (TidyPadding);
*copy = *padding;
return copy;
}
static void
tidy_padding_free (TidyPadding *padding)
{
if (G_LIKELY (padding))
g_slice_free (TidyPadding, padding);
}
GType
tidy_padding_get_type (void)
{
static GType our_type = 0;
if (G_UNLIKELY (our_type == 0))
our_type =
g_boxed_type_register_static (I_("TidyPadding"),
(GBoxedCopyFunc) tidy_padding_copy,
(GBoxedFreeFunc) tidy_padding_free);
return our_type;
}

88
src/tidy/tidy-actor.h Normal file
View File

@ -0,0 +1,88 @@
/* tidy-actor.h: Base class for Tidy actors
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __TIDY_ACTOR_H__
#define __TIDY_ACTOR_H__
#include <clutter/clutter-actor.h>
#include <tidy/tidy-types.h>
G_BEGIN_DECLS
#define TIDY_TYPE_ACTOR (tidy_actor_get_type ())
#define TIDY_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_ACTOR, TidyActor))
#define TIDY_IS_ACTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_ACTOR))
#define TIDY_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_ACTOR, TidyActorClass))
#define TIDY_IS_ACTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_ACTOR))
#define TIDY_ACTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_ACTOR, TidyActorClass))
typedef struct _TidyActor TidyActor;
typedef struct _TidyActorPrivate TidyActorPrivate;
typedef struct _TidyActorClass TidyActorClass;
/**
* TidyActor:
*
* Base class for stylable actors. The contents of the #TidyActor
* structure are private and should only be accessed through the
* public API.
*/
struct _TidyActor
{
/*< private >*/
ClutterActor parent_instance;
TidyActorPrivate *priv;
};
/**
* TidyActorClass:
*
* Base class for stylable actors.
*/
struct _TidyActorClass
{
/*< private >*/
ClutterActorClass parent_class;
};
GType tidy_actor_get_type (void) G_GNUC_CONST;
void tidy_actor_set_padding (TidyActor *actor,
const TidyPadding *padding);
void tidy_actor_get_padding (TidyActor *actor,
TidyPadding *padding);
void tidy_actor_set_alignment (TidyActor *actor,
gdouble x_align,
gdouble y_align);
void tidy_actor_get_alignment (TidyActor *actor,
gdouble *x_align,
gdouble *y_align);
void tidy_actor_set_alignmentx (TidyActor *actor,
ClutterFixed x_align,
ClutterFixed y_align);
void tidy_actor_get_alignmentx (TidyActor *actor,
ClutterFixed *x_align,
ClutterFixed *y_align);
G_END_DECLS
#endif /* __TIDY_ACTOR_H__ */

374
src/tidy/tidy-button.c Normal file
View File

@ -0,0 +1,374 @@
/* tidy-button.c: Plain button actor
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "tidy-button.h"
#include "tidy-debug.h"
#include "tidy-marshal.h"
#include "tidy-stylable.h"
enum
{
PROP_0,
PROP_LABEL
};
enum
{
CLICKED,
LAST_SIGNAL
};
#define TIDY_BUTTON_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_BUTTON, TidyButtonPrivate))
struct _TidyButtonPrivate
{
gchar *text;
ClutterTimeline *timeline;
ClutterEffectTemplate *press_tmpl;
guint8 old_opacity;
guint is_pressed : 1;
};
static guint button_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE (TidyButton, tidy_button, TIDY_TYPE_FRAME);
static void
tidy_button_real_pressed (TidyButton *button)
{
TidyButtonPrivate *priv = button->priv;
ClutterActor *actor = CLUTTER_ACTOR (button);
if (G_UNLIKELY (!priv->press_tmpl))
{
priv->timeline = clutter_timeline_new_for_duration (250);
priv->press_tmpl = clutter_effect_template_new (priv->timeline,
clutter_sine_inc_func);
clutter_effect_template_set_timeline_clone (priv->press_tmpl, FALSE);
}
if (clutter_timeline_is_playing (priv->timeline))
{
clutter_timeline_stop (priv->timeline);
clutter_actor_set_opacity (actor, priv->old_opacity);
}
priv->old_opacity = clutter_actor_get_opacity (actor);
clutter_effect_fade (priv->press_tmpl, actor,
0x44,
NULL, NULL);
}
static void
tidy_button_real_released (TidyButton *button)
{
TidyButtonPrivate *priv = button->priv;
ClutterActor *actor = CLUTTER_ACTOR (button);
if (G_UNLIKELY (!priv->press_tmpl))
{
priv->timeline = clutter_timeline_new_for_duration (250);
priv->press_tmpl = clutter_effect_template_new (priv->timeline,
clutter_sine_inc_func);
clutter_effect_template_set_timeline_clone (priv->press_tmpl, FALSE);
}
if (clutter_timeline_is_playing (priv->timeline))
clutter_timeline_stop (priv->timeline);
clutter_effect_fade (priv->press_tmpl, actor,
priv->old_opacity,
NULL, NULL);
}
static void
tidy_button_construct_child (TidyButton *button)
{
TidyButtonPrivate *priv = button->priv;
gchar *font_name;
ClutterColor *text_color;
ClutterActor *label;
if (!priv->text)
return;
tidy_stylable_get (TIDY_STYLABLE (button),
"font-name", &font_name,
"text-color", &text_color,
NULL);
label = g_object_new (CLUTTER_TYPE_LABEL,
"font-name", font_name,
"text", priv->text,
"color", text_color,
"alignment", PANGO_ALIGN_CENTER,
"ellipsize", PANGO_ELLIPSIZE_MIDDLE,
"use-markup", TRUE,
"wrap", FALSE,
NULL);
clutter_actor_show (label);
clutter_container_add_actor (CLUTTER_CONTAINER (button), label);
clutter_color_free (text_color);
g_free (font_name);
}
static gboolean
tidy_button_button_press (ClutterActor *actor,
ClutterButtonEvent *event)
{
if (event->button == 1 &&
event->click_count == 1)
{
TidyButton *button = TIDY_BUTTON (actor);
TidyButtonClass *klass = TIDY_BUTTON_GET_CLASS (button);
button->priv->is_pressed = TRUE;
clutter_grab_pointer (actor);
if (klass->pressed)
klass->pressed (button);
return TRUE;
}
return FALSE;
}
static gboolean
tidy_button_button_release (ClutterActor *actor,
ClutterButtonEvent *event)
{
if (event->button == 1)
{
TidyButton *button = TIDY_BUTTON (actor);
TidyButtonClass *klass = TIDY_BUTTON_GET_CLASS (button);
if (!button->priv->is_pressed)
return FALSE;
clutter_ungrab_pointer ();
button->priv->is_pressed = FALSE;
if (klass->released)
klass->released (button);
g_signal_emit (button, button_signals[CLICKED], 0);
return TRUE;
}
return FALSE;
}
static gboolean
tidy_button_leave (ClutterActor *actor,
ClutterCrossingEvent *event)
{
TidyButton *button = TIDY_BUTTON (actor);
if (button->priv->is_pressed)
{
TidyButtonClass *klass = TIDY_BUTTON_GET_CLASS (button);
clutter_ungrab_pointer ();
button->priv->is_pressed = FALSE;
if (klass->released)
klass->released (button);
}
return FALSE;
}
static void
tidy_button_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
TidyButton *button = TIDY_BUTTON (gobject);
switch (prop_id)
{
case PROP_LABEL:
tidy_button_set_label (button, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_button_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
TidyButtonPrivate *priv = TIDY_BUTTON (gobject)->priv;
switch (prop_id)
{
case PROP_LABEL:
g_value_set_string (value, priv->text);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_button_finalize (GObject *gobject)
{
TidyButtonPrivate *priv = TIDY_BUTTON (gobject)->priv;
g_free (priv->text);
G_OBJECT_CLASS (tidy_button_parent_class)->finalize (gobject);
}
static void
tidy_button_dispose (GObject *gobject)
{
TidyButtonPrivate *priv = TIDY_BUTTON (gobject)->priv;
if (priv->press_tmpl)
{
g_object_unref (priv->press_tmpl);
g_object_unref (priv->timeline);
priv->press_tmpl = NULL;
priv->timeline = NULL;
}
G_OBJECT_CLASS (tidy_button_parent_class)->dispose (gobject);
}
static void
tidy_button_class_init (TidyButtonClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
g_type_class_add_private (klass, sizeof (TidyButtonPrivate));
klass->pressed = tidy_button_real_pressed;
klass->released = tidy_button_real_released;
gobject_class->set_property = tidy_button_set_property;
gobject_class->get_property = tidy_button_get_property;
gobject_class->dispose = tidy_button_dispose;
gobject_class->finalize = tidy_button_finalize;
actor_class->button_press_event = tidy_button_button_press;
actor_class->button_release_event = tidy_button_button_release;
actor_class->leave_event = tidy_button_leave;
g_object_class_install_property (gobject_class,
PROP_LABEL,
g_param_spec_string ("label",
"Label",
"Label of the button",
NULL,
G_PARAM_READWRITE));
button_signals[CLICKED] =
g_signal_new ("clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (TidyButtonClass, clicked),
NULL, NULL,
_tidy_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
tidy_button_init (TidyButton *button)
{
button->priv = TIDY_BUTTON_GET_PRIVATE (button);
}
ClutterActor *
tidy_button_new (void)
{
return g_object_new (TIDY_TYPE_BUTTON, NULL);
}
ClutterActor *
tidy_button_new_with_label (const gchar *text)
{
return g_object_new (TIDY_TYPE_BUTTON, "label", text, NULL);
}
G_CONST_RETURN gchar *
tidy_button_get_label (TidyButton *button)
{
g_return_val_if_fail (TIDY_IS_BUTTON (button), NULL);
return button->priv->text;
}
void
tidy_button_set_label (TidyButton *button,
const gchar *text)
{
TidyButtonPrivate *priv;
g_return_if_fail (TIDY_IS_BUTTON (button));
priv = button->priv;
g_free (priv->text);
priv->text = g_strdup (text);
tidy_button_construct_child (button);
g_object_notify (G_OBJECT (button), "label");
}

70
src/tidy/tidy-button.h Normal file
View File

@ -0,0 +1,70 @@
/* tidy-button.h: Plain button actor
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
*/
#ifndef __TIDY_BUTTON_H__
#define __TIDY_BUTTON_H__
#include <tidy/tidy-frame.h>
G_BEGIN_DECLS
#define TIDY_TYPE_BUTTON (tidy_button_get_type ())
#define TIDY_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_BUTTON, TidyButton))
#define TIDY_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_BUTTON))
#define TIDY_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_BUTTON, TidyButtonClass))
#define TIDY_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_BUTTON))
#define TIDY_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_BUTTON, TidyButtonClass))
typedef struct _TidyButton TidyButton;
typedef struct _TidyButtonPrivate TidyButtonPrivate;
typedef struct _TidyButtonClass TidyButtonClass;
struct _TidyButton
{
TidyFrame parent_instance;
TidyButtonPrivate *priv;
};
struct _TidyButtonClass
{
TidyFrameClass parent_class;
/* vfuncs, not signals */
void (* pressed) (TidyButton *button);
void (* released) (TidyButton *button);
/* signals */
void (* clicked) (TidyButton *button);
};
GType tidy_button_get_type (void) G_GNUC_CONST;
ClutterActor * tidy_button_new (void);
ClutterActor * tidy_button_new_with_label (const gchar *text);
G_CONST_RETURN gchar *tidy_button_get_label (TidyButton *button);
void tidy_button_set_label (TidyButton *button,
const gchar *text);
G_END_DECLS
#endif /* __TIDY_BUTTON_H__ */

4
src/tidy/tidy-debug.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef __TIDY_DEBUG_H__
#define __TIDY_DEBUG_H__
#endif /* __TIDY_DEBUG_H__ */

View File

@ -0,0 +1,30 @@
/*** BEGIN file-header ***/
#include "tidy-enum-types.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
#include "@filename@"
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type(void) {
static GType enum_type_id = 0;
if (G_UNLIKELY (!enum_type_id))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
enum_type_id = g_@type@_register_static("@EnumName@", values);
}
return enum_type_id;
}
/*** END value-tail ***/

View File

@ -0,0 +1,25 @@
/*** BEGIN file-header ***/
#ifndef __TIDY_ENUM_TYPES_H__
#define __TIDY_ENUM_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
/*** END file-production ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* !__TIDY_ENUM_TYPES_H__ */
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define TIDY_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/

515
src/tidy/tidy-frame.c Normal file
View File

@ -0,0 +1,515 @@
/* tidy-frame.c: Simple container with a background
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <glib-object.h>
#include <cogl/cogl.h>
#include <clutter/clutter.h>
#include "tidy-frame.h"
#include "tidy-private.h"
#include "tidy-stylable.h"
#define TIDY_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_FRAME, TidyFramePrivate))
enum
{
PROP_0,
PROP_CHILD,
PROP_TEXTURE
};
struct _TidyFramePrivate
{
ClutterActor *child;
ClutterActor *texture;
};
static ClutterColor default_bg_color = { 0xcc, 0xcc, 0xcc, 0xff };
static void clutter_container_iface_init (ClutterContainerIface *iface);
G_DEFINE_TYPE_WITH_CODE (TidyFrame, tidy_frame, TIDY_TYPE_ACTOR,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
clutter_container_iface_init));
static void
tidy_frame_get_preferred_width (ClutterActor *actor,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
TidyPadding padding = { 0, };
ClutterUnit min_width, natural_width;
tidy_actor_get_padding (TIDY_ACTOR (actor), &padding);
min_width = 0;
natural_width = padding.left + padding.right;
if (priv->child)
{
ClutterUnit child_min, child_natural;
clutter_actor_get_preferred_width (priv->child, for_height,
&child_min,
&child_natural);
min_width += child_min;
natural_width += child_natural;
}
if (min_width_p)
*min_width_p = min_width;
if (natural_width_p)
*natural_width_p = natural_width;
}
static void
tidy_frame_get_preferred_height (ClutterActor *actor,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
TidyPadding padding = { 0, };
ClutterUnit min_height, natural_height;
tidy_actor_get_padding (TIDY_ACTOR (actor), &padding);
min_height = 0;
natural_height = padding.top + padding.bottom;
if (priv->child)
{
ClutterUnit child_min, child_natural;
clutter_actor_get_preferred_height (priv->child, for_width,
&child_min,
&child_natural);
min_height += child_min;
natural_height += child_natural;
}
if (min_height_p)
*min_height_p = min_height;
if (natural_height_p)
*natural_height_p = natural_height;
}
static void
tidy_frame_allocate (ClutterActor *actor,
const ClutterActorBox *box,
gboolean origin_changed)
{
TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
ClutterActorClass *klass;
klass = CLUTTER_ACTOR_CLASS (tidy_frame_parent_class);
klass->allocate (actor, box, origin_changed);
if (priv->texture)
{
ClutterActorBox texture_box = { 0, };
texture_box.x1 = 0;
texture_box.y1 = 0;
texture_box.x2 = box->x2 - box->x1;
texture_box.y2 = box->y2 - box->y1;
clutter_actor_allocate (priv->texture, &texture_box, origin_changed);
}
if (priv->child)
{
TidyPadding padding = { 0, };
ClutterFixed x_align, y_align;
ClutterUnit available_width, available_height;
ClutterUnit child_width, child_height;
ClutterActorBox child_box = { 0, };
tidy_actor_get_padding (TIDY_ACTOR (actor), &padding);
tidy_actor_get_alignmentx (TIDY_ACTOR (actor), &x_align, &y_align);
available_width = box->x2 - box->x1
- padding.left
- padding.right;
available_height = box->y2 - box->y1
- padding.top
- padding.bottom;
if (available_width < 0)
available_width = 0;
if (available_height < 0)
available_height = 0;
clutter_actor_get_preferred_size (priv->child,
NULL, NULL,
&child_width,
&child_height);
if (child_width > available_width)
child_width = available_width;
if (child_height > available_height)
child_height = available_height;
child_box.x1 = CLUTTER_FIXED_MUL ((available_width - child_width),
x_align)
+ padding.left;
child_box.y1 = CLUTTER_FIXED_MUL ((available_height - child_height),
y_align)
+ padding.top;
child_box.x2 = child_box.x1 + child_width;
child_box.y2 = child_box.y1 + child_height;
clutter_actor_allocate (priv->child, &child_box, origin_changed);
}
}
static void
tidy_frame_paint (ClutterActor *actor)
{
TidyFrame *frame = TIDY_FRAME (actor);
TidyFramePrivate *priv = frame->priv;
cogl_push_matrix ();
if (priv->texture)
clutter_actor_paint (priv->texture);
else
{
ClutterActorBox allocation = { 0, };
ClutterColor *bg_color;
guint w, h;
tidy_stylable_get (TIDY_STYLABLE (frame), "bg-color", &bg_color, NULL);
if (!bg_color)
bg_color = &default_bg_color;
bg_color->alpha = clutter_actor_get_paint_opacity (actor)
* bg_color->alpha
/ 255;
clutter_actor_get_allocation_box (actor, &allocation);
w = CLUTTER_UNITS_TO_DEVICE (allocation.x2 - allocation.x1);
h = CLUTTER_UNITS_TO_DEVICE (allocation.y2 - allocation.y1);
cogl_color (bg_color);
cogl_rectangle (0, 0, w, h);
if (bg_color != &default_bg_color)
clutter_color_free (bg_color);
}
if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
clutter_actor_paint (priv->child);
cogl_pop_matrix ();
}
static void
tidy_frame_pick (ClutterActor *actor,
const ClutterColor *pick_color)
{
TidyFramePrivate *priv = TIDY_FRAME (actor)->priv;
/* chain up, so we get a box with our coordinates */
CLUTTER_ACTOR_CLASS (tidy_frame_parent_class)->pick (actor, pick_color);
if (priv->child && CLUTTER_ACTOR_IS_VISIBLE (priv->child))
clutter_actor_paint (priv->child);
}
static void
tidy_frame_dispose (GObject *gobject)
{
TidyFramePrivate *priv = TIDY_FRAME (gobject)->priv;
if (priv->child)
{
clutter_actor_unparent (priv->child);
priv->child = NULL;
}
if (priv->texture)
{
clutter_actor_unparent (priv->texture);
priv->texture = NULL;
}
G_OBJECT_CLASS (tidy_frame_parent_class)->dispose (gobject);
}
static void
tidy_frame_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
case PROP_CHILD:
clutter_container_add_actor (CLUTTER_CONTAINER (gobject),
g_value_get_object (value));
break;
case PROP_TEXTURE:
tidy_frame_set_texture (TIDY_FRAME (gobject),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_frame_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
TidyFramePrivate *priv = TIDY_FRAME (gobject)->priv;
switch (prop_id)
{
case PROP_CHILD:
g_value_set_object (value, priv->child);
break;
case PROP_TEXTURE:
g_value_set_object (value, priv->texture);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
tidy_frame_class_init (TidyFrameClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
g_type_class_add_private (klass, sizeof (TidyFramePrivate));
gobject_class->set_property = tidy_frame_set_property;
gobject_class->get_property = tidy_frame_get_property;
gobject_class->dispose = tidy_frame_dispose;
actor_class->pick = tidy_frame_pick;
actor_class->paint = tidy_frame_paint;
actor_class->allocate = tidy_frame_allocate;
actor_class->get_preferred_width = tidy_frame_get_preferred_width;
actor_class->get_preferred_height = tidy_frame_get_preferred_height;
g_object_class_install_property (gobject_class,
PROP_CHILD,
g_param_spec_object ("child",
"Child",
"The child of the frame",
CLUTTER_TYPE_ACTOR,
TIDY_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_TEXTURE,
g_param_spec_object ("texture",
"Texture",
"The background texture of the frame",
CLUTTER_TYPE_ACTOR,
TIDY_PARAM_READWRITE));
}
static void
tidy_frame_init (TidyFrame *frame)
{
frame->priv = TIDY_FRAME_GET_PRIVATE (frame);
}
static void
tidy_frame_add_actor (ClutterContainer *container,
ClutterActor *actor)
{
TidyFramePrivate *priv = TIDY_FRAME (container)->priv;
if (priv->child)
clutter_actor_unparent (priv->child);
clutter_actor_set_parent (actor, CLUTTER_ACTOR (container));
priv->child = actor;
clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
g_signal_emit_by_name (container, "actor-added", actor);
g_object_notify (G_OBJECT (container), "child");
}
static void
tidy_frame_remove_actor (ClutterContainer *container,
ClutterActor *actor)
{
TidyFramePrivate *priv = TIDY_FRAME (container)->priv;
if (priv->child == actor)
{
g_object_ref (priv->child);
clutter_actor_unparent (priv->child);
priv->child = NULL;
clutter_actor_queue_relayout (CLUTTER_ACTOR (container));
g_signal_emit_by_name (container, "actor-removed", priv->child);
g_object_unref (priv->child);
}
}
static void
tidy_frame_foreach (ClutterContainer *container,
ClutterCallback callback,
gpointer callback_data)
{
TidyFramePrivate *priv = TIDY_FRAME (container)->priv;
if (priv->texture)
callback (priv->texture, callback_data);
if (priv->child)
callback (priv->child, callback_data);
}
static void
tidy_frame_lower (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
/* single child */
}
static void
tidy_frame_raise (ClutterContainer *container,
ClutterActor *actor,
ClutterActor *sibling)
{
/* single child */
}
static void
tidy_frame_sort_depth_order (ClutterContainer *container)
{
/* single child */
}
static void
clutter_container_iface_init (ClutterContainerIface *iface)
{
iface->add = tidy_frame_add_actor;
iface->remove = tidy_frame_remove_actor;
iface->foreach = tidy_frame_foreach;
iface->lower = tidy_frame_lower;
iface->raise = tidy_frame_raise;
iface->sort_depth_order = tidy_frame_sort_depth_order;
}
ClutterActor *
tidy_frame_new (void)
{
return g_object_new (TIDY_TYPE_FRAME, NULL);
}
ClutterActor *
tidy_frame_get_child (TidyFrame *frame)
{
g_return_val_if_fail (TIDY_IS_FRAME (frame), NULL);
return frame->priv->child;
}
void
tidy_frame_set_texture (TidyFrame *frame,
ClutterActor *texture)
{
TidyFramePrivate *priv;
g_return_if_fail (TIDY_IS_FRAME (frame));
g_return_if_fail (CLUTTER_IS_ACTOR (texture));
priv = frame->priv;
if (priv->texture == texture)
return;
if (priv->texture)
{
clutter_actor_unparent (priv->texture);
priv->texture = NULL;
}
if (texture)
{
ClutterActor *parent = clutter_actor_get_parent (texture);
if (G_UNLIKELY (parent != NULL))
{
g_warning ("Unable to set the background texture of type `%s' for "
"the frame of type `%s': the texture actor is already "
"a child of a container of type `%s'",
g_type_name (G_OBJECT_TYPE (texture)),
g_type_name (G_OBJECT_TYPE (frame)),
g_type_name (G_OBJECT_TYPE (parent)));
return;
}
priv->texture = texture;
clutter_actor_set_parent (texture, CLUTTER_ACTOR (frame));
}
clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
g_object_notify (G_OBJECT (frame), "texture");
}
ClutterActor *
tidy_frame_get_texture (TidyFrame *frame)
{
g_return_val_if_fail (TIDY_IS_FRAME (frame), NULL);
return frame->priv->texture;
}

64
src/tidy/tidy-frame.h Normal file
View File

@ -0,0 +1,64 @@
/* tidy-frame.h: Simple container with a background
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
*/
#ifndef __TIDY_FRAME_H__
#define __TIDY_FRAME_H__
#include <clutter/clutter-actor.h>
#include <tidy/tidy-actor.h>
G_BEGIN_DECLS
#define TIDY_TYPE_FRAME (tidy_frame_get_type ())
#define TIDY_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_FRAME, TidyFrame))
#define TIDY_IS_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_FRAME))
#define TIDY_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_FRAME, TidyFrameClass))
#define TIDY_IS_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_FRAME))
#define TIDY_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_FRAME, TidyFrameClass))
typedef struct _TidyFrame TidyFrame;
typedef struct _TidyFramePrivate TidyFramePrivate;
typedef struct _TidyFrameClass TidyFrameClass;
struct _TidyFrame
{
TidyActor parent_instance;
TidyFramePrivate *priv;
};
struct _TidyFrameClass
{
TidyActorClass parent_class;
};
GType tidy_frame_get_type (void) G_GNUC_CONST;
ClutterActor *tidy_frame_new (void);
ClutterActor *tidy_frame_get_child (TidyFrame *frame);
void tidy_frame_set_texture (TidyFrame *frame,
ClutterActor *actor);
ClutterActor *tidy_frame_get_texture (TidyFrame *frame);
G_END_DECLS
#endif /* __TIDY_FRAME_H__ */

1005
src/tidy/tidy-grid.c Normal file

File diff suppressed because it is too large Load Diff

99
src/tidy/tidy-grid.h Normal file
View File

@ -0,0 +1,99 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2008 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __TIDY_GRID_H__
#define __TIDY_GRID_H__
#include <clutter/clutter-actor.h>
G_BEGIN_DECLS
#define TIDY_TYPE_GRID (tidy_grid_get_type())
#define TIDY_GRID(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
TIDY_TYPE_GRID, \
TidyGrid))
#define TIDY_GRID_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
TIDY_TYPE_GRID, \
TidyGridClass))
#define TIDY_IS_GRID(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
TIDY_TYPE_GRID))
#define TIDY_IS_GRID_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
TIDY_TYPE_GRID))
#define TIDY_GRID_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
TIDY_TYPE_GRID, \
TidyGridClass))
typedef struct _TidyGrid TidyGrid;
typedef struct _TidyGridClass TidyGridClass;
typedef struct _TidyGridPrivate TidyGridPrivate;
struct _TidyGridClass
{
ClutterActorClass parent_class;
};
struct _TidyGrid
{
ClutterActor parent;
TidyGridPrivate *priv;
};
GType tidy_grid_get_type (void) G_GNUC_CONST;
ClutterActor *tidy_grid_new (void);
void tidy_grid_set_end_align (TidyGrid *self,
gboolean value);
gboolean tidy_grid_get_end_align (TidyGrid *self);
void tidy_grid_set_homogenous_rows (TidyGrid *self,
gboolean value);
gboolean tidy_grid_get_homogenous_rows (TidyGrid *self);
void tidy_grid_set_homogenous_columns (TidyGrid *self,
gboolean value);
gboolean tidy_grid_get_homogenous_columns (TidyGrid *self);
void tidy_grid_set_column_major (TidyGrid *self,
gboolean value);
gboolean tidy_grid_get_column_major (TidyGrid *self);
void tidy_grid_set_row_gap (TidyGrid *self,
ClutterUnit value);
ClutterUnit tidy_grid_get_row_gap (TidyGrid *self);
void tidy_grid_set_column_gap (TidyGrid *self,
ClutterUnit value);
ClutterUnit tidy_grid_get_column_gap (TidyGrid *self);
void tidy_grid_set_valign (TidyGrid *self,
gdouble value);
gdouble tidy_grid_get_valign (TidyGrid *self);
void tidy_grid_set_halign (TidyGrid *self,
gdouble value);
gdouble tidy_grid_get_halign (TidyGrid *self);
G_END_DECLS
#endif /* __TIDY_GRID_H__ */

View File

@ -0,0 +1,8 @@
VOID:OBJECT
VOID:VOID
VOID:PARAM
VOID:POINTER
VOID:UINT
VOID:UINT,UINT
VOID:OBJECT,OBJECT
VOID:STRING,OBJECT

40
src/tidy/tidy-private.h Normal file
View File

@ -0,0 +1,40 @@
/* tidy-private.h: Private declarations
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __TIDY_PRIVATE_H__
#define __TIDY_PRIVATE_H__
#include <glib.h>
G_BEGIN_DECLS
#define I_(str) (g_intern_static_string ((str)))
#define TIDY_PARAM_READABLE \
(G_PARAM_READABLE | \
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
#define TIDY_PARAM_READWRITE \
(G_PARAM_READABLE | G_PARAM_WRITABLE | \
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
G_END_DECLS
#endif /* __TIDY_PRIVATE_H__ */

789
src/tidy/tidy-stylable.c Normal file
View File

@ -0,0 +1,789 @@
/* tidy-stylable.c: Interface for stylable objects
*/
/**
* SECTION:tidy-stylable
* @short_description: Interface for stylable objects
*
* Stylable objects are classes that can have "style properties", that is
* properties that can be changed by attaching a #TidyStyle to them.
*
* Objects can choose to subclass #TidyActor, and thus inherit all the
* #TidyActor style properties; or they can subclass #TidyActor and
* reimplement the #TidyStylable interface to add new style properties
* specific for them (and their subclasses); or, finally, they can simply
* subclass #GObject and implement #TidyStylable to install new properties.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#include <gobject/gobjectnotifyqueue.c>
#include "tidy-marshal.h"
#include "tidy-private.h"
#include "tidy-stylable.h"
enum
{
STYLE_SET,
STYLE_NOTIFY,
LAST_SIGNAL
};
static GObjectNotifyContext property_notify_context = { 0, };
static GParamSpecPool *style_property_spec_pool = NULL;
static GQuark quark_real_owner = 0;
static GQuark quark_style = 0;
static guint stylable_signals[LAST_SIGNAL] = { 0, };
static void
tidy_stylable_notify_dispatcher (GObject *gobject,
guint n_pspecs,
GParamSpec **pspecs)
{
guint i;
for (i = 0; i < n_pspecs; i++)
g_signal_emit (gobject, stylable_signals[STYLE_NOTIFY],
g_quark_from_string (pspecs[i]->name),
pspecs[i]);
}
static void
tidy_stylable_base_finalize (gpointer g_iface)
{
GList *list, *node;
list = g_param_spec_pool_list_owned (style_property_spec_pool,
G_TYPE_FROM_INTERFACE (g_iface));
for (node = list; node; node = node->next)
{
GParamSpec *pspec = node->data;
g_param_spec_pool_remove (style_property_spec_pool, pspec);
g_param_spec_unref (pspec);
}
g_list_free (list);
}
static void
tidy_stylable_base_init (gpointer g_iface)
{
static gboolean initialised = FALSE;
if (G_UNLIKELY (!initialised))
{
GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
initialised = TRUE;
quark_real_owner = g_quark_from_static_string ("tidy-stylable-real-owner-quark");
quark_style = g_quark_from_static_string ("tidy-stylable-style-quark");
style_property_spec_pool = g_param_spec_pool_new (FALSE);
property_notify_context.quark_notify_queue = g_quark_from_static_string ("TidyStylable-style-property-notify-queue");
property_notify_context.dispatcher = tidy_stylable_notify_dispatcher;
/**
* TidyStylable:style:
*
* The #TidyStyle attached to a stylable object.
*/
g_object_interface_install_property (g_iface,
g_param_spec_object ("style",
"Style",
"A style object",
TIDY_TYPE_STYLE,
TIDY_PARAM_READWRITE));
/**
* TidyStylable::style-set:
* @stylable: the #TidyStylable that received the signal
* @old_style: the previously set #TidyStyle for @stylable
*
* The ::style-set signal is emitted each time the #TidyStyle attached
* to @stylable has been changed.
*/
stylable_signals[STYLE_SET] =
g_signal_new (I_("style-set"),
iface_type,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (TidyStylableIface, style_set),
NULL, NULL,
_tidy_marshal_VOID__OBJECT,
G_TYPE_NONE, 1,
TIDY_TYPE_STYLE);
stylable_signals[STYLE_NOTIFY] =
g_signal_new (I_("style-notify"),
iface_type,
G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (TidyStylableIface, style_notify),
NULL, NULL,
_tidy_marshal_VOID__PARAM,
G_TYPE_NONE, 1,
G_TYPE_PARAM);
}
}
GType
tidy_stylable_get_type (void)
{
static GType our_type = 0;
if (G_UNLIKELY (our_type == 0))
{
GTypeInfo stylable_info = {
sizeof (TidyStylableIface),
tidy_stylable_base_init,
tidy_stylable_base_finalize
};
our_type = g_type_register_static (G_TYPE_INTERFACE,
I_("TidyStylable"),
&stylable_info, 0);
}
return our_type;
}
void
tidy_stylable_freeze_notify (TidyStylable *stylable)
{
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_object_ref (stylable);
g_object_notify_queue_freeze (G_OBJECT (stylable), &property_notify_context);
g_object_unref (stylable);
}
void
tidy_stylable_thaw_notify (TidyStylable *stylable)
{
GObjectNotifyQueue *nqueue;
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_object_ref (stylable);
nqueue = g_object_notify_queue_from_object (G_OBJECT (stylable),
&property_notify_context);
if (!nqueue || !nqueue->freeze_count)
g_warning ("%s: property-changed notification for %s(%p) is not frozen",
G_STRFUNC, G_OBJECT_TYPE_NAME (stylable), stylable);
else
g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
g_object_unref (stylable);
}
void
tidy_stylable_notify (TidyStylable *stylable,
const gchar *property_name)
{
GParamSpec *pspec;
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_return_if_fail (property_name != NULL);
g_object_ref (stylable);
pspec = g_param_spec_pool_lookup (style_property_spec_pool,
property_name,
G_OBJECT_TYPE (stylable),
TRUE);
if (!pspec)
g_warning ("%s: object class `%s' has no style property named `%s'",
G_STRFUNC,
G_OBJECT_TYPE_NAME (stylable),
property_name);
else
{
GObjectNotifyQueue *nqueue;
nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable),
&property_notify_context);
g_object_notify_queue_add (G_OBJECT (stylable), nqueue, pspec);
g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
}
g_object_unref (stylable);
}
/**
* tidy_stylable_iface_install_property:
* @iface: a #TidyStylableIface
* @owner_type: #GType of the style property owner
* @pspec: a #GParamSpec
*
* Installs a property for @owner_type using @pspec as the property
* description.
*
* This function should be used inside the #TidyStylableIface initialization
* function of a class, for instance:
*
* <informalexample><programlisting>
* G_DEFINE_TYPE_WITH_CODE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR,
* G_IMPLEMENT_INTERFACE (TIDY_TYPE_STYLABLE,
* tidy_stylable_init));
* ...
* static void
* tidy_stylable_init (TidyStylableIface *iface)
* {
* static gboolean is_initialized = FALSE;
*
* if (!is_initialized)
* {
* ...
* tidy_stylable_iface_install_property (stylable,
* FOO_TYPE_ACTOR,
* g_param_spec_int ("x-spacing",
* "X Spacing",
* "Horizontal spacing",
* -1, G_MAXINT,
* 2,
* G_PARAM_READWRITE));
* ...
* }
* }
* </programlisting></informalexample>
*/
void
tidy_stylable_iface_install_property (TidyStylableIface *iface,
GType owner_type,
GParamSpec *pspec)
{
g_return_if_fail (TIDY_IS_STYLABLE_IFACE (iface));
g_return_if_fail (owner_type != G_TYPE_INVALID);
g_return_if_fail (G_IS_PARAM_SPEC (pspec));
g_return_if_fail (pspec->flags & G_PARAM_READABLE);
g_return_if_fail (!(pspec->flags & (G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT
)));
if (g_param_spec_pool_lookup (style_property_spec_pool, pspec->name,
owner_type,
FALSE))
{
g_warning ("%s: class `%s' already contains a style property named `%s'",
G_STRLOC,
g_type_name (owner_type),
pspec->name);
return;
}
g_param_spec_ref_sink (pspec);
g_param_spec_set_qdata_full (pspec, quark_real_owner,
g_strdup (g_type_name (owner_type)),
g_free);
g_param_spec_pool_insert (style_property_spec_pool,
pspec,
owner_type);
}
/**
* tidy_stylable_list_properties:
* @stylable: a #TidyStylable
* @n_props: return location for the number of properties, or %NULL
*
* Retrieves all the #GParamSpec<!-- -->s installed by @stylable.
*
* Return value: an array of #GParamSpec<!-- -->s. Free it with
* g_free() when done.
*/
GParamSpec **
tidy_stylable_list_properties (TidyStylable *stylable,
guint *n_props)
{
GParamSpec **pspecs = NULL;
guint n;
g_return_val_if_fail (TIDY_IS_STYLABLE (stylable), NULL);
pspecs = g_param_spec_pool_list (style_property_spec_pool,
G_OBJECT_TYPE (stylable),
&n);
if (n_props)
*n_props = n;
return pspecs;
}
/**
* tidy_stylable_find_property:
* @stylable: a #TidyStylable
* @property_name: the name of the property to find
*
* Finds the #GParamSpec installed by @stylable for the property
* with @property_name.
*
* Return value: a #GParamSpec for the given property, or %NULL if
* no property with that name was found
*/
GParamSpec *
tidy_stylable_find_property (TidyStylable *stylable,
const gchar *property_name)
{
g_return_val_if_fail (TIDY_IS_STYLABLE (stylable), NULL);
g_return_val_if_fail (property_name != NULL, NULL);
return g_param_spec_pool_lookup (style_property_spec_pool,
property_name,
G_OBJECT_TYPE (stylable),
TRUE);
}
static inline void
tidy_stylable_set_property_internal (TidyStylable *stylable,
GParamSpec *pspec,
const GValue *value,
GObjectNotifyQueue *nqueue)
{
GValue tmp_value = { 0, };
g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
if (!g_value_transform (value, &tmp_value))
g_warning ("unable to set property `%s' of type `%s' from value of type `%s'",
pspec->name,
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
G_VALUE_TYPE_NAME (value));
else if (g_param_value_validate (pspec, &tmp_value) &&
!(pspec->flags & G_PARAM_LAX_VALIDATION))
{
gchar *contents = g_strdup_value_contents (value);
g_warning ("value \"%s\" of type `%s' is invalid or out of range for property `%s' of type `%s'",
contents,
G_VALUE_TYPE_NAME (value),
pspec->name,
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
g_free (contents);
}
else
{
TidyStyle *style = tidy_stylable_get_style (stylable);
gchar *real_name;
real_name = g_strconcat (g_param_spec_get_qdata (pspec, quark_real_owner),
"::",
pspec->name,
NULL);
if (!tidy_style_has_property (style, real_name))
tidy_style_add_property (style, real_name,
G_PARAM_SPEC_VALUE_TYPE (pspec));
tidy_style_set_property (style, real_name, &tmp_value);
g_object_notify_queue_add (G_OBJECT (stylable), nqueue, pspec);
g_free (real_name);
}
g_value_unset (&tmp_value);
}
static inline void
tidy_stylable_get_property_internal (TidyStylable *stylable,
GParamSpec *pspec,
GValue *value)
{
TidyStyle *style;
GValue real_value = { 0, };
gchar *real_name;
real_name = g_strconcat (g_param_spec_get_qdata (pspec, quark_real_owner),
"::",
pspec->name,
NULL);
style = tidy_stylable_get_style (stylable);
if (!tidy_style_has_property (style, real_name))
{
/* the style has no property set, use the default value
* from the GParamSpec
*/
g_param_value_set_default (pspec, value);
g_free (real_name);
return;
}
tidy_style_get_property (style, real_name, &real_value);
g_value_copy (&real_value, value);
g_value_unset (&real_value);
g_free (real_name);
}
/**
* tidy_stylable_get_property:
* @stylable: a #TidyStylable
* @property_name: the name of the property
* @value: return location for an empty #GValue
*
* Retrieves the value of @property_name for @stylable, and puts it
* into @value.
*/
void
tidy_stylable_get_property (TidyStylable *stylable,
const gchar *property_name,
GValue *value)
{
GParamSpec *pspec;
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_return_if_fail (property_name != NULL);
g_return_if_fail (value != NULL);
pspec = tidy_stylable_find_property (stylable, property_name);
if (!pspec)
{
g_warning ("Stylable class `%s' doesn't have a property named `%s'",
g_type_name (G_OBJECT_TYPE (stylable)),
property_name);
return;
}
if (!(pspec->flags & G_PARAM_READABLE))
{
g_warning ("Style property `%s' of class `%s' is not readable",
pspec->name,
g_type_name (G_OBJECT_TYPE (stylable)));
return;
}
if (G_VALUE_TYPE (value) != G_PARAM_SPEC_VALUE_TYPE (pspec))
{
g_warning ("Passed value is not of the requested type `%s' for "
"the style property `%s' of class `%s'",
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
pspec->name,
g_type_name (G_OBJECT_TYPE (stylable)));
return;
}
tidy_stylable_get_property_internal (stylable, pspec, value);
}
/**
* tidy_stylable_set_property:
* @stylable: a #TidyStylable
* @property_name: the name of the property to set
* @value: an initialized #GValue
*
* Sets the property @property_name with @value.
*/
void
tidy_stylable_set_property (TidyStylable *stylable,
const gchar *property_name,
const GValue *value)
{
GObjectNotifyQueue *nqueue;
GParamSpec *pspec;
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_return_if_fail (property_name != NULL);
g_return_if_fail (value != NULL);
g_object_ref (stylable);
nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable),
&property_notify_context);
pspec = tidy_stylable_find_property (stylable, property_name);
if (!pspec)
{
g_warning ("Stylable class `%s' doesn't have a property named `%s'",
g_type_name (G_OBJECT_TYPE (stylable)),
property_name);
}
else if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("Style property `%s' of class `%s' is not readable",
pspec->name,
g_type_name (G_OBJECT_TYPE (stylable)));
}
else if (G_VALUE_TYPE (value) != G_PARAM_SPEC_VALUE_TYPE (pspec))
{
g_warning ("Passed value is not of the requested type `%s' for "
"the style property `%s' of class `%s'",
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
pspec->name,
g_type_name (G_OBJECT_TYPE (stylable)));
}
else
tidy_stylable_set_property_internal (stylable, pspec, value, nqueue);
g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
g_object_unref (stylable);
}
static void
tidy_stylable_get_valist (TidyStylable *stylable,
const gchar *first_property_name,
va_list varargs)
{
const gchar *name;
g_object_ref (stylable);
name = first_property_name;
while (name)
{
GParamSpec *pspec;
GValue value = { 0, };
gchar *error;
pspec = tidy_stylable_find_property (stylable, name);
if (!pspec)
{
g_warning ("%s: no style property named `%s' found for class `%s'",
G_STRLOC,
name,
g_type_name (G_OBJECT_TYPE (stylable)));
break;
}
if (!(pspec->flags & G_PARAM_READABLE))
{
g_warning ("Style property `%s' of class `%s' is not readable",
pspec->name,
g_type_name (G_OBJECT_TYPE (stylable)));
break;
}
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
tidy_stylable_get_property_internal (stylable, pspec, &value);
G_VALUE_LCOPY (&value, varargs, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
g_value_unset (&value);
break;
}
g_value_unset (&value);
name = va_arg (varargs, gchar*);
}
g_object_unref (stylable);
}
static void
tidy_stylable_set_valist (TidyStylable *stylable,
const gchar *first_property_name,
va_list varargs)
{
GObjectNotifyQueue *nqueue;
const gchar *name;
g_object_ref (stylable);
nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable),
&property_notify_context);
name = first_property_name;
while (name)
{
GParamSpec *pspec;
GValue value = { 0, };
gchar *error;
pspec = tidy_stylable_find_property (stylable, name);
if (!pspec)
{
g_warning ("%s: no style property named `%s' found for class `%s'",
G_STRLOC,
name,
g_type_name (G_OBJECT_TYPE (stylable)));
break;
}
if (!(pspec->flags & G_PARAM_WRITABLE) ||
(pspec->flags & G_PARAM_CONSTRUCT_ONLY))
{
g_warning ("Style property `%s' of class `%s' is not writable",
pspec->name,
g_type_name (G_OBJECT_TYPE (stylable)));
break;
}
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
G_VALUE_COLLECT (&value, varargs, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
g_value_unset (&value);
break;
}
tidy_stylable_set_property_internal (stylable, pspec, &value, nqueue);
g_value_unset (&value);
name = va_arg (varargs, gchar*);
}
g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
g_object_unref (stylable);
}
/**
* tidy_stylable_get:
* @stylable: a #TidyStylable
* @first_property_name: name of the first property to get
* @Varargs: return location for the first property, followed optionally
* by more name/return location pairs, followed by %NULL
*
* Gets the style properties for @stylable.
*
* In general, a copy is made of the property contents and the called
* is responsible for freeing the memory in the appropriate manner for
* the property type.
*
* <example>
* <title>Using tidy_stylable_get(<!-- -->)</title>
* <para>An example of using tidy_stylable_get() to get the contents of
* two style properties - one of type #G_TYPE_INT and one of type
* #CLUTTER_TYPE_COLOR:</para>
* <programlisting>
* gint x_spacing;
* ClutterColor *bg_color;
*
* tidy_stylable_get (stylable,
* "x-spacing", &amp;x_spacing,
* "bg-color", &amp;bg_color,
* NULL);
*
* /<!-- -->* do something with x_spacing and bg_color *<!-- -->/
*
* clutter_color_free (bg_color);
* </programlisting>
* </example>
*/
void
tidy_stylable_get (TidyStylable *stylable,
const gchar *first_property_name,
...)
{
va_list args;
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_return_if_fail (first_property_name != NULL);
va_start (args, first_property_name);
tidy_stylable_get_valist (stylable, first_property_name, args);
va_end (args);
}
/**
* tidy_stylable_set:
* @stylable: a #TidyStylable
* @first_property_name: name of the first property to set
* @Varargs: value for the first property, followed optionally by
* more name/value pairs, followed by %NULL
*
* Sets the style properties of @stylable.
*/
void
tidy_stylable_set (TidyStylable *stylable,
const gchar *first_property_name,
...)
{
va_list args;
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_return_if_fail (first_property_name != NULL);
va_start (args, first_property_name);
tidy_stylable_set_valist (stylable, first_property_name, args);
va_end (args);
}
/**
* tidy_stylable_get_style:
* @stylable: a #TidyStylable
*
* Retrieves the #TidyStyle used by @stylable. This function does not
* alter the reference count of the returned object.
*
* Return value: a #TidyStyle
*/
TidyStyle *
tidy_stylable_get_style (TidyStylable *stylable)
{
TidyStylableIface *iface;
g_return_val_if_fail (TIDY_IS_STYLABLE (stylable), NULL);
iface = TIDY_STYLABLE_GET_IFACE (stylable);
if (iface->get_style)
return iface->get_style (stylable);
return g_object_get_data (G_OBJECT (stylable), "tidy-stylable-style");
}
/**
* tidy_stylable_set_style:
* @stylable: a #TidyStylable
* @style: a #TidyStyle
*
* Sets @style as the new #TidyStyle to be used by @stylable.
*
* The #TidyStylable will take ownership of the passed #TidyStyle.
*
* After the #TidyStle has been set, the TidyStylable::style-set signal
* will be emitted.
*/
void
tidy_stylable_set_style (TidyStylable *stylable,
TidyStyle *style)
{
TidyStylableIface *iface;
TidyStyle *old_style;
g_return_if_fail (TIDY_IS_STYLABLE (stylable));
g_return_if_fail (TIDY_IS_STYLE (style));
iface = TIDY_STYLABLE_GET_IFACE (stylable);
old_style = tidy_stylable_get_style (stylable);
g_object_ref (old_style);
if (iface->set_style)
iface->set_style (stylable, style);
else
{
g_object_set_qdata_full (G_OBJECT (stylable),
quark_style,
g_object_ref_sink (style),
g_object_unref);
}
g_signal_emit (stylable, stylable_signals[STYLE_SET], 0, old_style);
g_object_unref (old_style);
g_object_notify (G_OBJECT (stylable), "style");
}

69
src/tidy/tidy-stylable.h Normal file
View File

@ -0,0 +1,69 @@
#ifndef __TIDY_STYLABLE_H__
#define __TIDY_STYLABLE_H__
#include <glib-object.h>
#include <tidy/tidy-style.h>
G_BEGIN_DECLS
#define TIDY_TYPE_STYLABLE (tidy_stylable_get_type ())
#define TIDY_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_STYLABLE, TidyStylable))
#define TIDY_IS_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_STYLABLE))
#define TIDY_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_CAST ((iface), TIDY_TYPE_STYLABLE, TidyStylableIface))
#define TIDY_IS_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_TYPE ((iface), TIDY_TYPE_STYLABLE))
#define TIDY_STYLABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TIDY_TYPE_STYLABLE, TidyStylableIface))
typedef struct _TidyStylable TidyStylable; /* dummy typedef */
typedef struct _TidyStylableIface TidyStylableIface;
struct _TidyStylableIface
{
GTypeInterface g_iface;
/* virtual functions */
TidyStyle *(* get_style) (TidyStylable *stylable);
void (* set_style) (TidyStylable *stylable,
TidyStyle *style);
/* signals, not vfuncs */
void (* style_notify) (TidyStylable *stylable,
GParamSpec *pspec);
void (* style_set) (TidyStylable *stylable,
TidyStyle *old_style);
};
GType tidy_stylable_get_type (void) G_GNUC_CONST;
void tidy_stylable_iface_install_property (TidyStylableIface *iface,
GType owner_type,
GParamSpec *pspec);
void tidy_stylable_freeze_notify (TidyStylable *stylable);
void tidy_stylable_notify (TidyStylable *stylable,
const gchar *property_name);
void tidy_stylable_thaw_notify (TidyStylable *stylable);
GParamSpec **tidy_stylable_list_properties (TidyStylable *stylable,
guint *n_props);
GParamSpec * tidy_stylable_find_property (TidyStylable *stylable,
const gchar *property_name);
void tidy_stylable_set_style (TidyStylable *stylable,
TidyStyle *style);
TidyStyle * tidy_stylable_get_style (TidyStylable *stylable);
void tidy_stylable_set (TidyStylable *stylable,
const gchar *first_property_name,
...) G_GNUC_NULL_TERMINATED;
void tidy_stylable_get (TidyStylable *stylable,
const gchar *first_property_name,
...) G_GNUC_NULL_TERMINATED;
void tidy_stylable_set_property (TidyStylable *stylable,
const gchar *property_name,
const GValue *value);
void tidy_stylable_get_property (TidyStylable *stylable,
const gchar *property_name,
GValue *value);
G_END_DECLS
#endif /* __TIDY_STYLABLE_H__ */

653
src/tidy/tidy-style.c Normal file
View File

@ -0,0 +1,653 @@
#ifndef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#include <clutter/clutter-behaviour.h>
#include <clutter/clutter-color.h>
#include "tidy-style.h"
#include "tidy-marshal.h"
#include "tidy-debug.h"
enum
{
CHANGED,
LAST_SIGNAL
};
#define TIDY_STYLE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), TIDY_TYPE_STYLE, TidyStylePrivate))
typedef struct {
GType value_type;
gchar *value_name;
GValue value;
} StyleProperty;
typedef struct {
gchar *name;
GType behaviour_type;
GArray *parameters;
guint duration;
ClutterAlphaFunc alpha_func;
} StyleEffect;
struct _TidyStylePrivate
{
GHashTable *properties;
GHashTable *effects;
};
static guint style_signals[LAST_SIGNAL] = { 0, };
static const gchar *tidy_default_font_name = "Sans 12px";
static const ClutterColor tidy_default_text_color = { 0x00, 0x00, 0x00, 0xff };
static const ClutterColor tidy_default_bg_color = { 0xcc, 0xcc, 0xcc, 0xff };
static const ClutterColor tidy_default_active_color = { 0xf5, 0x79, 0x00, 0xff };
static TidyStyle *default_style = NULL;
G_DEFINE_TYPE (TidyStyle, tidy_style, G_TYPE_OBJECT);
static StyleProperty *
style_property_new (const gchar *value_name,
GType value_type)
{
StyleProperty *retval;
retval = g_slice_new0 (StyleProperty);
retval->value_type = value_type;
retval->value_name = g_strdup (value_name);
g_value_init (&retval->value, value_type);
return retval;
}
static void
style_property_free (gpointer data)
{
if (G_LIKELY (data))
{
StyleProperty *sp = data;
g_free (sp->value_name);
g_value_unset (&sp->value);
}
}
static StyleEffect *
style_effect_new (const gchar *name)
{
StyleEffect *retval;
retval = g_slice_new0 (StyleEffect);
retval->name = g_strdup (name);
retval->behaviour_type = G_TYPE_INVALID;
return retval;
}
static void
style_effect_free (gpointer data)
{
if (G_LIKELY (data))
{
StyleEffect *effect = data;
g_free (effect->name);
if (effect->parameters)
{
gint i;
for (i = 0; i < effect->parameters->len; i++)
{
GParameter *param;
param = &g_array_index (effect->parameters, GParameter, i);
g_free ((gchar *) param->name);
g_value_unset (&param->value);
}
g_array_free (effect->parameters, TRUE);
effect->parameters = NULL;
}
g_slice_free (StyleEffect, effect);
}
}
static void
init_defaults (TidyStyle *style)
{
TidyStylePrivate *priv = style->priv;
{
StyleProperty *sp;
sp = style_property_new (TIDY_FONT_NAME, G_TYPE_STRING);
g_value_set_string (&sp->value, tidy_default_font_name);
g_hash_table_insert (priv->properties, sp->value_name, sp);
}
{
StyleProperty *sp;
sp = style_property_new (TIDY_BACKGROUND_COLOR, CLUTTER_TYPE_COLOR);
g_value_set_boxed (&sp->value, &tidy_default_bg_color);
g_hash_table_insert (priv->properties, sp->value_name, sp);
}
{
StyleProperty *sp;
sp = style_property_new (TIDY_ACTIVE_COLOR, CLUTTER_TYPE_COLOR);
g_value_set_boxed (&sp->value, &tidy_default_active_color);
g_hash_table_insert (priv->properties, sp->value_name, sp);
}
{
StyleProperty *sp;
sp = style_property_new (TIDY_TEXT_COLOR, CLUTTER_TYPE_COLOR);
g_value_set_boxed (&sp->value, &tidy_default_text_color);
g_hash_table_insert (priv->properties, sp->value_name, sp);
}
}
static gboolean
tidy_style_load_from_file (TidyStyle *style,
const gchar *filename,
GError **error)
{
GKeyFile *rc_file;
GError *internal_error;
rc_file = g_key_file_new ();
internal_error = NULL;
g_key_file_load_from_file (rc_file, filename, 0, &internal_error);
if (internal_error)
{
g_key_file_free (rc_file);
/* if the specified files does not exist then just ignore it
* and fall back to the default values; if, instead, the file
* is not accessible or is malformed, propagate the error
*/
if (internal_error->domain == G_FILE_ERROR &&
internal_error->code == G_FILE_ERROR_NOENT)
{
g_error_free (internal_error);
return TRUE;
}
g_propagate_error (error, internal_error);
return FALSE;
}
g_key_file_free (rc_file);
return TRUE;
}
static void
tidy_style_load (TidyStyle *style)
{
const gchar *env_var;
gchar *rc_file = NULL;
GError *error;
init_defaults (style);
env_var = g_getenv ("TIDY_RC_FILE");
if (env_var && *env_var)
rc_file = g_strdup (env_var);
if (!rc_file)
rc_file = g_build_filename (g_get_user_config_dir (),
"tidy",
"tidyrc",
NULL);
error = NULL;
if (!tidy_style_load_from_file (style, rc_file, &error))
{
g_critical ("Unable to load resource file `%s': %s",
rc_file,
error->message);
g_error_free (error);
}
g_free (rc_file);
}
static void
tidy_style_finalize (GObject *gobject)
{
TidyStylePrivate *priv = TIDY_STYLE (gobject)->priv;
g_hash_table_destroy (priv->properties);
g_hash_table_destroy (priv->effects);
G_OBJECT_CLASS (tidy_style_parent_class)->finalize (gobject);
}
static void
tidy_style_class_init (TidyStyleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (klass, sizeof (TidyStylePrivate));
gobject_class->finalize = tidy_style_finalize;
style_signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (TidyStyleClass, changed),
NULL, NULL,
_tidy_marshal_VOID__VOID,
G_TYPE_NONE, 0);
}
static void
tidy_style_init (TidyStyle *style)
{
TidyStylePrivate *priv;
style->priv = priv = TIDY_STYLE_GET_PRIVATE (style);
priv->properties = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
style_property_free);
priv->effects = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
style_effect_free);
tidy_style_load (style);
}
/* need to unref */
TidyStyle *
tidy_style_new (void)
{
return g_object_new (TIDY_TYPE_STYLE, NULL);
}
/* never ref/unref */
TidyStyle *
tidy_style_get_default (void)
{
if (G_LIKELY (default_style))
return default_style;
default_style = g_object_new (TIDY_TYPE_STYLE, NULL);
return default_style;
}
static StyleProperty *
tidy_style_find_property (TidyStyle *style,
const gchar *property_name)
{
return g_hash_table_lookup (style->priv->properties, property_name);
}
gboolean
tidy_style_has_property (TidyStyle *style,
const gchar *property_name)
{
g_return_val_if_fail (TIDY_IS_STYLE (style), FALSE);
g_return_val_if_fail (property_name != NULL, FALSE);
return (tidy_style_find_property (style, property_name) != NULL);
}
void
tidy_style_add_property (TidyStyle *style,
const gchar *property_name,
GType property_type)
{
StyleProperty *property;
g_return_if_fail (TIDY_IS_STYLE (style));
g_return_if_fail (property_name != NULL);
g_return_if_fail (property_type != G_TYPE_INVALID);
property = tidy_style_find_property (style, property_name);
if (G_UNLIKELY (property))
{
g_warning ("A property named `%s', with type %s already exists.",
property->value_name,
g_type_name (property->value_type));
return;
}
property = style_property_new (property_name, property_type);
g_hash_table_insert (style->priv->properties, property->value_name, property);
g_signal_emit (style, style_signals[CHANGED], 0);
}
void
tidy_style_get_property (TidyStyle *style,
const gchar *property_name,
GValue *value)
{
StyleProperty *property;
g_return_if_fail (TIDY_IS_STYLE (style));
g_return_if_fail (property_name != NULL);
g_return_if_fail (value != NULL);
property = tidy_style_find_property (style, property_name);
if (!property)
{
g_warning ("No style property named `%s' found.", property_name);
return;
}
g_value_init (value, property->value_type);
g_value_copy (&property->value, value);
}
void
tidy_style_set_property (TidyStyle *style,
const gchar *property_name,
const GValue *value)
{
StyleProperty *property;
g_return_if_fail (TIDY_IS_STYLE (style));
g_return_if_fail (property_name != NULL);
g_return_if_fail (value != NULL);
property = tidy_style_find_property (style, property_name);
if (!property)
{
g_warning ("No style property named `%s' found.", property_name);
return;
}
g_value_copy (value, &property->value);
g_signal_emit (style, style_signals[CHANGED], 0);
}
static StyleEffect *
tidy_style_find_effect (TidyStyle *style,
const gchar *effect_name)
{
return g_hash_table_lookup (style->priv->effects, effect_name);
}
void
tidy_style_add_effect (TidyStyle *style,
const gchar *effect_name)
{
StyleEffect *effect;
effect = tidy_style_find_effect (style, effect_name);
if (G_UNLIKELY (effect))
{
g_warning ("An effect named `%s', with type %s already exists.",
effect->name,
g_type_name (effect->behaviour_type));
return;
}
effect = style_effect_new (effect_name);
g_hash_table_replace (style->priv->effects,
effect->name,
effect);
}
gboolean
tidy_style_has_effect (TidyStyle *style,
const gchar *effect_name)
{
g_return_val_if_fail (TIDY_IS_STYLE (style), FALSE);
g_return_val_if_fail (effect_name != NULL, FALSE);
return (tidy_style_find_effect (style, effect_name) != NULL);
}
static void
tidy_style_set_effect_valist (TidyStyle *style,
StyleEffect *effect,
const gchar *first_property_name,
va_list varargs)
{
GObjectClass *klass;
const gchar *name;
klass = g_type_class_ref (effect->behaviour_type);
if (G_UNLIKELY (!klass))
return;
name = first_property_name;
while (name)
{
GParamSpec *pspec;
GParameter param = { 0, };
GValue value = { 0, };
gchar *error = NULL;
pspec = g_object_class_find_property (klass, name);
if (!pspec)
{
g_warning ("Unable to find the property `%s' for the "
"behaviour of type `%s'",
name,
g_type_name (effect->behaviour_type));
break;
}
if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("The property `%s' for the behaviour of type "
"`%s' is not writable",
pspec->name,
g_type_name (effect->behaviour_type));
break;
}
param.name = g_strdup (pspec->name);
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
G_VALUE_COLLECT (&value, varargs, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
g_value_unset (&value);
break;
}
g_value_init (&(param.value), G_PARAM_SPEC_VALUE_TYPE (pspec));
g_value_copy (&value, &(param.value));
g_value_unset (&value);
name = va_arg (varargs, gchar*);
}
g_type_class_unref (klass);
}
void
tidy_style_set_effect (TidyStyle *style,
const gchar *effect_name,
guint duration,
GType behaviour_type,
ClutterAlphaFunc alpha_func,
const gchar *first_property_name,
...)
{
StyleEffect *effect;
va_list args;
effect = tidy_style_find_effect (style, effect_name);
if (!effect)
{
g_warning ("No effect named `%s' found.", effect_name);
return;
}
if (effect->parameters)
{
gint i;
for (i = 0; i < effect->parameters->len; i++)
{
GParameter *param;
param = &g_array_index (effect->parameters, GParameter, i);
g_free ((gchar *) param->name);
g_value_unset (&param->value);
}
g_array_free (effect->parameters, TRUE);
effect->parameters = NULL;
}
effect->duration = duration;
effect->behaviour_type = behaviour_type;
effect->alpha_func = alpha_func;
effect->parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
va_start (args, first_property_name);
tidy_style_set_effect_valist (style, effect, first_property_name, args);
va_end (args);
}
void
tidy_style_set_effectv (TidyStyle *style,
const gchar *effect_name,
guint duration,
GType behaviour_type,
ClutterAlphaFunc alpha_func,
guint n_parameters,
GParameter *parameters)
{
StyleEffect *effect;
gint i;
effect = tidy_style_find_effect (style, effect_name);
if (!effect)
{
g_warning ("No effect named `%s' found.", effect_name);
return;
}
if (effect->parameters)
{
gint i;
for (i = 0; i < effect->parameters->len; i++)
{
GParameter *param;
param = &g_array_index (effect->parameters, GParameter, i);
g_free ((gchar *) param->name);
g_value_unset (&param->value);
}
g_array_free (effect->parameters, TRUE);
effect->parameters = NULL;
}
effect->duration = duration;
effect->behaviour_type = behaviour_type;
effect->alpha_func = alpha_func;
effect->parameters = g_array_new (FALSE, FALSE, sizeof (GParameter));
for (i = 0; i < n_parameters; i++)
{
GParameter param = { NULL, };
param.name = g_strdup (parameters[i].name);
g_value_init (&param.value, G_VALUE_TYPE (&parameters[i].value));
g_value_copy (&parameters[i].value, &param.value);
g_array_append_val (effect->parameters, param);
}
}
static ClutterBehaviour *
tidy_style_construct_effect (TidyStyle *style,
const gchar *effect_name)
{
ClutterTimeline *timeline;
ClutterAlpha *alpha;
ClutterBehaviour *behaviour;
StyleEffect *effect;
effect = tidy_style_find_effect (style, effect_name);
if (!effect)
{
g_warning ("No effect named `%s' found.", effect_name);
return NULL;
}
timeline = clutter_timeline_new_for_duration (effect->duration);
alpha = clutter_alpha_new_full (timeline, effect->alpha_func, NULL, NULL);
g_object_unref (timeline);
behaviour = g_object_newv (effect->behaviour_type,
effect->parameters->len,
(GParameter *) effect->parameters->data);
clutter_behaviour_set_alpha (behaviour, alpha);
/* we just unref the behaviour, which will take care of cleaning
* up everything (alpha+timeline)
*/
g_signal_connect_swapped (timeline,
"completed", G_CALLBACK (g_object_unref),
behaviour);
return behaviour;
}
ClutterTimeline *
tidy_style_get_effect (TidyStyle *style,
const gchar *effect_name,
ClutterActor *actor)
{
ClutterBehaviour *behaviour;
ClutterAlpha *alpha;
ClutterTimeline *timeline;
g_return_val_if_fail (TIDY_IS_STYLE (style), NULL);
g_return_val_if_fail (effect_name != NULL, NULL);
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
behaviour = tidy_style_construct_effect (style, effect_name);
if (!behaviour)
return NULL;
clutter_behaviour_apply (behaviour, actor);
alpha = clutter_behaviour_get_alpha (behaviour);
timeline = clutter_alpha_get_timeline (alpha);
return timeline;
}

85
src/tidy/tidy-style.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef __TIDY_STYLE_H__
#define __TIDY_STYLE_H__
#include <glib-object.h>
#include <clutter/clutter-actor.h>
#include <clutter/clutter-alpha.h>
#include <clutter/clutter-timeline.h>
G_BEGIN_DECLS
#define TIDY_TYPE_STYLE (tidy_style_get_type ())
#define TIDY_STYLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIDY_TYPE_STYLE, TidyStyle))
#define TIDY_IS_STYLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIDY_TYPE_STYLE))
#define TIDY_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TIDY_TYPE_STYLE, TidyStyleClass))
#define TIDY_IS_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TIDY_TYPE_STYLE))
#define TIDY_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TIDY_TYPE_STYLE, TidyStyleClass))
/* Default properties */
#define TIDY_FONT_NAME "TidyActor::font-name"
#define TIDY_BACKGROUND_COLOR "TidyActor::bg-color"
#define TIDY_ACTIVE_COLOR "TidyActor::active-color"
#define TIDY_TEXT_COLOR "TidyActor::text-color"
typedef struct _TidyStyle TidyStyle;
typedef struct _TidyStylePrivate TidyStylePrivate;
typedef struct _TidyStyleClass TidyStyleClass;
struct _TidyStyle
{
GObject parent_instance;
TidyStylePrivate *priv;
};
struct _TidyStyleClass
{
GObjectClass parent_class;
void (* changed) (TidyStyle *style);
};
GType tidy_style_get_type (void) G_GNUC_CONST;
TidyStyle * tidy_style_get_default (void);
TidyStyle * tidy_style_new (void);
gboolean tidy_style_has_property (TidyStyle *style,
const gchar *property_name);
gboolean tidy_style_has_effect (TidyStyle *style,
const gchar *effect_name);
void tidy_style_add_property (TidyStyle *style,
const gchar *property_name,
GType property_type);
void tidy_style_add_effect (TidyStyle *style,
const gchar *effect_name);
void tidy_style_get_property (TidyStyle *style,
const gchar *property_name,
GValue *value);
void tidy_style_set_property (TidyStyle *style,
const gchar *property_name,
const GValue *value);
ClutterTimeline *tidy_style_get_effect (TidyStyle *style,
const gchar *effect_name,
ClutterActor *actor);
void tidy_style_set_effectv (TidyStyle *style,
const gchar *effect_name,
guint duration,
GType behaviour_type,
ClutterAlphaFunc alpha_func,
guint n_parameters,
GParameter *parameters);
void tidy_style_set_effect (TidyStyle *style,
const gchar *effect_name,
guint duration,
GType behaviour_type,
ClutterAlphaFunc alpha_func,
const gchar *first_property_name,
...) G_GNUC_NULL_TERMINATED;
G_END_DECLS
#endif /* __TIDY_STYLE_H__ */

25
src/tidy/tidy-types.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __TIDY_TYPES_H__
#define __TIDY_TYPES_H__
#include <glib-object.h>
#include <clutter/clutter-units.h>
G_BEGIN_DECLS
#define TIDY_TYPE_PADDING (tidy_padding_get_type ())
typedef struct _TidyPadding TidyPadding;
struct _TidyPadding
{
ClutterUnit top;
ClutterUnit right;
ClutterUnit bottom;
ClutterUnit left;
};
GType tidy_padding_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __TIDY_TYPES_H__ */

37
src/tidy/tidy-util.c Normal file
View File

@ -0,0 +1,37 @@
#include "tidy-util.h"
/* Hack to (mostly) fill glyph cache, useful on MBX.
*
* FIXME: untested
*/
void
tidy_util_preload_glyphs (char *font, ...)
{
va_list args;
va_start (args, font);
while (font)
{
/* Hold on to your hat.. */
ClutterActor *foo;
ClutterColor text_color = { 0xff, 0xff, 0xff, 0xff };
foo = clutter_label_new_full
(font,
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"1234567890&()*.,';:-_+=[]{}#@?><\"!`%\\|/ ",
&text_color);
if (foo)
{
clutter_actor_realize(foo);
clutter_actor_paint(foo);
g_object_unref (foo);
}
font = va_arg (args, char*);
}
va_end (args);
}

9
src/tidy/tidy-util.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _TIDY_UTIL
#define _TIDY_UTIL
#include <clutter/clutter.h>
void
tidy_util_preload_glyphs (char *font, ...);
#endif