Import Mx core as ST
Import the core MxWidget/MxBin and their dependencies; we use the namespace "St" (Shell Toolkit) because it is the same length as Mx so enabling easy sharing of code, but makes it clear that this is a friendly fork and not a literal import. Based on a patch by Colin Walters <walters@verbum.org> https://bugzilla.gnome.org/show_bug.cgi?id=591245
This commit is contained in:
parent
2b78d5bd5d
commit
d291e568fd
@ -57,6 +57,7 @@ PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1 mutter-plugin
|
||||
gnome-desktop-2.0 >= 2.26 libstartup-notification-1.0
|
||||
gobject-introspection-1.0 >= 0.6.5)
|
||||
PKG_CHECK_MODULES(TIDY, clutter-1.0)
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-2.0 libccss-1 >= 0.3.1)
|
||||
PKG_CHECK_MODULES(BIG, clutter-1.0 gtk+-2.0 librsvg-2.0)
|
||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
|
||||
PKG_CHECK_MODULES(TRAY, gtk+-2.0)
|
||||
|
102
src/Makefile-st.am
Normal file
102
src/Makefile-st.am
Normal file
@ -0,0 +1,102 @@
|
||||
st_cflags = \
|
||||
-I$(top_srcdir)/src \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
-DG_LOG_DOMAIN=\"St\" \
|
||||
-DST_COMPILATION \
|
||||
-DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" \
|
||||
$(ST_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
st_built_sources = \
|
||||
st-enum-types.h \
|
||||
st-enum-types.c \
|
||||
st-marshal.h \
|
||||
st-marshal.c
|
||||
|
||||
BUILT_SOURCES += $(st_built_sources)
|
||||
|
||||
EXTRA_DIST += \
|
||||
st/st-marshal.list \
|
||||
st/st-enum-types.h.in \
|
||||
st/st-enum-types.c.in
|
||||
|
||||
CLEANFILES += stamp-st-marshal.h stamp-st-enum-types.h
|
||||
|
||||
st-marshal.h: stamp-st-marshal.h
|
||||
@true
|
||||
stamp-st-marshal.h: Makefile st/st-marshal.list
|
||||
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
|
||||
--prefix=_st_marshal \
|
||||
--header \
|
||||
$(srcdir)/st/st-marshal.list > $@.tmp && \
|
||||
(cmp -s $@.tmp st-marshal.h || cp -f $@.tmp st-marshal.h) && \
|
||||
rm -f $@.tmp && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
st-marshal.c: Makefile st/st-marshal.list
|
||||
$(AM_V_GEN) (echo "#include \"st-marshal.h\"" ; \
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_st_marshal \
|
||||
--body \
|
||||
$(srcdir)/st/st-marshal.list ) > $@.tmp && \
|
||||
cp -f $@.tmp st-marshal.c && \
|
||||
rm -f $@.tmp
|
||||
|
||||
st-enum-types.h: stamp-st-enum-types.h Makefile
|
||||
@true
|
||||
stamp-st-enum-types.h: $(source_h) st/st-enum-types.h.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template st/st-enum-types.h.in \
|
||||
$(st_source_h) ) >> $@.tmp && \
|
||||
(cmp -s $@.tmp st-enum-types.h || cp $@.tmp st-enum-types.h) && \
|
||||
rm -f $@.tmp && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
st-enum-types.c: stamp-st-enum-types.h st/st-enum-types.c.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template st/st-enum-types.c.in \
|
||||
$(st_source_h) ) >> $@.tmp && \
|
||||
cp $@.tmp $@ && \
|
||||
rm -f $@.tmp
|
||||
|
||||
# please, keep this sorted alphabetically
|
||||
st_source_h = \
|
||||
st/st-bin.h \
|
||||
st/st-private.h \
|
||||
st/st-stylable.h \
|
||||
st/st-style.h \
|
||||
st/st-subtexture.h \
|
||||
st/st-texture-cache.h \
|
||||
st/st-texture-frame.h \
|
||||
st/st-tooltip.h \
|
||||
st/st-types.h \
|
||||
st/st-widget.h \
|
||||
$(NULL)
|
||||
|
||||
# please, keep this sorted alphabetically
|
||||
st_source_c = \
|
||||
st/st-bin.c \
|
||||
st/st-private.c \
|
||||
st/st-stylable.c \
|
||||
st/st-style.c \
|
||||
st/st-subtexture.c \
|
||||
st/st-texture-cache.c \
|
||||
st/st-texture-frame.c \
|
||||
st/st-tooltip.c \
|
||||
st/st-widget.c \
|
||||
$(NULL)
|
||||
|
||||
noinst_LTLIBRARIES += libst-1.0.la
|
||||
|
||||
libst_1_0_la_LIBADD = $(ST_LIBS)
|
||||
libst_1_0_la_SOURCES = \
|
||||
$(st_source_c) \
|
||||
$(st_source_h) \
|
||||
$(st_built_sources) \
|
||||
$(NULL)
|
||||
libst_1_0_la_CPPFLAGS = $(st_cflags)
|
||||
libst_1_0_la_LDFLAGS = $(LDADD)
|
@ -24,6 +24,7 @@ EXTRA_DIST += gnome-shell.in
|
||||
|
||||
include Makefile-big.am
|
||||
include Makefile-gdmuser.am
|
||||
include Makefile-st.am
|
||||
include Makefile-tray.am
|
||||
|
||||
gnome_shell_cflags = \
|
||||
@ -150,14 +151,15 @@ libgnome_shell_la_LIBADD = \
|
||||
$(MUTTER_PLUGIN_LIBS) \
|
||||
$(LIBGNOMEUI_LIBS) \
|
||||
libbig-1.0.la \
|
||||
libst-1.0.la \
|
||||
libgdmuser-1.0.la \
|
||||
libtray.la
|
||||
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
|
||||
|
||||
typelibdir = $(pkglibdir)
|
||||
typelib_DATA = Shell-0.1.typelib Big-1.0.typelib
|
||||
typelib_DATA = Shell-0.1.typelib Big-1.0.typelib St-1.0.typelib
|
||||
|
||||
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
|
||||
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir St-1.0.gir libgnome-shell.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
--namespace=Shell \
|
||||
--nsversion=0.1 \
|
||||
@ -167,6 +169,7 @@ Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
|
||||
--libtool="$(LIBTOOL)" \
|
||||
--add-include-path=$(builddir) \
|
||||
--include=Big-1.0 \
|
||||
--include=St-1.0 \
|
||||
--program=mutter \
|
||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||
$(addprefix $(srcdir)/,$(libgnome_shell_la_gir_sources)) \
|
||||
@ -177,14 +180,14 @@ CLEANFILES += Shell-0.1.gir
|
||||
# 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)
|
||||
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Big-1.0.gir
|
||||
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
|
||||
$(AM_V_GEN) \
|
||||
$(G_IR_COMPILER) \
|
||||
--includedir=. \
|
||||
--includedir=$(MUTTER_LIB_DIR)/mutter/ \
|
||||
Shell-0.1.gir -o $@
|
||||
CLEANFILES += Shell-0.1.typelib
|
||||
|
||||
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la $(srcdir)/big-enum-types.h Makefile
|
||||
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
--namespace=Big \
|
||||
--nsversion=1.0 \
|
||||
@ -201,6 +204,28 @@ Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la $(srcdir)
|
||||
CLEANFILES += Big-1.0.gir
|
||||
|
||||
Big-1.0.typelib: libbig-1.0.la Big-1.0.gir
|
||||
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
|
||||
$(G_IR_COMPILER) Big-1.0.gir -o $@
|
||||
$(AM_V_GEN) $(G_IR_COMPILER) Big-1.0.gir -o $@
|
||||
CLEANFILES += Big-1.0.typelib
|
||||
|
||||
St-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libst-1.0.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
--namespace=St \
|
||||
--nsversion=1.0 \
|
||||
--include=Clutter-1.0 \
|
||||
--add-include-path=$(builddir) \
|
||||
--libtool="$(LIBTOOL)" \
|
||||
--program=mutter \
|
||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||
-DST_COMPILATION \
|
||||
$(addprefix $(srcdir)/,$(st_source_h)) \
|
||||
$(addprefix $(srcdir)/,$(st_source_c)) \
|
||||
$(srcdir)/st-enum-types.h \
|
||||
$(ST_CFLAGS) \
|
||||
-o $@
|
||||
CLEANFILES += St-1.0.gir
|
||||
|
||||
St-1.0.typelib: St-1.0.gir
|
||||
$(AM_V_GEN) $(G_IR_COMPILER) \
|
||||
$< -o $@
|
||||
|
||||
CLEANFILES += St-1.0.typelib
|
||||
|
791
src/st/st-bin.c
Normal file
791
src/st/st-bin.c
Normal file
@ -0,0 +1,791 @@
|
||||
/*
|
||||
* st-bin.c: Basic container actor
|
||||
*
|
||||
* Copyright (c) 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Written by: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-bin
|
||||
* @short_description: a simple container with one actor
|
||||
*
|
||||
* #StBin is a simple container capable of having only one
|
||||
* #ClutterActor as a child.
|
||||
*
|
||||
* #StBin inherits from #StWidget, so it is fully themable.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "st-bin.h"
|
||||
#include "st-enum-types.h"
|
||||
#include "st-private.h"
|
||||
#include "st-stylable.h"
|
||||
|
||||
#define ST_BIN_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_BIN, StBinPrivate))
|
||||
|
||||
struct _StBinPrivate
|
||||
{
|
||||
ClutterActor *child;
|
||||
|
||||
StAlign x_align;
|
||||
StAlign y_align;
|
||||
|
||||
guint x_fill : 1;
|
||||
guint y_fill : 1;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_CHILD,
|
||||
PROP_X_ALIGN,
|
||||
PROP_Y_ALIGN,
|
||||
PROP_X_FILL,
|
||||
PROP_Y_FILL
|
||||
};
|
||||
|
||||
static void clutter_container_iface_init (ClutterContainerIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StBin, st_bin, ST_TYPE_WIDGET,
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
|
||||
clutter_container_iface_init));
|
||||
|
||||
void
|
||||
_st_bin_get_align_factors (StBin *bin,
|
||||
gdouble *x_align,
|
||||
gdouble *y_align)
|
||||
{
|
||||
StBinPrivate *priv = bin->priv;
|
||||
gdouble factor;
|
||||
|
||||
switch (priv->x_align)
|
||||
{
|
||||
case ST_ALIGN_START:
|
||||
factor = 0.0;
|
||||
break;
|
||||
|
||||
case ST_ALIGN_MIDDLE:
|
||||
factor = 0.5;
|
||||
break;
|
||||
|
||||
case ST_ALIGN_END:
|
||||
factor = 1.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
factor = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (x_align)
|
||||
*x_align = factor;
|
||||
|
||||
switch (priv->y_align)
|
||||
{
|
||||
case ST_ALIGN_START:
|
||||
factor = 0.0;
|
||||
break;
|
||||
|
||||
case ST_ALIGN_MIDDLE:
|
||||
factor = 0.5;
|
||||
break;
|
||||
|
||||
case ST_ALIGN_END:
|
||||
factor = 1.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
factor = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (y_align)
|
||||
*y_align = factor;
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_add (ClutterContainer *container,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
st_bin_set_child (ST_BIN (container), actor);
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_remove (ClutterContainer *container,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (container)->priv;
|
||||
|
||||
if (priv->child == actor)
|
||||
st_bin_set_child (ST_BIN (container), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_foreach (ClutterContainer *container,
|
||||
ClutterCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (container)->priv;
|
||||
|
||||
if (priv->child)
|
||||
callback (priv->child, user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_container_iface_init (ClutterContainerIface *iface)
|
||||
{
|
||||
iface->add = st_bin_add;
|
||||
iface->remove = st_bin_remove;
|
||||
iface->foreach = st_bin_foreach;
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_paint (ClutterActor *self)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (self)->priv;
|
||||
|
||||
/* allow StWidget to paint the background */
|
||||
CLUTTER_ACTOR_CLASS (st_bin_parent_class)->paint (self);
|
||||
|
||||
/* the pain our child */
|
||||
if (priv->child)
|
||||
clutter_actor_paint (priv->child);
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_pick (ClutterActor *self,
|
||||
const ClutterColor *pick_color)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (self)->priv;
|
||||
|
||||
/* get the default pick implementation */
|
||||
CLUTTER_ACTOR_CLASS (st_bin_parent_class)->pick (self, pick_color);
|
||||
|
||||
if (priv->child)
|
||||
clutter_actor_paint (priv->child);
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (self)->priv;
|
||||
|
||||
CLUTTER_ACTOR_CLASS (st_bin_parent_class)->allocate (self, box,
|
||||
flags);
|
||||
|
||||
if (priv->child)
|
||||
{
|
||||
gfloat natural_width, natural_height;
|
||||
gfloat min_width, min_height;
|
||||
gfloat child_width, child_height;
|
||||
gfloat available_width, available_height;
|
||||
ClutterRequestMode request;
|
||||
ClutterActorBox allocation = { 0, };
|
||||
StPadding padding = { 0, };
|
||||
gdouble x_align, y_align;
|
||||
|
||||
_st_bin_get_align_factors (ST_BIN (self), &x_align, &y_align);
|
||||
|
||||
st_widget_get_padding (ST_WIDGET (self), &padding);
|
||||
|
||||
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;
|
||||
|
||||
if (priv->x_fill)
|
||||
{
|
||||
allocation.x1 = (int) padding.left;
|
||||
allocation.x2 = (int)(allocation.x1 + available_width);
|
||||
}
|
||||
|
||||
if (priv->y_fill)
|
||||
{
|
||||
allocation.y1 = (int) padding.top;
|
||||
allocation.y2 = (int)(allocation.y1 + available_height);
|
||||
}
|
||||
|
||||
/* if we are filling horizontally and vertically then we're done */
|
||||
if (priv->x_fill && priv->y_fill)
|
||||
{
|
||||
clutter_actor_allocate (priv->child, &allocation, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
|
||||
g_object_get (G_OBJECT (priv->child), "request-mode", &request, NULL);
|
||||
|
||||
if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
|
||||
{
|
||||
clutter_actor_get_preferred_width (priv->child, available_height,
|
||||
&min_width,
|
||||
&natural_width);
|
||||
|
||||
child_width = CLAMP (natural_width, min_width, available_width);
|
||||
|
||||
clutter_actor_get_preferred_height (priv->child, child_width,
|
||||
&min_height,
|
||||
&natural_height);
|
||||
|
||||
child_height = CLAMP (natural_height, min_height, available_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_actor_get_preferred_height (priv->child, available_width,
|
||||
&min_height,
|
||||
&natural_height);
|
||||
|
||||
child_height = CLAMP (natural_height, min_height, available_height);
|
||||
|
||||
clutter_actor_get_preferred_width (priv->child, child_height,
|
||||
&min_width,
|
||||
&natural_width);
|
||||
|
||||
child_width = CLAMP (natural_width, min_width, available_width);
|
||||
}
|
||||
|
||||
if (!priv->x_fill)
|
||||
{
|
||||
allocation.x1 = (int)((available_width - child_width) * x_align
|
||||
+ padding.left);
|
||||
allocation.x2 = allocation.x1 + child_width;
|
||||
}
|
||||
|
||||
if (!priv->y_fill)
|
||||
{
|
||||
allocation.y1 = (int)((available_height - child_height) * y_align
|
||||
+ padding.top);
|
||||
allocation.y2 = allocation.y1 + child_height;
|
||||
}
|
||||
|
||||
clutter_actor_allocate (priv->child, &allocation, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (self)->priv;
|
||||
gfloat min_width, natural_width;
|
||||
StPadding padding = { 0, };
|
||||
|
||||
st_widget_get_padding (ST_WIDGET (self), &padding);
|
||||
|
||||
min_width = natural_width = padding.left + padding.right;
|
||||
|
||||
if (priv->child == NULL)
|
||||
{
|
||||
if (min_width_p)
|
||||
*min_width_p = min_width;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = natural_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_actor_get_preferred_width (priv->child, for_height,
|
||||
min_width_p,
|
||||
natural_width_p);
|
||||
|
||||
if (min_width_p)
|
||||
*min_width_p += min_width;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p += natural_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_get_preferred_height (ClutterActor *self,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (self)->priv;
|
||||
gfloat min_height, natural_height;
|
||||
StPadding padding = { 0, };
|
||||
|
||||
st_widget_get_padding (ST_WIDGET (self), &padding);
|
||||
|
||||
min_height = natural_height = padding.top + padding.bottom;
|
||||
|
||||
if (priv->child == NULL)
|
||||
{
|
||||
if (min_height_p)
|
||||
*min_height_p = min_height;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p = natural_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_actor_get_preferred_height (priv->child, for_width,
|
||||
min_height_p,
|
||||
natural_height_p);
|
||||
|
||||
if (min_height_p)
|
||||
*min_height_p += min_height;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p += natural_height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_dispose (GObject *gobject)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (gobject)->priv;
|
||||
|
||||
if (priv->child)
|
||||
{
|
||||
clutter_actor_unparent (priv->child);
|
||||
priv->child = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_bin_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StBin *bin = ST_BIN (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD:
|
||||
st_bin_set_child (bin, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_X_ALIGN:
|
||||
st_bin_set_alignment (bin,
|
||||
g_value_get_enum (value),
|
||||
bin->priv->y_align);
|
||||
break;
|
||||
|
||||
case PROP_Y_ALIGN:
|
||||
st_bin_set_alignment (bin,
|
||||
bin->priv->x_align,
|
||||
g_value_get_enum (value));
|
||||
break;
|
||||
|
||||
case PROP_X_FILL:
|
||||
st_bin_set_fill (bin,
|
||||
g_value_get_boolean (value),
|
||||
bin->priv->y_fill);
|
||||
break;
|
||||
|
||||
case PROP_Y_FILL:
|
||||
st_bin_set_fill (bin,
|
||||
bin->priv->y_fill,
|
||||
g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StBinPrivate *priv = ST_BIN (gobject)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_CHILD:
|
||||
g_value_set_object (value, priv->child);
|
||||
break;
|
||||
|
||||
case PROP_X_FILL:
|
||||
g_value_set_boolean (value, priv->x_fill);
|
||||
break;
|
||||
|
||||
case PROP_Y_FILL:
|
||||
g_value_set_boolean (value, priv->y_fill);
|
||||
break;
|
||||
|
||||
case PROP_X_ALIGN:
|
||||
g_value_set_enum (value, priv->x_align);
|
||||
break;
|
||||
|
||||
case PROP_Y_ALIGN:
|
||||
g_value_set_enum (value, priv->y_align);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_class_init (StBinClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (StBinPrivate));
|
||||
|
||||
gobject_class->set_property = st_bin_set_property;
|
||||
gobject_class->get_property = st_bin_get_property;
|
||||
gobject_class->dispose = st_bin_dispose;
|
||||
|
||||
actor_class->get_preferred_width = st_bin_get_preferred_width;
|
||||
actor_class->get_preferred_height = st_bin_get_preferred_height;
|
||||
actor_class->allocate = st_bin_allocate;
|
||||
actor_class->paint = st_bin_paint;
|
||||
actor_class->pick = st_bin_pick;
|
||||
|
||||
/**
|
||||
* StBin:child:
|
||||
*
|
||||
* The child #ClutterActor of the #StBin container.
|
||||
*/
|
||||
pspec = g_param_spec_object ("child",
|
||||
"Child",
|
||||
"The child of the Bin",
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_CHILD, pspec);
|
||||
|
||||
/**
|
||||
* StBin:x-align:
|
||||
*
|
||||
* The horizontal alignment of the #StBin child.
|
||||
*/
|
||||
pspec = g_param_spec_enum ("x-align",
|
||||
"X Align",
|
||||
"The horizontal alignment",
|
||||
ST_TYPE_ALIGN,
|
||||
ST_ALIGN_MIDDLE,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_X_ALIGN, pspec);
|
||||
|
||||
/**
|
||||
* StBin:y-align:
|
||||
*
|
||||
* The vertical alignment of the #StBin child.
|
||||
*/
|
||||
pspec = g_param_spec_enum ("y-align",
|
||||
"Y Align",
|
||||
"The vertical alignment",
|
||||
ST_TYPE_ALIGN,
|
||||
ST_ALIGN_MIDDLE,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_Y_ALIGN, pspec);
|
||||
|
||||
/**
|
||||
* StBin:x-fill:
|
||||
*
|
||||
* Whether the child should fill the horizontal allocation
|
||||
*/
|
||||
pspec = g_param_spec_boolean ("x-fill",
|
||||
"X Fill",
|
||||
"Whether the child should fill the "
|
||||
"horizontal allocation",
|
||||
FALSE,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_X_FILL, pspec);
|
||||
|
||||
/**
|
||||
* StBin:y-fill:
|
||||
*
|
||||
* Whether the child should fill the vertical allocation
|
||||
*/
|
||||
pspec = g_param_spec_boolean ("y-fill",
|
||||
"Y Fill",
|
||||
"Whether the child should fill the "
|
||||
"vertical allocation",
|
||||
FALSE,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_Y_FILL, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
st_bin_init (StBin *bin)
|
||||
{
|
||||
bin->priv = ST_BIN_GET_PRIVATE (bin);
|
||||
|
||||
bin->priv->x_align = ST_ALIGN_MIDDLE;
|
||||
bin->priv->y_align = ST_ALIGN_MIDDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_bin_new:
|
||||
*
|
||||
* Creates a new #StBin, a simple container for one child.
|
||||
*
|
||||
* Return value: the newly created #StBin actor
|
||||
*/
|
||||
StWidget *
|
||||
st_bin_new (void)
|
||||
{
|
||||
return g_object_new (ST_TYPE_BIN, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_bin_set_child:
|
||||
* @bin: a #StBin
|
||||
* @child: a #ClutterActor, or %NULL
|
||||
*
|
||||
* Sets @child as the child of @bin.
|
||||
*
|
||||
* If @bin already has a child, the previous child is removed.
|
||||
*/
|
||||
void
|
||||
st_bin_set_child (StBin *bin,
|
||||
ClutterActor *child)
|
||||
{
|
||||
StBinPrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_BIN (bin));
|
||||
g_return_if_fail (child == NULL || CLUTTER_IS_ACTOR (child));
|
||||
|
||||
priv = bin->priv;
|
||||
|
||||
if (priv->child == child)
|
||||
return;
|
||||
|
||||
if (priv->child)
|
||||
{
|
||||
ClutterActor *old_child = priv->child;
|
||||
|
||||
g_object_ref (old_child);
|
||||
|
||||
priv->child = NULL;
|
||||
clutter_actor_unparent (old_child);
|
||||
|
||||
g_signal_emit_by_name (bin, "actor-removed", old_child);
|
||||
|
||||
g_object_unref (old_child);
|
||||
}
|
||||
|
||||
if (child)
|
||||
{
|
||||
priv->child = child;
|
||||
clutter_actor_set_parent (child, CLUTTER_ACTOR (bin));
|
||||
|
||||
g_signal_emit_by_name (bin, "actor-added", priv->child);
|
||||
}
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
|
||||
|
||||
g_object_notify (G_OBJECT (bin), "child");
|
||||
}
|
||||
|
||||
/**
|
||||
* st_bin_get_child:
|
||||
* @bin: a #StBin
|
||||
*
|
||||
* Retrieves a pointer to the child of @bin.
|
||||
*
|
||||
* Return value: a #ClutterActor, or %NULL
|
||||
*/
|
||||
ClutterActor *
|
||||
st_bin_get_child (StBin *bin)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_BIN (bin), NULL);
|
||||
|
||||
return bin->priv->child;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_bin_set_alignment:
|
||||
* @bin: a #StBin
|
||||
* @x_align: horizontal alignment
|
||||
* @y_align: vertical alignment
|
||||
*
|
||||
* Sets the horizontal and vertical alignment of the child
|
||||
* inside a #StBin.
|
||||
*/
|
||||
void
|
||||
st_bin_set_alignment (StBin *bin,
|
||||
StAlign x_align,
|
||||
StAlign y_align)
|
||||
{
|
||||
StBinPrivate *priv;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_return_if_fail (ST_IS_BIN (bin));
|
||||
|
||||
priv = bin->priv;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (bin));
|
||||
|
||||
if (priv->x_align != x_align)
|
||||
{
|
||||
priv->x_align = x_align;
|
||||
g_object_notify (G_OBJECT (bin), "x-align");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->y_align != y_align)
|
||||
{
|
||||
priv->y_align = y_align;
|
||||
g_object_notify (G_OBJECT (bin), "y-align");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (bin));
|
||||
}
|
||||
|
||||
/**
|
||||
* st_bin_get_alignment:
|
||||
* @bin: a #StBin
|
||||
* @x_align: return location for the horizontal alignment, or %NULL
|
||||
* @y_align: return location for the vertical alignment, or %NULL
|
||||
*
|
||||
* Retrieves the horizontal and vertical alignment of the child
|
||||
* inside a #StBin, as set by st_bin_set_alignment().
|
||||
*/
|
||||
void
|
||||
st_bin_get_alignment (StBin *bin,
|
||||
StAlign *x_align,
|
||||
StAlign *y_align)
|
||||
{
|
||||
StBinPrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_BIN (bin));
|
||||
|
||||
priv = bin->priv;
|
||||
|
||||
if (x_align)
|
||||
*x_align = priv->x_align;
|
||||
|
||||
if (y_align)
|
||||
*y_align = priv->y_align;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_bin_set_fill:
|
||||
* @bin: a #StBin
|
||||
* @x_fill: %TRUE if the child should fill horizontally the @bin
|
||||
* @y_fill: %TRUE if the child should fill vertically the @bin
|
||||
*
|
||||
* Sets whether the child of @bin should fill out the horizontal
|
||||
* and/or vertical allocation of the parent
|
||||
*/
|
||||
void
|
||||
st_bin_set_fill (StBin *bin,
|
||||
gboolean x_fill,
|
||||
gboolean y_fill)
|
||||
{
|
||||
StBinPrivate *priv;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_return_if_fail (ST_IS_BIN (bin));
|
||||
|
||||
priv = bin->priv;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (bin));
|
||||
|
||||
if (priv->x_fill != x_fill)
|
||||
{
|
||||
priv->x_fill = x_fill;
|
||||
changed = TRUE;
|
||||
|
||||
g_object_notify (G_OBJECT (bin), "x-fill");
|
||||
}
|
||||
|
||||
if (priv->y_fill != y_fill)
|
||||
{
|
||||
priv->y_fill = y_fill;
|
||||
changed = TRUE;
|
||||
|
||||
g_object_notify (G_OBJECT (bin), "y-fill");
|
||||
}
|
||||
|
||||
if (changed)
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (bin));
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (bin));
|
||||
}
|
||||
|
||||
/**
|
||||
* st_bin_get_fill:
|
||||
* @bin: a #StBin
|
||||
* @x_fill: (out): return location for the horizontal fill, or %NULL
|
||||
* @y_fill: (out): return location for the vertical fill, or %NULL
|
||||
*
|
||||
* Retrieves the horizontal and vertical fill settings
|
||||
*/
|
||||
void
|
||||
st_bin_get_fill (StBin *bin,
|
||||
gboolean *x_fill,
|
||||
gboolean *y_fill)
|
||||
{
|
||||
g_return_if_fail (ST_IS_BIN (bin));
|
||||
|
||||
if (x_fill)
|
||||
*x_fill = bin->priv->x_fill;
|
||||
|
||||
if (y_fill)
|
||||
*y_fill = bin->priv->y_fill;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
st_padding_copy (gpointer data)
|
||||
{
|
||||
return g_slice_dup (StPadding, data);
|
||||
}
|
||||
|
||||
static void
|
||||
st_padding_free (gpointer data)
|
||||
{
|
||||
if (G_LIKELY (data))
|
||||
g_slice_free (StPadding, data);
|
||||
}
|
||||
|
||||
GType
|
||||
st_padding_get_type (void)
|
||||
{
|
||||
static GType our_type = 0;
|
||||
|
||||
if (G_UNLIKELY (our_type == 0))
|
||||
our_type = g_boxed_type_register_static (I_("StPadding"),
|
||||
st_padding_copy,
|
||||
st_padding_free);
|
||||
|
||||
return our_type;
|
||||
}
|
92
src/st/st-bin.h
Normal file
92
src/st/st-bin.h
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* st-bin.h: Basic container actor
|
||||
*
|
||||
* Copyright 2009, 2008 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Written by: Emmanuele Bassi <ebassi@linux.intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_BIN_H__
|
||||
#define __ST_BIN_H__
|
||||
|
||||
#include <st/st-types.h>
|
||||
#include <st/st-widget.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_BIN (st_bin_get_type ())
|
||||
#define ST_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_BIN, StBin))
|
||||
#define ST_IS_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_BIN))
|
||||
#define ST_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_BIN, StBinClass))
|
||||
#define ST_IS_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_BIN))
|
||||
#define ST_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_BIN, StBinClass))
|
||||
|
||||
typedef struct _StBin StBin;
|
||||
typedef struct _StBinPrivate StBinPrivate;
|
||||
typedef struct _StBinClass StBinClass;
|
||||
|
||||
/**
|
||||
* StBin:
|
||||
*
|
||||
* The #StBin struct contains only private data
|
||||
*/
|
||||
struct _StBin
|
||||
{
|
||||
/*< private >*/
|
||||
StWidget parent_instance;
|
||||
|
||||
StBinPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* StBinClass:
|
||||
*
|
||||
* The #StBinClass struct contains only private data
|
||||
*/
|
||||
struct _StBinClass
|
||||
{
|
||||
/*< private >*/
|
||||
StWidgetClass parent_class;
|
||||
};
|
||||
|
||||
GType st_bin_get_type (void) G_GNUC_CONST;
|
||||
|
||||
StWidget * st_bin_new (void);
|
||||
void st_bin_set_child (StBin *bin,
|
||||
ClutterActor *child);
|
||||
ClutterActor *st_bin_get_child (StBin *bin);
|
||||
void st_bin_set_alignment (StBin *bin,
|
||||
StAlign x_align,
|
||||
StAlign y_align);
|
||||
void st_bin_get_alignment (StBin *bin,
|
||||
StAlign *x_align,
|
||||
StAlign *y_align);
|
||||
void st_bin_set_fill (StBin *bin,
|
||||
gboolean x_fill,
|
||||
gboolean y_fill);
|
||||
void st_bin_get_fill (StBin *bin,
|
||||
gboolean *x_fill,
|
||||
gboolean *y_fill);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_BIN_H__ */
|
30
src/st/st-enum-types.c.in
Normal file
30
src/st/st-enum-types.c.in
Normal file
@ -0,0 +1,30 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#include "st-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 (g_intern_static_string ("@EnumName@"), values);
|
||||
}
|
||||
return enum_type_id;
|
||||
}
|
||||
/*** END value-tail ***/
|
29
src/st/st-enum-types.h.in
Normal file
29
src/st/st-enum-types.h.in
Normal file
@ -0,0 +1,29 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_ENUM_TYPES_H__
|
||||
#define __ST_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 /* !__ST_ENUM_TYPES_H__ */
|
||||
/*** END file-tail ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType @enum_name@_get_type (void) G_GNUC_CONST;
|
||||
#define ST_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
|
||||
|
||||
/*** END value-header ***/
|
12
src/st/st-marshal.list
Normal file
12
src/st/st-marshal.list
Normal file
@ -0,0 +1,12 @@
|
||||
VOID:OBJECT
|
||||
VOID:VOID
|
||||
VOID:PARAM
|
||||
VOID:POINTER
|
||||
VOID:UINT
|
||||
VOID:UINT,UINT
|
||||
VOID:OBJECT,OBJECT
|
||||
VOID:STRING,OBJECT
|
||||
VOID:OBJECT,OBJECT,INT,INT
|
||||
VOID:OBJECT,FLOAT,FLOAT,INT,ENUM
|
||||
VOID:FLOAT,FLOAT,INT,ENUM
|
||||
VOID:FLOAT,FLOAT
|
111
src/st/st-private.c
Normal file
111
src/st/st-private.c
Normal file
@ -0,0 +1,111 @@
|
||||
#include "st-private.h"
|
||||
|
||||
/* Utility function to modify a child allocation box with respect to the
|
||||
* x/y-fill child properties. Expects childbox to contain the available
|
||||
* allocation space.
|
||||
*/
|
||||
void
|
||||
_st_allocate_fill (ClutterActor *child,
|
||||
ClutterActorBox *childbox,
|
||||
StAlign x_alignment,
|
||||
StAlign y_alignment,
|
||||
gboolean x_fill,
|
||||
gboolean y_fill)
|
||||
{
|
||||
gfloat natural_width, natural_height;
|
||||
gfloat min_width, min_height;
|
||||
gfloat child_width, child_height;
|
||||
gfloat available_width, available_height;
|
||||
ClutterRequestMode request;
|
||||
ClutterActorBox allocation = { 0, };
|
||||
gdouble x_align, y_align;
|
||||
|
||||
if (x_alignment == ST_ALIGN_START)
|
||||
x_align = 0.0;
|
||||
else if (x_alignment == ST_ALIGN_MIDDLE)
|
||||
x_align = 0.5;
|
||||
else
|
||||
x_align = 1.0;
|
||||
|
||||
if (y_alignment == ST_ALIGN_START)
|
||||
y_align = 0.0;
|
||||
else if (y_alignment == ST_ALIGN_MIDDLE)
|
||||
y_align = 0.5;
|
||||
else
|
||||
y_align = 1.0;
|
||||
|
||||
available_width = childbox->x2 - childbox->x1;
|
||||
available_height = childbox->y2 - childbox->y1;
|
||||
|
||||
if (available_width < 0)
|
||||
available_width = 0;
|
||||
|
||||
if (available_height < 0)
|
||||
available_height = 0;
|
||||
|
||||
if (x_fill)
|
||||
{
|
||||
allocation.x1 = childbox->x1;
|
||||
allocation.x2 = (int)(allocation.x1 + available_width);
|
||||
}
|
||||
|
||||
if (y_fill)
|
||||
{
|
||||
allocation.y1 = childbox->y1;
|
||||
allocation.y2 = (int)(allocation.y1 + available_height);
|
||||
}
|
||||
|
||||
/* if we are filling horizontally and vertically then we're done */
|
||||
if (x_fill && y_fill)
|
||||
{
|
||||
*childbox = allocation;
|
||||
return;
|
||||
}
|
||||
|
||||
request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
|
||||
g_object_get (G_OBJECT (child), "request-mode", &request, NULL);
|
||||
|
||||
if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
|
||||
{
|
||||
clutter_actor_get_preferred_width (child, available_height,
|
||||
&min_width,
|
||||
&natural_width);
|
||||
|
||||
child_width = CLAMP (natural_width, min_width, available_width);
|
||||
|
||||
clutter_actor_get_preferred_height (child, child_width,
|
||||
&min_height,
|
||||
&natural_height);
|
||||
|
||||
child_height = CLAMP (natural_height, min_height, available_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
clutter_actor_get_preferred_height (child, available_width,
|
||||
&min_height,
|
||||
&natural_height);
|
||||
|
||||
child_height = CLAMP (natural_height, min_height, available_height);
|
||||
|
||||
clutter_actor_get_preferred_width (child, child_height,
|
||||
&min_width,
|
||||
&natural_width);
|
||||
|
||||
child_width = CLAMP (natural_width, min_width, available_width);
|
||||
}
|
||||
|
||||
if (!x_fill)
|
||||
{
|
||||
allocation.x1 = childbox->x1 + (int)((available_width - child_width) * x_align);
|
||||
allocation.x2 = allocation.x1 + (int) child_width;
|
||||
}
|
||||
|
||||
if (!y_fill)
|
||||
{
|
||||
allocation.y1 = childbox->y1 + (int)((available_height - child_height) * y_align);
|
||||
allocation.y2 = allocation.y1 + (int) child_height;
|
||||
}
|
||||
|
||||
*childbox = allocation;
|
||||
|
||||
}
|
57
src/st/st-private.h
Normal file
57
src/st/st-private.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* st-private.h: Private declarations
|
||||
*
|
||||
* Copyright 2007 OpenedHand
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ST_PRIVATE_H__
|
||||
#define __ST_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include "st-widget.h"
|
||||
#include "st-bin.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define I_(str) (g_intern_static_string ((str)))
|
||||
|
||||
#define ST_PARAM_READABLE \
|
||||
(G_PARAM_READABLE | \
|
||||
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
|
||||
|
||||
#define ST_PARAM_READWRITE \
|
||||
(G_PARAM_READABLE | G_PARAM_WRITABLE | \
|
||||
G_PARAM_STATIC_NICK | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
ClutterActor *_st_widget_get_dnd_clone (StWidget *widget);
|
||||
|
||||
void _st_bin_get_align_factors (StBin *bin,
|
||||
gdouble *x_align,
|
||||
gdouble *y_align);
|
||||
|
||||
void _st_allocate_fill (ClutterActor *child,
|
||||
ClutterActorBox *childbox,
|
||||
StAlign x_align,
|
||||
StAlign y_align,
|
||||
gboolean x_fill,
|
||||
gboolean y_fill);
|
||||
|
||||
#endif /* __ST_PRIVATE_H__ */
|
849
src/st/st-stylable.c
Normal file
849
src/st/st-stylable.c
Normal file
@ -0,0 +1,849 @@
|
||||
/*
|
||||
* st-stylable.c: Interface for stylable objects
|
||||
*
|
||||
* Copyright 2008 Intel Corporation
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
|
||||
* Thomas Wood <thomas@linux.intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-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 #StStyle to them.
|
||||
*
|
||||
* Objects can choose to subclass #StWidget, and thus inherit all the
|
||||
* #StWidget style properties; or they can subclass #StWidget and
|
||||
* reimplement the #StStylable interface to add new style properties
|
||||
* specific for them (and their subclasses); or, finally, they can simply
|
||||
* subclass #GObject and implement #StStylable 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 "st-marshal.h"
|
||||
#include "st-private.h"
|
||||
#include "st-stylable.h"
|
||||
|
||||
enum
|
||||
{
|
||||
STYLE_CHANGED,
|
||||
STYLE_NOTIFY,
|
||||
CHANGED,
|
||||
|
||||
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
|
||||
st_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
|
||||
st_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
|
||||
st_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 ("st-stylable-real-owner-quark");
|
||||
quark_style = g_quark_from_static_string ("st-stylable-style-quark");
|
||||
|
||||
style_property_spec_pool = g_param_spec_pool_new (FALSE);
|
||||
|
||||
property_notify_context.quark_notify_queue = g_quark_from_static_string ("StStylable-style-property-notify-queue");
|
||||
property_notify_context.dispatcher = st_stylable_notify_dispatcher;
|
||||
|
||||
/**
|
||||
* StStylable:style:
|
||||
*
|
||||
* The #StStyle attached to a stylable object.
|
||||
*/
|
||||
g_object_interface_install_property (g_iface,
|
||||
g_param_spec_object ("style",
|
||||
"Style",
|
||||
"A style object",
|
||||
ST_TYPE_STYLE,
|
||||
ST_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* StStylable::style-changed:
|
||||
* @stylable: the #StStylable that received the signal
|
||||
* @old_style: the previously set #StStyle for @stylable
|
||||
*
|
||||
* The ::style-changed signal is emitted each time one of the style
|
||||
* properties have changed.
|
||||
*/
|
||||
stylable_signals[STYLE_CHANGED] =
|
||||
g_signal_new (I_("style-changed"),
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (StStylableIface, style_changed),
|
||||
NULL, NULL,
|
||||
_st_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* StStylable::stylable-changed:
|
||||
* @actor: the actor that received the signal
|
||||
*
|
||||
* The ::changed signal is emitted each time any of the properties of the
|
||||
* stylable has changed.
|
||||
*/
|
||||
stylable_signals[CHANGED] =
|
||||
g_signal_new (I_("stylable-changed"),
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (StStylableIface, stylable_changed),
|
||||
NULL, NULL,
|
||||
_st_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
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 (StStylableIface, style_notify),
|
||||
NULL, NULL,
|
||||
_st_marshal_VOID__PARAM,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
GType
|
||||
st_stylable_get_type (void)
|
||||
{
|
||||
static GType our_type = 0;
|
||||
|
||||
if (G_UNLIKELY (our_type == 0))
|
||||
{
|
||||
GTypeInfo stylable_info = {
|
||||
sizeof (StStylableIface),
|
||||
st_stylable_base_init,
|
||||
st_stylable_base_finalize
|
||||
};
|
||||
|
||||
our_type = g_type_register_static (G_TYPE_INTERFACE,
|
||||
I_("StStylable"),
|
||||
&stylable_info, 0);
|
||||
}
|
||||
|
||||
return our_type;
|
||||
}
|
||||
|
||||
void
|
||||
st_stylable_freeze_notify (StStylable *stylable)
|
||||
{
|
||||
g_return_if_fail (ST_IS_STYLABLE (stylable));
|
||||
|
||||
g_object_ref (stylable);
|
||||
g_object_notify_queue_freeze (G_OBJECT (stylable), &property_notify_context);
|
||||
g_object_unref (stylable);
|
||||
}
|
||||
|
||||
void
|
||||
st_stylable_thaw_notify (StStylable *stylable)
|
||||
{
|
||||
GObjectNotifyQueue *nqueue;
|
||||
|
||||
g_return_if_fail (ST_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
|
||||
st_stylable_notify (StStylable *stylable,
|
||||
const gchar *property_name)
|
||||
{
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_return_if_fail (ST_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_iface_install_property:
|
||||
* @iface: a #StStylableIface
|
||||
* @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 #StStylableIface initialization
|
||||
* function of a class, for instance:
|
||||
*
|
||||
* <informalexample><programlisting>
|
||||
* G_DEFINE_TYPE_WITH_CODE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR,
|
||||
* G_IMPLEMENT_INTERFACE (ST_TYPE_STYLABLE,
|
||||
* st_stylable_init));
|
||||
* ...
|
||||
* static void
|
||||
* st_stylable_init (StStylableIface *iface)
|
||||
* {
|
||||
* static gboolean is_initialized = FALSE;
|
||||
*
|
||||
* if (!is_initialized)
|
||||
* {
|
||||
* ...
|
||||
* st_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
|
||||
st_stylable_iface_install_property (StStylableIface *iface,
|
||||
GType owner_type,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
g_return_if_fail (ST_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_list_properties:
|
||||
* @stylable: a #StStylable
|
||||
* @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 **
|
||||
st_stylable_list_properties (StStylable *stylable,
|
||||
guint *n_props)
|
||||
{
|
||||
GParamSpec **pspecs = NULL;
|
||||
guint n;
|
||||
|
||||
g_return_val_if_fail (ST_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_find_property:
|
||||
* @stylable: a #StStylable
|
||||
* @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 *
|
||||
st_stylable_find_property (StStylable *stylable,
|
||||
const gchar *property_name)
|
||||
{
|
||||
g_return_val_if_fail (ST_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
|
||||
st_stylable_get_property_internal (StStylable *stylable,
|
||||
GParamSpec *pspec,
|
||||
GValue *value)
|
||||
{
|
||||
StStyle *style;
|
||||
GValue real_value = { 0, };
|
||||
|
||||
style = st_stylable_get_style (stylable);
|
||||
|
||||
if (!style)
|
||||
{
|
||||
g_value_reset (value);
|
||||
return;
|
||||
}
|
||||
|
||||
st_style_get_property (style, stylable, pspec, &real_value);
|
||||
|
||||
g_value_copy (&real_value, value);
|
||||
g_value_unset (&real_value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_property:
|
||||
* @stylable: a #StStylable
|
||||
* @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
|
||||
st_stylable_get_property (StStylable *stylable,
|
||||
const gchar *property_name,
|
||||
GValue *value)
|
||||
{
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_return_if_fail (ST_IS_STYLABLE (stylable));
|
||||
g_return_if_fail (property_name != NULL);
|
||||
g_return_if_fail (value != NULL);
|
||||
|
||||
pspec = st_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;
|
||||
}
|
||||
|
||||
st_stylable_get_property_internal (stylable, pspec, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get:
|
||||
* @stylable: a #StStylable
|
||||
* @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 st_stylable_get(<!-- -->)</title>
|
||||
* <para>An example of using st_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;
|
||||
*
|
||||
* st_stylable_get (stylable,
|
||||
* "x-spacing", &x_spacing,
|
||||
* "bg-color", &bg_color,
|
||||
* NULL);
|
||||
*
|
||||
* /<!-- -->* do something with x_spacing and bg_color *<!-- -->/
|
||||
*
|
||||
* clutter_color_free (bg_color);
|
||||
* </programlisting>
|
||||
* </example>
|
||||
*/
|
||||
void
|
||||
st_stylable_get (StStylable *stylable,
|
||||
const gchar *first_property_name,
|
||||
...)
|
||||
{
|
||||
StStyle *style;
|
||||
va_list args;
|
||||
|
||||
g_return_if_fail (ST_IS_STYLABLE (stylable));
|
||||
g_return_if_fail (first_property_name != NULL);
|
||||
|
||||
style = st_stylable_get_style (stylable);
|
||||
|
||||
va_start (args, first_property_name);
|
||||
st_style_get_valist (style, stylable, first_property_name, args);
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_default_value:
|
||||
* @stylable: a #StStylable
|
||||
* @property_name: name of the property to query
|
||||
* @value_out: return location for the default value
|
||||
*
|
||||
* Query @stylable for the default value of property @property_name and
|
||||
* fill @value_out with the result.
|
||||
*
|
||||
* Returns: %TRUE if property @property_name exists and the default value has
|
||||
* been returned.
|
||||
*/
|
||||
gboolean
|
||||
st_stylable_get_default_value (StStylable *stylable,
|
||||
const gchar *property_name,
|
||||
GValue *value_out)
|
||||
{
|
||||
GParamSpec *pspec;
|
||||
|
||||
pspec = st_stylable_find_property (stylable, property_name);
|
||||
if (!pspec)
|
||||
{
|
||||
g_warning ("%s: no style property named `%s' found for class `%s'",
|
||||
G_STRLOC,
|
||||
property_name,
|
||||
g_type_name (G_OBJECT_TYPE (stylable)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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 FALSE;
|
||||
}
|
||||
|
||||
g_value_init (value_out, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
||||
g_param_value_set_default (pspec, value_out);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_style:
|
||||
* @stylable: a #StStylable
|
||||
*
|
||||
* Retrieves the #StStyle used by @stylable. This function does not
|
||||
* alter the reference count of the returned object.
|
||||
*
|
||||
* Return value: a #StStyle
|
||||
*/
|
||||
StStyle *
|
||||
st_stylable_get_style (StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
if (iface->get_style)
|
||||
return iface->get_style (stylable);
|
||||
|
||||
return g_object_get_data (G_OBJECT (stylable), "st-stylable-style");
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_set_style:
|
||||
* @stylable: a #StStylable
|
||||
* @style: a #StStyle
|
||||
*
|
||||
* Sets @style as the new #StStyle to be used by @stylable.
|
||||
*
|
||||
* The #StStylable will take ownership of the passed #StStyle.
|
||||
*
|
||||
* After the #StStle has been set, the StStylable::style-set signal
|
||||
* will be emitted.
|
||||
*/
|
||||
void
|
||||
st_stylable_set_style (StStylable *stylable,
|
||||
StStyle *style)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
StStyle *old_style;
|
||||
|
||||
g_return_if_fail (ST_IS_STYLABLE (stylable));
|
||||
g_return_if_fail (ST_IS_STYLE (style));
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
old_style = st_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_CHANGED], 0, old_style);
|
||||
g_object_unref (old_style);
|
||||
|
||||
g_object_notify (G_OBJECT (stylable), "style");
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_container:
|
||||
* @stylable: a #StStylable
|
||||
*
|
||||
* Obtain the parent #StStylable that contains @stylable.
|
||||
*
|
||||
* Return value: The parent #StStylable
|
||||
*/
|
||||
StStylable*
|
||||
st_stylable_get_container (StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
if (iface->get_container)
|
||||
return iface->get_container (stylable);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_base_style:
|
||||
* @stylable: a #StStylable
|
||||
*
|
||||
* Get the parent ancestor #StStylable of @stylable.
|
||||
*
|
||||
* Return value: the parent #StStylable
|
||||
*/
|
||||
StStylable*
|
||||
st_stylable_get_base_style (StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
if (iface->get_base_style)
|
||||
return iface->get_base_style (stylable);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_stylable_get_style_id:
|
||||
* @stylable: a #StStylable
|
||||
*
|
||||
* Get the ID value of @stylable
|
||||
*
|
||||
* Return value: the id of @stylable
|
||||
*/
|
||||
const gchar*
|
||||
st_stylable_get_style_id (StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
if (iface->get_style_id)
|
||||
return iface->get_style_id (stylable);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_style_type:
|
||||
* @stylable: a #StStylable
|
||||
*
|
||||
* Get the type name of @stylable
|
||||
*
|
||||
* Return value: the type name of @stylable
|
||||
*/
|
||||
const gchar*
|
||||
st_stylable_get_style_type (StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
if (iface->get_style_type)
|
||||
return iface->get_style_type (stylable);
|
||||
else
|
||||
return G_OBJECT_TYPE_NAME (stylable);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_style_class:
|
||||
* @stylable: a #StStylable
|
||||
*
|
||||
* Get the style class name of @stylable
|
||||
*
|
||||
* Return value: the type name of @stylable
|
||||
*/
|
||||
const gchar*
|
||||
st_stylable_get_style_class (StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
if (iface->get_style_class)
|
||||
return iface->get_style_class (stylable);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_pseudo_class:
|
||||
* @stylable: a #StStylable
|
||||
*
|
||||
* Get the pseudo class name of @stylable
|
||||
*
|
||||
* Return value: the pseudo class name of @stylable
|
||||
*/
|
||||
const gchar*
|
||||
st_stylable_get_pseudo_class (StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
if (iface->get_pseudo_class)
|
||||
return iface->get_pseudo_class (stylable);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_attribute:
|
||||
* @stylable: a #StStylable
|
||||
* @name: attribute name
|
||||
*
|
||||
* Get the named attribute from @stylable
|
||||
*
|
||||
* Return value: the value of the attribute
|
||||
*/
|
||||
gchar*
|
||||
st_stylable_get_attribute (StStylable *stylable,
|
||||
const gchar *name)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
GValue value = { 0, };
|
||||
GValue string_value = { 0, };
|
||||
gchar *ret;
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), NULL);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
|
||||
if (iface->get_attribute)
|
||||
return iface->get_attribute (stylable, name);
|
||||
|
||||
/* look up a generic gobject property */
|
||||
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (stylable), name);
|
||||
|
||||
/* if no such property exists, return NULL */
|
||||
if (pspec == NULL)
|
||||
return NULL;
|
||||
|
||||
g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
||||
g_object_get_property (G_OBJECT (stylable), name, &value);
|
||||
|
||||
g_value_init (&string_value, G_TYPE_STRING);
|
||||
if (g_value_transform (&value, &string_value))
|
||||
ret = g_strdup (g_value_get_string (&string_value));
|
||||
else
|
||||
ret = NULL;
|
||||
|
||||
g_value_unset (&value);
|
||||
g_value_unset (&string_value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_stylable_get_viewport:
|
||||
* @stylable: a #StStylable
|
||||
* @x: location to store X coordinate
|
||||
* @y: location to store Y coordinate
|
||||
* @width: location to store width
|
||||
* @height: location to store height
|
||||
*
|
||||
* Obtain the position and dimensions of @stylable.
|
||||
*
|
||||
* Return value: true if the function succeeded
|
||||
*/
|
||||
gboolean
|
||||
st_stylable_get_viewport (StStylable *stylable,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
StStylableIface *iface;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLABLE (stylable), FALSE);
|
||||
|
||||
iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
if (iface->get_viewport)
|
||||
return iface->get_viewport (stylable, x, y, width, height);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_stylable_changed:
|
||||
* @stylable: A #StStylable
|
||||
*
|
||||
* Emit the "stylable-changed" signal on @stylable
|
||||
*/
|
||||
void
|
||||
st_stylable_changed (StStylable *stylable)
|
||||
{
|
||||
g_signal_emit (stylable, stylable_signals[CHANGED], 0, NULL);
|
||||
}
|
124
src/st/st-stylable.h
Normal file
124
src/st/st-stylable.h
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* st-stylable.h: Interface for stylable objects
|
||||
*
|
||||
* Copyright 2008, 2009 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Written by: Emmanuele Bassi <ebassi@openedhand.com>
|
||||
* Thomas Wood <thomas@linux.intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_STYLABLE_H__
|
||||
#define __ST_STYLABLE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <st/st-style.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_STYLABLE (st_stylable_get_type ())
|
||||
#define ST_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_STYLABLE, StStylable))
|
||||
#define ST_IS_STYLABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_STYLABLE))
|
||||
#define ST_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_CAST ((iface), ST_TYPE_STYLABLE, StStylableIface))
|
||||
#define ST_IS_STYLABLE_IFACE(iface) (G_TYPE_CHECK_CLASS_TYPE ((iface), ST_TYPE_STYLABLE))
|
||||
#define ST_STYLABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), ST_TYPE_STYLABLE, StStylableIface))
|
||||
|
||||
/* StStylableIface is defined in st-style.h */
|
||||
|
||||
struct _StStylableIface
|
||||
{
|
||||
GTypeInterface g_iface;
|
||||
|
||||
/* virtual functions */
|
||||
StStyle * (* get_style) (StStylable *stylable);
|
||||
void (* set_style) (StStylable *stylable,
|
||||
StStyle *style);
|
||||
|
||||
/* context virtual functions */
|
||||
StStylable *(*get_container) (StStylable *stylable);
|
||||
StStylable *(*get_base_style) (StStylable *stylable);
|
||||
const gchar *(*get_style_id) (StStylable *stylable);
|
||||
const gchar *(*get_style_type) (StStylable *stylable);
|
||||
const gchar *(*get_style_class) (StStylable *stylable);
|
||||
const gchar *(*get_pseudo_class) (StStylable *stylable);
|
||||
gchar *(*get_attribute) (StStylable *stylable,
|
||||
const gchar *name);
|
||||
gboolean (*get_viewport) (StStylable *stylable,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
/* signals, not vfuncs */
|
||||
void (* style_notify) (StStylable *stylable,
|
||||
GParamSpec *pspec);
|
||||
void (* style_changed) (StStylable *stylable);
|
||||
|
||||
void (* stylable_changed) (StStylable *stylable);
|
||||
};
|
||||
|
||||
GType st_stylable_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void st_stylable_iface_install_property (StStylableIface *iface,
|
||||
GType owner_type,
|
||||
GParamSpec *pspec);
|
||||
|
||||
void st_stylable_freeze_notify (StStylable *stylable);
|
||||
void st_stylable_notify (StStylable *stylable,
|
||||
const gchar *property_name);
|
||||
void st_stylable_thaw_notify (StStylable *stylable);
|
||||
GParamSpec **st_stylable_list_properties (StStylable *stylable,
|
||||
guint *n_props);
|
||||
GParamSpec * st_stylable_find_property (StStylable *stylable,
|
||||
const gchar *property_name);
|
||||
void st_stylable_set_style (StStylable *stylable,
|
||||
StStyle *style);
|
||||
StStyle * st_stylable_get_style (StStylable *stylable);
|
||||
|
||||
void st_stylable_get (StStylable *stylable,
|
||||
const gchar *first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
void st_stylable_get_property (StStylable *stylable,
|
||||
const gchar *property_name,
|
||||
GValue *value);
|
||||
gboolean st_stylable_get_default_value (StStylable *stylable,
|
||||
const gchar *property_name,
|
||||
GValue *value_out);
|
||||
|
||||
StStylable* st_stylable_get_container (StStylable *stylable);
|
||||
StStylable* st_stylable_get_base_style (StStylable *stylable);
|
||||
const gchar* st_stylable_get_style_id (StStylable *stylable);
|
||||
const gchar* st_stylable_get_style_type (StStylable *stylable);
|
||||
const gchar* st_stylable_get_style_class (StStylable *stylable);
|
||||
const gchar* st_stylable_get_pseudo_class (StStylable *stylable);
|
||||
gchar* st_stylable_get_attribute (StStylable *stylable,
|
||||
const gchar *name);
|
||||
gboolean st_stylable_get_viewport (StStylable *stylable,
|
||||
gint *x,
|
||||
gint *y,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
void st_stylable_changed (StStylable *stylable);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_STYLABLE_H__ */
|
780
src/st/st-style.c
Normal file
780
src/st/st-style.c
Normal file
@ -0,0 +1,780 @@
|
||||
/*
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-style
|
||||
* @short_description: a data store for style properties
|
||||
*
|
||||
* #StStyle is a property data store that can read properties from a style
|
||||
* sheet. It is queried with objects that implement the StStylable
|
||||
* interface.
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gobject/gvaluecollector.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include <ccss/ccss.h>
|
||||
|
||||
#include "st-stylable.h"
|
||||
#include "st-style.h"
|
||||
#include "st-types.h"
|
||||
#include "st-marshal.h"
|
||||
#include "st-widget.h"
|
||||
|
||||
enum
|
||||
{
|
||||
CHANGED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define ST_STYLE_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_STYLE, StStylePrivate))
|
||||
|
||||
#define ST_STYLE_ERROR g_style_error_quark ()
|
||||
|
||||
typedef struct {
|
||||
GType value_type;
|
||||
gchar *value_name;
|
||||
GValue value;
|
||||
} StyleProperty;
|
||||
|
||||
struct _StStylePrivate
|
||||
{
|
||||
ccss_stylesheet_t *stylesheet;
|
||||
GList *image_paths;
|
||||
|
||||
GHashTable *style_hash;
|
||||
GHashTable *node_hash;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ccss_node_t parent;
|
||||
StStylable *stylable;
|
||||
StStylableIface *iface;
|
||||
} st_style_node_t;
|
||||
|
||||
static ccss_function_t const * peek_css_functions (void);
|
||||
|
||||
static ccss_node_class_t * peek_node_class (void);
|
||||
|
||||
static guint style_signals[LAST_SIGNAL] = { 0, };
|
||||
|
||||
static StStyle *default_style = NULL;
|
||||
|
||||
G_DEFINE_TYPE (StStyle, st_style, G_TYPE_OBJECT);
|
||||
|
||||
static GQuark
|
||||
g_style_error_quark (void)
|
||||
{
|
||||
return g_quark_from_static_string ("st-style-error-quark");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_style_real_load_from_file (StStyle *style,
|
||||
const gchar *filename,
|
||||
GError **error,
|
||||
gint priority)
|
||||
{
|
||||
StStylePrivate *priv;
|
||||
ccss_grammar_t *grammar;
|
||||
GError *internal_error;
|
||||
gchar *path;
|
||||
GList *l;
|
||||
|
||||
g_return_val_if_fail (ST_IS_STYLE (style), FALSE);
|
||||
g_return_val_if_fail (filename != NULL, FALSE);
|
||||
|
||||
priv = ST_STYLE (style)->priv;
|
||||
|
||||
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
internal_error = g_error_new (ST_STYLE_ERROR,
|
||||
ST_STYLE_ERROR_INVALID_FILE,
|
||||
_("Invalid theme file '%s'"), filename);
|
||||
g_propagate_error (error, internal_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* add the path of the stylesheet to the search path */
|
||||
path = g_path_get_dirname (filename);
|
||||
|
||||
/* make sure path is valid */
|
||||
if (!path)
|
||||
return TRUE;
|
||||
|
||||
for (l = priv->image_paths; l; l = l->next)
|
||||
{
|
||||
if (g_str_equal ((gchar *) l->data, path))
|
||||
{
|
||||
/* we have this path already */
|
||||
g_free (path);
|
||||
path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the new path */
|
||||
if (path)
|
||||
priv->image_paths = g_list_append (priv->image_paths, path);
|
||||
|
||||
/* now load the stylesheet */
|
||||
if (!priv->stylesheet)
|
||||
{
|
||||
grammar = ccss_grammar_create_css ();
|
||||
ccss_grammar_add_functions (grammar, peek_css_functions ());
|
||||
priv->stylesheet = ccss_grammar_create_stylesheet_from_file (grammar,
|
||||
filename,
|
||||
path);
|
||||
ccss_grammar_destroy (grammar);
|
||||
}
|
||||
else
|
||||
{
|
||||
ccss_stylesheet_add_from_file (priv->stylesheet, filename, priority, path);
|
||||
}
|
||||
|
||||
g_signal_emit (style, style_signals[CHANGED], 0, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_style_load_from_file:
|
||||
* @style: a #StStyle
|
||||
* @filename: filename of the style sheet to load
|
||||
* @error: a #GError or #NULL
|
||||
*
|
||||
* Load style information from the specified file.
|
||||
*
|
||||
* returns: TRUE if the style information was loaded successfully. Returns
|
||||
* FALSE on error.
|
||||
*/
|
||||
gboolean
|
||||
st_style_load_from_file (StStyle *style,
|
||||
const gchar *filename,
|
||||
GError **error)
|
||||
{
|
||||
return st_style_real_load_from_file (style, filename, error,
|
||||
CCSS_STYLESHEET_AUTHOR);
|
||||
}
|
||||
|
||||
static void
|
||||
st_style_load (StStyle *style)
|
||||
{
|
||||
const gchar *env_var;
|
||||
gchar *rc_file = NULL;
|
||||
GError *error;
|
||||
|
||||
env_var = g_getenv ("ST_RC_FILE");
|
||||
if (env_var && *env_var)
|
||||
rc_file = g_strdup (env_var);
|
||||
|
||||
if (!rc_file)
|
||||
rc_file = g_build_filename (PACKAGE_DATA_DIR,
|
||||
"st",
|
||||
"style",
|
||||
"default.css",
|
||||
NULL);
|
||||
|
||||
error = NULL;
|
||||
|
||||
if (g_file_test (rc_file, G_FILE_TEST_EXISTS))
|
||||
{
|
||||
/* load the default theme with lowest priority */
|
||||
if (!st_style_real_load_from_file (style, rc_file, &error, CCSS_STYLESHEET_USER_AGENT))
|
||||
{
|
||||
g_critical ("Unable to load resource file '%s': %s",
|
||||
rc_file,
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (rc_file);
|
||||
}
|
||||
|
||||
static void
|
||||
st_style_finalize (GObject *gobject)
|
||||
{
|
||||
StStylePrivate *priv = ((StStyle *) gobject)->priv;
|
||||
GList *l;
|
||||
|
||||
for (l = priv->image_paths; l; l = g_list_delete_link (l, l))
|
||||
{
|
||||
g_free (l->data);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_style_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_style_class_init (StStyleClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (StStylePrivate));
|
||||
|
||||
gobject_class->finalize = st_style_finalize;
|
||||
|
||||
/**
|
||||
* StStyle::changed:
|
||||
*
|
||||
* Indicates that the style data has changed in some way. For example, a new
|
||||
* stylesheet may have been loaded.
|
||||
*/
|
||||
|
||||
style_signals[CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (StStyleClass, changed),
|
||||
NULL, NULL,
|
||||
_st_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/* url loader for libccss */
|
||||
static char *
|
||||
ccss_url (GSList const *args,
|
||||
void *user_data)
|
||||
{
|
||||
const gchar *given_path, *filename;
|
||||
gchar *test_path;
|
||||
|
||||
g_return_val_if_fail (args, NULL);
|
||||
|
||||
given_path = (char const *) args->data;
|
||||
|
||||
/* we can only deal with local paths */
|
||||
if (!g_str_has_prefix (given_path, "file://"))
|
||||
return NULL;
|
||||
filename = &given_path[7];
|
||||
|
||||
/*
|
||||
* Handle absolute paths correctly
|
||||
*/
|
||||
if (*filename == '/')
|
||||
return strdup (filename);
|
||||
|
||||
/* first try looking in the theme dir */
|
||||
test_path = g_build_filename (g_get_user_config_dir (),
|
||||
"st",
|
||||
filename,
|
||||
NULL);
|
||||
if (g_file_test (test_path, G_FILE_TEST_IS_REGULAR))
|
||||
return test_path;
|
||||
g_free (test_path);
|
||||
|
||||
if (user_data)
|
||||
{
|
||||
test_path = g_build_filename ((gchar *) user_data, filename, NULL);
|
||||
|
||||
if (g_file_test (test_path, G_FILE_TEST_IS_REGULAR))
|
||||
return test_path;
|
||||
|
||||
g_free (test_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("No path available css url resolver!");
|
||||
}
|
||||
|
||||
/* couldn't find the image anywhere, so just return the filename */
|
||||
return strdup (given_path);
|
||||
}
|
||||
|
||||
static ccss_function_t const *
|
||||
peek_css_functions (void)
|
||||
{
|
||||
static ccss_function_t const ccss_functions[] =
|
||||
{
|
||||
{ "url", ccss_url },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return ccss_functions;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
st_style_init (StStyle *style)
|
||||
{
|
||||
StStylePrivate *priv;
|
||||
|
||||
style->priv = priv = ST_STYLE_GET_PRIVATE (style);
|
||||
|
||||
/* create a hash table to look up pointer keys and values */
|
||||
style->priv->node_hash = g_hash_table_new_full (NULL, NULL,
|
||||
NULL, g_free);
|
||||
style->priv->style_hash = g_hash_table_new_full (NULL, NULL,
|
||||
NULL, (GDestroyNotify) ccss_style_destroy);
|
||||
|
||||
st_style_load (style);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_style_new:
|
||||
*
|
||||
* Creates a new #StStyle object. This must be freed using #g_object_unref
|
||||
* when no longer required.
|
||||
*
|
||||
* Returns: a newly allocated #StStyle
|
||||
*/
|
||||
StStyle *
|
||||
st_style_new (void)
|
||||
{
|
||||
return g_object_new (ST_TYPE_STYLE, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_style_get_default:
|
||||
*
|
||||
* Return the default StStyle object. This includes the current theme (if
|
||||
* any).
|
||||
*
|
||||
* Returns: a #StStyle object. This must not be freed or unref'd by
|
||||
* applications
|
||||
*/
|
||||
StStyle *
|
||||
st_style_get_default (void)
|
||||
{
|
||||
if (G_LIKELY (default_style))
|
||||
return default_style;
|
||||
|
||||
default_style = g_object_new (ST_TYPE_STYLE, NULL);
|
||||
|
||||
return default_style;
|
||||
}
|
||||
|
||||
/* functions for ccss */
|
||||
|
||||
static st_style_node_t *
|
||||
get_container (st_style_node_t *node)
|
||||
{
|
||||
st_style_node_t *container;
|
||||
ClutterActor *parent;
|
||||
|
||||
g_return_val_if_fail (node, NULL);
|
||||
g_return_val_if_fail (node->iface, NULL);
|
||||
g_return_val_if_fail (node->stylable, NULL);
|
||||
|
||||
parent = clutter_actor_get_parent (CLUTTER_ACTOR (node->stylable));
|
||||
while (parent && !ST_IS_WIDGET (parent))
|
||||
parent = clutter_actor_get_parent (CLUTTER_ACTOR (parent));
|
||||
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
container = g_new0 (st_style_node_t, 1);
|
||||
ccss_node_init ((ccss_node_t*) container, peek_node_class ());
|
||||
container->iface = node->iface;
|
||||
container->stylable = ST_STYLABLE (parent);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
static const gchar*
|
||||
get_style_id (st_style_node_t *node)
|
||||
{
|
||||
return st_stylable_get_style_id (node->stylable);
|
||||
}
|
||||
|
||||
static const gchar*
|
||||
get_style_type (st_style_node_t *node)
|
||||
{
|
||||
return st_stylable_get_style_type (node->stylable);
|
||||
}
|
||||
|
||||
static const gchar*
|
||||
get_style_class (st_style_node_t *node)
|
||||
{
|
||||
return st_stylable_get_style_class (node->stylable);
|
||||
}
|
||||
|
||||
static const gchar*
|
||||
get_pseudo_class (st_style_node_t *node)
|
||||
{
|
||||
return st_stylable_get_pseudo_class (node->stylable);
|
||||
}
|
||||
|
||||
static const gchar*
|
||||
get_attribute (st_style_node_t *node,
|
||||
const char *name)
|
||||
{
|
||||
return st_stylable_get_attribute (node->stylable, name);
|
||||
}
|
||||
|
||||
static void
|
||||
release (st_style_node_t *node)
|
||||
{
|
||||
g_return_if_fail (node);
|
||||
|
||||
g_free (node);
|
||||
}
|
||||
|
||||
static ccss_node_class_t *
|
||||
peek_node_class (void)
|
||||
{
|
||||
static ccss_node_class_t _node_class = {
|
||||
.is_a = NULL,
|
||||
.get_container = (ccss_node_get_container_f) get_container,
|
||||
.get_id = (ccss_node_get_id_f) get_style_id,
|
||||
.get_type = (ccss_node_get_type_f) get_style_type,
|
||||
.get_class = (ccss_node_get_class_f) get_style_class,
|
||||
.get_pseudo_class = (ccss_node_get_pseudo_class_f) get_pseudo_class,
|
||||
.get_viewport = NULL, // (ccss_node_get_viewport_f) get_viewport,
|
||||
.get_attribute = (ccss_node_get_attribute_f) get_attribute,
|
||||
.release = (ccss_node_release_f) release
|
||||
};
|
||||
|
||||
return &_node_class;
|
||||
}
|
||||
|
||||
static void
|
||||
st_style_fetch_ccss_property (ccss_style_t *ccss_style,
|
||||
GParamSpec *pspec,
|
||||
GValue *value)
|
||||
{
|
||||
gboolean value_set = FALSE;
|
||||
|
||||
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
||||
|
||||
if (G_PARAM_SPEC_VALUE_TYPE (pspec))
|
||||
{
|
||||
double number;
|
||||
|
||||
if (G_IS_PARAM_SPEC_INT (pspec))
|
||||
{
|
||||
if (ccss_style_get_double (ccss_style, pspec->name, &number))
|
||||
{
|
||||
g_value_set_int (value, (gint) number);
|
||||
value_set = TRUE;
|
||||
}
|
||||
}
|
||||
else if (G_IS_PARAM_SPEC_UINT (pspec))
|
||||
{
|
||||
if (ccss_style_get_double (ccss_style, pspec->name, &number))
|
||||
{
|
||||
g_value_set_uint (value, (guint) number);
|
||||
value_set = TRUE;
|
||||
}
|
||||
}
|
||||
else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == ST_TYPE_BORDER_IMAGE &&
|
||||
!g_strcmp0 ("border-image", pspec->name))
|
||||
{
|
||||
ccss_border_image_t const *border_image;
|
||||
|
||||
if (ccss_style_get_property (ccss_style,
|
||||
"border-image",
|
||||
(ccss_property_base_t const **) &border_image))
|
||||
{
|
||||
if (border_image &&
|
||||
border_image->base.state == CCSS_PROPERTY_STATE_SET)
|
||||
{
|
||||
g_value_set_boxed (value, border_image);
|
||||
value_set = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ST_TYPE_PADDING == G_PARAM_SPEC_VALUE_TYPE (pspec) &&
|
||||
0 == g_strcmp0 ("padding", pspec->name))
|
||||
{
|
||||
StPadding padding = { 0, };
|
||||
gboolean padding_set = 0;
|
||||
|
||||
if (ccss_style_get_double (ccss_style, "padding-top", &number))
|
||||
{
|
||||
padding.top = number;
|
||||
padding_set = TRUE;
|
||||
}
|
||||
|
||||
if (ccss_style_get_double (ccss_style, "padding-right", &number))
|
||||
{
|
||||
padding.right = number;
|
||||
padding_set = TRUE;
|
||||
}
|
||||
|
||||
if (ccss_style_get_double (ccss_style, "padding-bottom", &number))
|
||||
{
|
||||
padding.bottom = number;
|
||||
padding_set = TRUE;
|
||||
}
|
||||
|
||||
if (ccss_style_get_double (ccss_style, "padding-left", &number))
|
||||
{
|
||||
padding.left = number;
|
||||
padding_set = TRUE;
|
||||
}
|
||||
|
||||
if (padding_set)
|
||||
{
|
||||
g_value_set_boxed (value, &padding);
|
||||
value_set = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *string = NULL;
|
||||
|
||||
ccss_style_get_string (ccss_style, pspec->name, &string);
|
||||
|
||||
if (string)
|
||||
{
|
||||
if (CLUTTER_IS_PARAM_SPEC_COLOR (pspec))
|
||||
{
|
||||
ClutterColor color = { 0, };
|
||||
|
||||
clutter_color_from_string (&color, string);
|
||||
clutter_value_set_color (value, &color);
|
||||
|
||||
value_set = TRUE;
|
||||
}
|
||||
else
|
||||
if (G_IS_PARAM_SPEC_STRING (pspec))
|
||||
{
|
||||
g_value_set_string (value, string);
|
||||
value_set = TRUE;
|
||||
}
|
||||
g_free (string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* no value was found in css, so copy in the default value */
|
||||
if (!value_set)
|
||||
g_param_value_set_default (pspec, value);
|
||||
}
|
||||
|
||||
static ccss_style_t*
|
||||
st_style_get_ccss_query (StStyle *style,
|
||||
StStylable *stylable)
|
||||
{
|
||||
StStylableIface *iface = ST_STYLABLE_GET_IFACE (stylable);
|
||||
ccss_style_t *ccss_style;
|
||||
st_style_node_t *ccss_node;
|
||||
|
||||
ccss_node = g_hash_table_lookup (style->priv->node_hash, stylable);
|
||||
|
||||
if (!ccss_node)
|
||||
{
|
||||
ccss_node = g_new0 (st_style_node_t, 1);
|
||||
ccss_node_init ((ccss_node_t*) ccss_node, peek_node_class ());
|
||||
ccss_node->iface = iface;
|
||||
ccss_node->stylable = stylable;
|
||||
|
||||
g_hash_table_insert (style->priv->node_hash, stylable, ccss_node);
|
||||
g_signal_connect_swapped (stylable, "stylable-changed",
|
||||
G_CALLBACK (g_hash_table_remove),
|
||||
style->priv->node_hash);
|
||||
|
||||
|
||||
g_object_weak_ref ((GObject*) stylable,
|
||||
(GWeakNotify) g_hash_table_remove, style->priv->node_hash);
|
||||
}
|
||||
|
||||
|
||||
ccss_style = g_hash_table_lookup (style->priv->style_hash, stylable);
|
||||
|
||||
if (!ccss_style)
|
||||
{
|
||||
ccss_style = ccss_stylesheet_query (style->priv->stylesheet,
|
||||
(ccss_node_t *) ccss_node);
|
||||
|
||||
g_hash_table_insert (style->priv->style_hash, stylable, ccss_style);
|
||||
|
||||
/* remove the cache if the stylable changes */
|
||||
g_signal_connect_swapped (stylable, "stylable-changed",
|
||||
G_CALLBACK (g_hash_table_remove),
|
||||
style->priv->style_hash);
|
||||
|
||||
g_object_weak_ref ((GObject*) stylable,
|
||||
(GWeakNotify) g_hash_table_remove, style->priv->style_hash);
|
||||
}
|
||||
|
||||
return ccss_style;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_style_get_property:
|
||||
* @style: the style data store object
|
||||
* @stylable: a stylable to retreive the data for
|
||||
* @pspec: a #GParamSpec describing the property required
|
||||
* @value: a #GValue to place the return value in
|
||||
*
|
||||
* Requests the property described in @pspec for the specified stylable
|
||||
*/
|
||||
|
||||
void
|
||||
st_style_get_property (StStyle *style,
|
||||
StStylable *stylable,
|
||||
GParamSpec *pspec,
|
||||
GValue *value)
|
||||
{
|
||||
StStylePrivate *priv;
|
||||
gboolean value_set = FALSE;
|
||||
|
||||
g_return_if_fail (ST_IS_STYLE (style));
|
||||
g_return_if_fail (ST_IS_STYLABLE (stylable));
|
||||
g_return_if_fail (pspec != NULL);
|
||||
g_return_if_fail (value != NULL);
|
||||
|
||||
priv = style->priv;
|
||||
|
||||
/* look up the property in the css */
|
||||
if (priv->stylesheet)
|
||||
{
|
||||
ccss_style_t *ccss_style;
|
||||
|
||||
ccss_style = st_style_get_ccss_query (style, stylable);
|
||||
if (ccss_style)
|
||||
{
|
||||
st_style_fetch_ccss_property (ccss_style, pspec, value);
|
||||
value_set = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* no value was found in css, so copy in the default value */
|
||||
if (!value_set)
|
||||
{
|
||||
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
||||
g_param_value_set_default (pspec, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* st_style_get_valist:
|
||||
* @style: a #StStyle
|
||||
* @stylable: a #StStylable
|
||||
* @first_property_name: name of the first property to get
|
||||
* @va_args: return location for the first property, followed optionally
|
||||
* by more name/return location pairs, followed by %NULL
|
||||
*
|
||||
* Gets the style properties for @stylable from @style.
|
||||
*
|
||||
* Please refer to st_style_get() for further information.
|
||||
*/
|
||||
void
|
||||
st_style_get_valist (StStyle *style,
|
||||
StStylable *stylable,
|
||||
const gchar *first_property_name,
|
||||
va_list va_args)
|
||||
{
|
||||
StStylePrivate *priv;
|
||||
const gchar *name = first_property_name;
|
||||
gboolean values_set = FALSE;
|
||||
|
||||
g_return_if_fail (ST_IS_STYLE (style));
|
||||
g_return_if_fail (ST_IS_STYLABLE (stylable));
|
||||
g_return_if_fail (style->priv != NULL);
|
||||
|
||||
priv = style->priv;
|
||||
|
||||
/* look up the property in the css */
|
||||
if (priv->stylesheet)
|
||||
{
|
||||
ccss_style_t *ccss_style;
|
||||
|
||||
ccss_style = st_style_get_ccss_query (style, stylable);
|
||||
|
||||
if (ccss_style)
|
||||
{
|
||||
while (name)
|
||||
{
|
||||
GValue value = { 0, };
|
||||
gchar *error = NULL;
|
||||
GParamSpec *pspec = st_stylable_find_property (stylable, name);
|
||||
st_style_fetch_ccss_property (ccss_style, pspec, &value);
|
||||
G_VALUE_LCOPY (&value, va_args, 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 (va_args, gchar*);
|
||||
}
|
||||
values_set = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!values_set)
|
||||
{
|
||||
/* Set the remaining properties to their default values
|
||||
* even if broken out of the above loop. */
|
||||
while (name)
|
||||
{
|
||||
GValue value = { 0, };
|
||||
gchar *error = NULL;
|
||||
st_stylable_get_default_value (stylable, name, &value);
|
||||
G_VALUE_LCOPY (&value, va_args, 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 (va_args, gchar*);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* st_style_get:
|
||||
* @style: a #StStyle
|
||||
* @stylable: a #StStylable
|
||||
* @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 from @style.
|
||||
*
|
||||
* In general, a copy is made of the property contents and the caller
|
||||
* is responsible for freeing the memory in the appropriate manner for
|
||||
* the property type.
|
||||
*/
|
||||
void
|
||||
st_style_get (StStyle *style,
|
||||
StStylable *stylable,
|
||||
const gchar *first_property_name,
|
||||
...)
|
||||
{
|
||||
va_list va_args;
|
||||
|
||||
g_return_if_fail (ST_IS_STYLE (style));
|
||||
g_return_if_fail (first_property_name != NULL);
|
||||
|
||||
va_start (va_args, first_property_name);
|
||||
st_style_get_valist (style, stylable, first_property_name, va_args);
|
||||
va_end (va_args);
|
||||
}
|
||||
|
94
src/st/st-style.h
Normal file
94
src/st/st-style.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_STYLE_H__
|
||||
#define __ST_STYLE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_STYLE (st_style_get_type ())
|
||||
#define ST_STYLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_STYLE, StStyle))
|
||||
#define ST_IS_STYLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_STYLE))
|
||||
#define ST_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_STYLE, StStyleClass))
|
||||
#define ST_IS_STYLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_STYLE))
|
||||
#define ST_STYLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_STYLE, StStyleClass))
|
||||
|
||||
typedef struct _StStyle StStyle;
|
||||
typedef struct _StStylePrivate StStylePrivate;
|
||||
typedef struct _StStyleClass StStyleClass;
|
||||
|
||||
/* forward declaration */
|
||||
typedef struct _StStylable StStylable; /* dummy typedef */
|
||||
typedef struct _StStylableIface StStylableIface;
|
||||
|
||||
typedef enum { /*< prefix=ST_STYLE_ERROR >*/
|
||||
ST_STYLE_ERROR_INVALID_FILE
|
||||
} StStyleError;
|
||||
|
||||
/**
|
||||
* StStyle:
|
||||
*
|
||||
* The contents of this structure is private and should only be accessed using
|
||||
* the provided API.
|
||||
*/
|
||||
struct _StStyle
|
||||
{
|
||||
/*< private >*/
|
||||
GObject parent_instance;
|
||||
|
||||
StStylePrivate *priv;
|
||||
};
|
||||
|
||||
struct _StStyleClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* changed) (StStyle *style);
|
||||
};
|
||||
|
||||
GType st_style_get_type (void) G_GNUC_CONST;
|
||||
|
||||
StStyle *st_style_get_default (void);
|
||||
StStyle *st_style_new (void);
|
||||
|
||||
gboolean st_style_load_from_file (StStyle *style,
|
||||
const gchar *filename,
|
||||
GError **error);
|
||||
void st_style_get_property (StStyle *style,
|
||||
StStylable *stylable,
|
||||
GParamSpec *pspec,
|
||||
GValue *value);
|
||||
void st_style_get (StStyle *style,
|
||||
StStylable *stylable,
|
||||
const gchar *first_property_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
void st_style_get_valist (StStyle *style,
|
||||
StStylable *stylable,
|
||||
const gchar *first_property_name,
|
||||
va_list va_args);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_STYLE_H__ */
|
575
src/st/st-subtexture.c
Normal file
575
src/st/st-subtexture.c
Normal file
@ -0,0 +1,575 @@
|
||||
/*
|
||||
* st-subtexture.h: Class to wrap a texture and "subframe" it.
|
||||
* based on
|
||||
* st-texture-frame.c: Expandible texture actor
|
||||
*
|
||||
* Copyright 2007 OpenedHand
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "st-subtexture.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_PARENT_TEXTURE,
|
||||
|
||||
PROP_TOP,
|
||||
PROP_LEFT,
|
||||
PROP_WIDTH,
|
||||
PROP_HEIGHT
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StSubtexture, st_subtexture, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
#define ST_SUBTEXTURE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_SUBTEXTURE, StSubtexturePrivate))
|
||||
|
||||
struct _StSubtexturePrivate
|
||||
{
|
||||
ClutterTexture *parent_texture;
|
||||
|
||||
int left;
|
||||
int top;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
CoglHandle material;
|
||||
};
|
||||
|
||||
static void
|
||||
st_subtexture_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
StSubtexturePrivate *priv = ST_SUBTEXTURE (self)->priv;
|
||||
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
{
|
||||
if (min_width_p)
|
||||
*min_width_p = 0;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (min_width_p)
|
||||
*min_width_p = priv->width;
|
||||
if (natural_width_p)
|
||||
*natural_width_p = priv->width;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_get_preferred_height (ClutterActor *self,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
StSubtexturePrivate *priv = ST_SUBTEXTURE (self)->priv;
|
||||
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
{
|
||||
if (min_height_p)
|
||||
*min_height_p = 0;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (min_height_p)
|
||||
*min_height_p = priv->height;
|
||||
if (natural_height_p)
|
||||
*natural_height_p = priv->height;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_realize (ClutterActor *self)
|
||||
{
|
||||
StSubtexturePrivate *priv = ST_SUBTEXTURE (self)->priv;
|
||||
|
||||
if (priv->material != COGL_INVALID_HANDLE)
|
||||
return;
|
||||
|
||||
priv->material = cogl_material_new ();
|
||||
|
||||
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_unrealize (ClutterActor *self)
|
||||
{
|
||||
StSubtexturePrivate *priv = ST_SUBTEXTURE (self)->priv;
|
||||
|
||||
if (priv->material == COGL_INVALID_HANDLE)
|
||||
return;
|
||||
|
||||
cogl_material_unref (priv->material);
|
||||
priv->material = COGL_INVALID_HANDLE;
|
||||
|
||||
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_paint (ClutterActor *self)
|
||||
{
|
||||
StSubtexturePrivate *priv = ST_SUBTEXTURE (self)->priv;
|
||||
CoglHandle cogl_texture = COGL_INVALID_HANDLE;
|
||||
ClutterActorBox box = { 0, 0, 0, 0 };
|
||||
gfloat tx1, ty1, tx2, ty2, tex_width, tex_height, width, height;
|
||||
guint8 opacity;
|
||||
|
||||
/* no need to paint stuff if we don't have a texture */
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
return;
|
||||
|
||||
/* parent texture may have been hidden, so need to make sure it gets
|
||||
* realized
|
||||
*/
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
|
||||
clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
|
||||
|
||||
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
|
||||
if (cogl_texture == COGL_INVALID_HANDLE)
|
||||
return;
|
||||
|
||||
tex_width = cogl_texture_get_width (cogl_texture);
|
||||
tex_height = cogl_texture_get_height (cogl_texture);
|
||||
|
||||
clutter_actor_get_allocation_box (self, &box);
|
||||
|
||||
width = box.x2 - box.x1;
|
||||
height = box.y2 - box.y1;
|
||||
|
||||
tx1 = 1.0 * priv->left / tex_width;
|
||||
ty1 = 1.0 * priv->top / tex_height;
|
||||
|
||||
tx2 = 1.0 * (priv->left + priv->width) / tex_width;
|
||||
ty2 = 1.0 * (priv->top + priv->height) / tex_height;
|
||||
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (self);
|
||||
|
||||
g_assert (priv->material != COGL_INVALID_HANDLE);
|
||||
|
||||
/* set the source material using the parent texture's COGL handle */
|
||||
cogl_material_set_color4ub (priv->material, 255, 255, 255, opacity);
|
||||
cogl_material_set_layer (priv->material, 0, cogl_texture);
|
||||
cogl_set_source (priv->material);
|
||||
|
||||
cogl_rectangle_with_texture_coords (0,0, (float) width, (float) height,
|
||||
tx1, ty1, tx2, ty2);
|
||||
}
|
||||
|
||||
static inline void
|
||||
st_subtexture_set_frame_internal (StSubtexture *frame,
|
||||
int left,
|
||||
int top,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
StSubtexturePrivate *priv = frame->priv;
|
||||
GObject *gobject = G_OBJECT (frame);
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_object_freeze_notify (gobject);
|
||||
|
||||
if (priv->top != top)
|
||||
{
|
||||
priv->top = top;
|
||||
g_object_notify (gobject, "top");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->left != left)
|
||||
{
|
||||
priv->left = left;
|
||||
g_object_notify (gobject, "left");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->width != width)
|
||||
{
|
||||
priv->width = width;
|
||||
g_object_notify (gobject, "width");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->height != height)
|
||||
{
|
||||
priv->height = height;
|
||||
g_object_notify (gobject, "height");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
|
||||
|
||||
g_object_thaw_notify (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StSubtexture *frame = ST_SUBTEXTURE (gobject);
|
||||
StSubtexturePrivate *priv = frame->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PARENT_TEXTURE:
|
||||
st_subtexture_set_parent_texture (frame,
|
||||
g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_TOP:
|
||||
st_subtexture_set_frame_internal (frame,
|
||||
priv->left,
|
||||
g_value_get_int (value),
|
||||
priv->width,
|
||||
priv->height);
|
||||
break;
|
||||
|
||||
case PROP_LEFT:
|
||||
st_subtexture_set_frame_internal (frame,
|
||||
g_value_get_int (value),
|
||||
priv->top,
|
||||
priv->width,
|
||||
priv->height);
|
||||
break;
|
||||
|
||||
case PROP_WIDTH:
|
||||
st_subtexture_set_frame_internal (frame,
|
||||
priv->left,
|
||||
priv->top,
|
||||
g_value_get_int (value),
|
||||
priv->height);
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
st_subtexture_set_frame_internal (frame,
|
||||
priv->left,
|
||||
priv->top,
|
||||
priv->width,
|
||||
g_value_get_int (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StSubtexturePrivate *priv = ST_SUBTEXTURE (gobject)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PARENT_TEXTURE:
|
||||
g_value_set_object (value, priv->parent_texture);
|
||||
break;
|
||||
|
||||
case PROP_LEFT:
|
||||
g_value_set_int (value, priv->left);
|
||||
break;
|
||||
|
||||
case PROP_TOP:
|
||||
g_value_set_int (value, priv->top);
|
||||
break;
|
||||
|
||||
case PROP_WIDTH:
|
||||
g_value_set_int (value, priv->width);
|
||||
break;
|
||||
|
||||
case PROP_HEIGHT:
|
||||
g_value_set_int (value, priv->height);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_dispose (GObject *gobject)
|
||||
{
|
||||
StSubtexturePrivate *priv = ST_SUBTEXTURE (gobject)->priv;
|
||||
|
||||
if (priv->parent_texture)
|
||||
{
|
||||
g_object_unref (priv->parent_texture);
|
||||
priv->parent_texture = NULL;
|
||||
}
|
||||
|
||||
if (priv->material)
|
||||
{
|
||||
cogl_material_unref (priv->material);
|
||||
priv->material = COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_subtexture_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_class_init (StSubtextureClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (StSubtexturePrivate));
|
||||
|
||||
actor_class->get_preferred_width =
|
||||
st_subtexture_get_preferred_width;
|
||||
actor_class->get_preferred_height =
|
||||
st_subtexture_get_preferred_height;
|
||||
actor_class->realize = st_subtexture_realize;
|
||||
actor_class->unrealize = st_subtexture_unrealize;
|
||||
actor_class->paint = st_subtexture_paint;
|
||||
|
||||
gobject_class->set_property = st_subtexture_set_property;
|
||||
gobject_class->get_property = st_subtexture_get_property;
|
||||
gobject_class->dispose = st_subtexture_dispose;
|
||||
|
||||
pspec = g_param_spec_object ("parent-texture",
|
||||
"Parent Texture",
|
||||
"The parent ClutterTexture",
|
||||
CLUTTER_TYPE_TEXTURE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT);
|
||||
g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
|
||||
|
||||
pspec = g_param_spec_int ("left",
|
||||
"Left",
|
||||
"Left offset",
|
||||
0, G_MAXINT,
|
||||
0,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
|
||||
|
||||
pspec = g_param_spec_int ("top",
|
||||
"Top",
|
||||
"Top offset",
|
||||
0, G_MAXINT,
|
||||
0,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_TOP, pspec);
|
||||
|
||||
pspec = g_param_spec_int ("width",
|
||||
"Width",
|
||||
"Width",
|
||||
0, G_MAXINT,
|
||||
0,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_WIDTH, pspec);
|
||||
|
||||
pspec = g_param_spec_int ("height",
|
||||
"Height",
|
||||
"Height",
|
||||
0, G_MAXINT,
|
||||
0,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_HEIGHT, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
st_subtexture_init (StSubtexture *self)
|
||||
{
|
||||
StSubtexturePrivate *priv;
|
||||
|
||||
self->priv = priv = ST_SUBTEXTURE_GET_PRIVATE (self);
|
||||
|
||||
priv->material = COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_subtexture_new:
|
||||
* @texture: a #ClutterTexture or %NULL
|
||||
* @left: left
|
||||
* @top: top
|
||||
* @width: width
|
||||
* @height: height
|
||||
*
|
||||
* A #StSubtexture is a specialized texture that efficiently clones
|
||||
* an area of the given @texture while keeping preserving portions of the
|
||||
* same texture.
|
||||
*
|
||||
* A #StSubtexture can be used to make a rectangular texture fit a
|
||||
* given size without stretching its borders.
|
||||
*
|
||||
* Return value: the newly created #StSubtexture
|
||||
*/
|
||||
ClutterActor*
|
||||
st_subtexture_new (ClutterTexture *texture,
|
||||
gint left,
|
||||
gint top,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
|
||||
|
||||
return g_object_new (ST_TYPE_SUBTEXTURE,
|
||||
"parent-texture", texture,
|
||||
"top", top,
|
||||
"left", left,
|
||||
"width", width,
|
||||
"height", height,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_subtexture_get_parent_texture:
|
||||
* @frame: A #StSubtexture
|
||||
*
|
||||
* Return the texture used by the #StSubtexture
|
||||
*
|
||||
* Returns: a #ClutterTexture owned by the #StSubtexture
|
||||
*/
|
||||
ClutterTexture *
|
||||
st_subtexture_get_parent_texture (StSubtexture *frame)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_SUBTEXTURE (frame), NULL);
|
||||
|
||||
return frame->priv->parent_texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_subtexture_set_parent_texture:
|
||||
* @frame: A #StSubtexture
|
||||
* @texture: A #ClutterTexture
|
||||
*
|
||||
* Set the #ClutterTexture used by this #StSubtexture
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_subtexture_set_parent_texture (StSubtexture *frame,
|
||||
ClutterTexture *texture)
|
||||
{
|
||||
StSubtexturePrivate *priv;
|
||||
gboolean was_visible;
|
||||
|
||||
g_return_if_fail (ST_IS_SUBTEXTURE (frame));
|
||||
g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
|
||||
|
||||
priv = frame->priv;
|
||||
|
||||
was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
|
||||
|
||||
if (priv->parent_texture == texture)
|
||||
return;
|
||||
|
||||
if (priv->parent_texture)
|
||||
{
|
||||
g_object_unref (priv->parent_texture);
|
||||
priv->parent_texture = NULL;
|
||||
|
||||
if (was_visible)
|
||||
clutter_actor_hide (CLUTTER_ACTOR (frame));
|
||||
}
|
||||
|
||||
if (texture)
|
||||
{
|
||||
priv->parent_texture = g_object_ref (texture);
|
||||
|
||||
if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
|
||||
clutter_actor_show (CLUTTER_ACTOR (frame));
|
||||
}
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
|
||||
|
||||
g_object_notify (G_OBJECT (frame), "parent-texture");
|
||||
}
|
||||
|
||||
/**
|
||||
* st_subtexture_set_frame:
|
||||
* @frame: A #StSubtexture
|
||||
* @left: left
|
||||
* @top: top
|
||||
* @width: width
|
||||
* @height: height
|
||||
*
|
||||
* Set the frame of the subtexture
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_subtexture_set_frame (StSubtexture *frame,
|
||||
gint left,
|
||||
gint top,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
g_return_if_fail (ST_IS_SUBTEXTURE (frame));
|
||||
|
||||
st_subtexture_set_frame_internal (frame, left, top, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_subtexture_get_frame:
|
||||
* @frame: A #StSubtexture
|
||||
* @left: left
|
||||
* @top: top
|
||||
* @width: width
|
||||
* @height: height
|
||||
*
|
||||
* Retrieve the current frame.
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_subtexture_get_frame (StSubtexture *frame,
|
||||
gint *left,
|
||||
gint *top,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
StSubtexturePrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_SUBTEXTURE (frame));
|
||||
|
||||
priv = frame->priv;
|
||||
|
||||
if (top)
|
||||
*top = priv->top;
|
||||
|
||||
if (left)
|
||||
*left = priv->left;
|
||||
|
||||
if (width)
|
||||
*width = priv->width;
|
||||
|
||||
if (height)
|
||||
*height = priv->height;
|
||||
}
|
96
src/st/st-subtexture.h
Normal file
96
src/st/st-subtexture.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* st-subtexture.h: Class to wrap a texture and "subframe" it.
|
||||
*
|
||||
* Based on
|
||||
* st-texture-frame.h: Expandible texture actor
|
||||
*
|
||||
* Copyright 2007, 2008 OpenedHand Ltd
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_SUBTEXTURE_H__
|
||||
#define __ST_SUBTEXTURE_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_SUBTEXTURE (st_subtexture_get_type ())
|
||||
#define ST_SUBTEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_SUBTEXTURE, StSubtexture))
|
||||
#define ST_SUBTEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_SUBTEXTURE, StSubtextureClass))
|
||||
#define ST_IS_SUBTEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_SUBTEXTURE))
|
||||
#define ST_IS_SUBTEXTURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_SUBTEXTURE))
|
||||
#define ST_SUBTEXTURE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_SUBTEXTURE, StSubtextureClass))
|
||||
|
||||
typedef struct _StSubtexture StSubtexture;
|
||||
typedef struct _StSubtexturePrivate StSubtexturePrivate;
|
||||
typedef struct _StSubtextureClass StSubtextureClass;
|
||||
|
||||
/**
|
||||
* StSubtexture:
|
||||
*
|
||||
* The contents of this structure are private and should only be accessed
|
||||
* through the public API.
|
||||
*/
|
||||
struct _StSubtexture
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActor parent_instance;
|
||||
|
||||
StSubtexturePrivate *priv;
|
||||
};
|
||||
|
||||
struct _StSubtextureClass
|
||||
{
|
||||
ClutterActorClass parent_class;
|
||||
|
||||
/* padding for future expansion */
|
||||
void (*_st_box_1) (void);
|
||||
void (*_st_box_2) (void);
|
||||
void (*_st_box_3) (void);
|
||||
void (*_st_box_4) (void);
|
||||
};
|
||||
|
||||
GType st_subtexture_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor * st_subtexture_new (ClutterTexture *texture,
|
||||
gint top,
|
||||
gint left,
|
||||
gint width,
|
||||
gint height);
|
||||
void st_subtexture_set_parent_texture (StSubtexture *frame,
|
||||
ClutterTexture *texture);
|
||||
ClutterTexture *st_subtexture_get_parent_texture (StSubtexture *frame);
|
||||
void st_subtexture_set_frame (StSubtexture *frame,
|
||||
gint top,
|
||||
gint left,
|
||||
gint width,
|
||||
gint height);
|
||||
void st_subtexture_get_frame (StSubtexture *frame,
|
||||
gint *top,
|
||||
gint *left,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_SUBTEXTURE_H__ */
|
450
src/st/st-texture-cache.c
Normal file
450
src/st/st-texture-cache.c
Normal file
@ -0,0 +1,450 @@
|
||||
/*
|
||||
* st-widget.h: Base class for St actors
|
||||
*
|
||||
* Copyright 2007 OpenedHand
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-texture-cache
|
||||
* @short_description: A per-process store to cache textures
|
||||
*
|
||||
* #StTextureCache allows an application to re-use an previously loaded
|
||||
* textures.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "st-texture-cache.h"
|
||||
#include "st-marshal.h"
|
||||
#include "st-private.h"
|
||||
#include "st-subtexture.h"
|
||||
G_DEFINE_TYPE (StTextureCache, st_texture_cache, G_TYPE_OBJECT)
|
||||
|
||||
#define TEXTURE_CACHE_PRIVATE(o) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((o), ST_TYPE_TEXTURE_CACHE, StTextureCachePrivate))
|
||||
|
||||
typedef struct _StTextureCachePrivate StTextureCachePrivate;
|
||||
|
||||
struct _StTextureCachePrivate
|
||||
{
|
||||
GHashTable *cache;
|
||||
};
|
||||
|
||||
typedef struct FinalizedClosure
|
||||
{
|
||||
gchar *path;
|
||||
StTextureCache *cache;
|
||||
} FinalizedClosure;
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
};
|
||||
|
||||
static StTextureCache* __cache_singleton = NULL;
|
||||
|
||||
/*
|
||||
* Convention: posX with a value of -1 indicates whole texture
|
||||
*/
|
||||
typedef struct StTextureCacheItem {
|
||||
char filename[256];
|
||||
int width, height;
|
||||
int posX, posY;
|
||||
ClutterActor *ptr;
|
||||
} StTextureCacheItem;
|
||||
|
||||
static StTextureCacheItem *
|
||||
st_texture_cache_item_new (void)
|
||||
{
|
||||
return g_slice_new0 (StTextureCacheItem);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_cache_item_free (StTextureCacheItem *item)
|
||||
{
|
||||
g_slice_free (StTextureCacheItem, item);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_cache_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_cache_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_cache_dispose (GObject *object)
|
||||
{
|
||||
if (G_OBJECT_CLASS (st_texture_cache_parent_class)->dispose)
|
||||
G_OBJECT_CLASS (st_texture_cache_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_cache_finalize (GObject *object)
|
||||
{
|
||||
StTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(object);
|
||||
|
||||
if (priv->cache)
|
||||
{
|
||||
g_hash_table_unref (priv->cache);
|
||||
priv->cache = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_texture_cache_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_cache_class_init (StTextureCacheClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (StTextureCachePrivate));
|
||||
|
||||
object_class->get_property = st_texture_cache_get_property;
|
||||
object_class->set_property = st_texture_cache_set_property;
|
||||
object_class->dispose = st_texture_cache_dispose;
|
||||
object_class->finalize = st_texture_cache_finalize;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_cache_init (StTextureCache *self)
|
||||
{
|
||||
StTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);
|
||||
|
||||
priv->cache = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
NULL);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_cache_get_default:
|
||||
*
|
||||
* Returns the default texture cache. This is owned by St and should not be
|
||||
* unreferenced or freed.
|
||||
*
|
||||
* Returns: a StTextureCache
|
||||
*/
|
||||
StTextureCache*
|
||||
st_texture_cache_get_default (void)
|
||||
{
|
||||
if (G_UNLIKELY (__cache_singleton == NULL))
|
||||
__cache_singleton = g_object_new (ST_TYPE_TEXTURE_CACHE, NULL);
|
||||
|
||||
return __cache_singleton;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
on_texure_finalized (gpointer data,
|
||||
GObject *where_the_object_was)
|
||||
{
|
||||
FinalizedClosure *closure = (FinalizedClosure *) data;
|
||||
StTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(closure->cache);
|
||||
|
||||
g_hash_table_remove (priv->cache, closure->path);
|
||||
|
||||
g_free(closure->path);
|
||||
g_free(closure);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* st_texture_cache_get_size:
|
||||
* @self: A #StTextureCache
|
||||
*
|
||||
* Returns the number of items in the texture cache
|
||||
*
|
||||
* Returns: the current size of the cache
|
||||
*/
|
||||
gint
|
||||
st_texture_cache_get_size (StTextureCache *self)
|
||||
{
|
||||
StTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);
|
||||
|
||||
return g_hash_table_size (priv->cache);
|
||||
}
|
||||
|
||||
static void
|
||||
add_texture_to_cache (StTextureCache *self,
|
||||
const gchar *path,
|
||||
StTextureCacheItem *item)
|
||||
{
|
||||
/* FinalizedClosure *closure; */
|
||||
StTextureCachePrivate *priv = TEXTURE_CACHE_PRIVATE(self);
|
||||
|
||||
g_hash_table_insert (priv->cache, g_strdup (path), item);
|
||||
|
||||
#if 0
|
||||
/* Make sure we can remove from hash */
|
||||
closure = g_new0 (FinalizedClosure, 1);
|
||||
closure->path = g_strdup (path);
|
||||
closure->cache = self;
|
||||
|
||||
g_object_weak_ref (G_OBJECT (res), on_texure_finalized, closure);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* NOTE: you should unref the returned texture when not needed */
|
||||
|
||||
/**
|
||||
* st_texture_cache_get_texture:
|
||||
* @self: A #StTextureCache
|
||||
* @path: A path to a image file
|
||||
*
|
||||
* Create a new ClutterTexture with the specified image. Adds the image to the
|
||||
* cache if the image had not been previously loaded. Subsequent calls with
|
||||
* the same image path will return a new ClutterTexture with the previously
|
||||
* loaded image.
|
||||
*
|
||||
* Returns: a newly created ClutterTexture
|
||||
*/
|
||||
ClutterTexture*
|
||||
st_texture_cache_get_texture (StTextureCache *self,
|
||||
const gchar *path)
|
||||
{
|
||||
ClutterActor *texture;
|
||||
CoglHandle *handle;
|
||||
StTextureCachePrivate *priv;
|
||||
StTextureCacheItem *item;
|
||||
|
||||
g_return_val_if_fail (ST_IS_TEXTURE_CACHE (self), NULL);
|
||||
g_return_val_if_fail (path != NULL, NULL);
|
||||
|
||||
|
||||
priv = TEXTURE_CACHE_PRIVATE (self);
|
||||
|
||||
item = g_hash_table_lookup (priv->cache, path);
|
||||
|
||||
if (item && item->posX != -1)
|
||||
{
|
||||
GError *err = NULL;
|
||||
/*
|
||||
* We have a cache hit, but it's for a partial texture. The only
|
||||
* sane option is to read it from disk and just don't cache it
|
||||
* at all.
|
||||
*/
|
||||
return CLUTTER_TEXTURE(clutter_texture_new_from_file(path, &err));
|
||||
}
|
||||
if (!item)
|
||||
{
|
||||
GError *err = NULL;
|
||||
|
||||
item = st_texture_cache_item_new ();
|
||||
item->posX = -1;
|
||||
item->posY = -1;
|
||||
item->ptr = clutter_texture_new_from_file (path, &err);
|
||||
clutter_texture_get_base_size (CLUTTER_TEXTURE (item->ptr),
|
||||
&item->width, &item->height);
|
||||
|
||||
if (!item->ptr)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
g_warning ("Error loading image: %s", err->message);
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_texture_to_cache (self, path, item);
|
||||
}
|
||||
|
||||
texture = clutter_texture_new ();
|
||||
handle = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (item->ptr));
|
||||
clutter_texture_set_cogl_texture ((ClutterTexture*) texture, handle);
|
||||
|
||||
return (ClutterTexture*) texture;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_texture_cache_get_actor:
|
||||
* @self: A #StTextureCache
|
||||
* @path: A path to a image file
|
||||
*
|
||||
* Create a new ClutterSubTexture with the specified image. Adds the image to the
|
||||
* cache if the image had not been previously loaded. Subsequent calls with
|
||||
* the same image path will return a new ClutterTexture with the previously
|
||||
* loaded image.
|
||||
*
|
||||
* Use this function if all you need is an actor for drawing.
|
||||
*
|
||||
* Returns: a newly created ClutterTexture
|
||||
*/
|
||||
ClutterActor*
|
||||
st_texture_cache_get_actor (StTextureCache *self,
|
||||
const gchar *path)
|
||||
{
|
||||
StTextureCachePrivate *priv;
|
||||
StTextureCacheItem *item;
|
||||
GError *err = NULL;
|
||||
|
||||
g_return_val_if_fail (ST_IS_TEXTURE_CACHE (self), NULL);
|
||||
g_return_val_if_fail (path != NULL, NULL);
|
||||
|
||||
priv = TEXTURE_CACHE_PRIVATE (self);
|
||||
|
||||
|
||||
item = g_hash_table_lookup (priv->cache, path);
|
||||
|
||||
if (item)
|
||||
{
|
||||
int posX = item->posX;
|
||||
int posY = item->posY;
|
||||
if (posX == -1)
|
||||
posX = 0;
|
||||
if (posY == -1)
|
||||
posY = 0;
|
||||
return st_subtexture_new (CLUTTER_TEXTURE (item->ptr), posX, posY,
|
||||
item->width, item->height);
|
||||
}
|
||||
|
||||
item = st_texture_cache_item_new ();
|
||||
item->posX = -1;
|
||||
item->posY = -1;
|
||||
item->ptr = clutter_texture_new_from_file (path, &err);
|
||||
clutter_texture_get_base_size (CLUTTER_TEXTURE (item->ptr),
|
||||
&item->width, &item->height);
|
||||
|
||||
if (!item->ptr)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
g_warning ("Error loading image: %s", err->message);
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
add_texture_to_cache (self, path, item);
|
||||
|
||||
return st_subtexture_new (CLUTTER_TEXTURE (item->ptr), 0, 0, item->width,
|
||||
item->height);
|
||||
}
|
||||
|
||||
void
|
||||
st_texture_cache_load_cache (StTextureCache *self,
|
||||
const gchar *filename)
|
||||
{
|
||||
FILE *file;
|
||||
StTextureCacheItem *element, head;
|
||||
int ret;
|
||||
ClutterActor *actor;
|
||||
GError *error = NULL;
|
||||
StTextureCachePrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_TEXTURE_CACHE (self));
|
||||
g_return_if_fail (filename != NULL);
|
||||
|
||||
priv = TEXTURE_CACHE_PRIVATE (self);
|
||||
|
||||
file = fopen(filename, "rm");
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
ret = fread (&head, sizeof(StTextureCacheItem), 1, file);
|
||||
if (ret < 0)
|
||||
{
|
||||
fclose (file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if we already if this texture in the cache */
|
||||
if (g_hash_table_lookup (priv->cache, head.filename))
|
||||
{
|
||||
/* skip it, we're done */
|
||||
fclose (file);
|
||||
return;
|
||||
}
|
||||
|
||||
actor = clutter_texture_new_from_file (head.filename, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_critical (G_STRLOC ": Error opening cache image file: %s",
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
fclose (file);
|
||||
return;
|
||||
}
|
||||
|
||||
element = st_texture_cache_item_new ();
|
||||
element->posX = -1;
|
||||
element->posY = -1;
|
||||
element->ptr = actor;
|
||||
strncpy (element->filename, head.filename, 256);
|
||||
clutter_texture_get_base_size (CLUTTER_TEXTURE (element->ptr),
|
||||
&element->width, &element->height);
|
||||
g_hash_table_insert (priv->cache, element->filename, element);
|
||||
|
||||
while (!feof (file))
|
||||
{
|
||||
element = st_texture_cache_item_new ();
|
||||
ret = fread (element, sizeof (StTextureCacheItem), 1, file);
|
||||
if (ret < 1)
|
||||
{
|
||||
/* end of file */
|
||||
st_texture_cache_item_free (element);
|
||||
break;
|
||||
}
|
||||
|
||||
element->ptr = actor;
|
||||
|
||||
if (g_hash_table_lookup (priv->cache, element->filename))
|
||||
{
|
||||
/* file is already in the cache.... */
|
||||
st_texture_cache_item_free (element);
|
||||
} else {
|
||||
g_hash_table_insert (priv->cache, element->filename, element);
|
||||
}
|
||||
}
|
||||
}
|
95
src/st/st-texture-cache.h
Normal file
95
src/st/st-texture-cache.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* st-texture-cache.h: Cached textures object
|
||||
*
|
||||
* Copyright 2007 OpenedHand
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ST_TEXTURE_CACHE
|
||||
#define _ST_TEXTURE_CACHE
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_TEXTURE_CACHE st_texture_cache_get_type()
|
||||
|
||||
#define ST_TEXTURE_CACHE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||||
ST_TYPE_TEXTURE_CACHE, StTextureCache))
|
||||
|
||||
#define ST_TEXTURE_CACHE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
||||
ST_TYPE_TEXTURE_CACHE, StTextureCacheClass))
|
||||
|
||||
#define ST_IS_TEXTURE_CACHE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
|
||||
ST_TYPE_TEXTURE_CACHE))
|
||||
|
||||
#define ST_IS_TEXTURE_CACHE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
||||
ST_TYPE_TEXTURE_CACHE))
|
||||
|
||||
#define ST_TEXTURE_CACHE_GET_CLASS(obj) \
|
||||
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
||||
ST_TYPE_TEXTURE_CACHE, StTextureCacheClass))
|
||||
|
||||
/**
|
||||
* StTextureCache:
|
||||
*
|
||||
* The contents of this structure are private and should only be accessed
|
||||
* through the public API.
|
||||
*/
|
||||
typedef struct {
|
||||
/*< private >*/
|
||||
GObject parent;
|
||||
} StTextureCache;
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* loaded) (StTextureCache *self,
|
||||
const gchar *path,
|
||||
ClutterTexture *texture);
|
||||
|
||||
void (* error_loading) (StTextureCache *self,
|
||||
GError *error);
|
||||
} StTextureCacheClass;
|
||||
|
||||
GType st_texture_cache_get_type (void);
|
||||
|
||||
StTextureCache* st_texture_cache_get_default (void);
|
||||
|
||||
ClutterTexture* st_texture_cache_get_texture (StTextureCache *self,
|
||||
const gchar *path);
|
||||
ClutterActor* st_texture_cache_get_actor (StTextureCache *self,
|
||||
const gchar *path);
|
||||
|
||||
gint st_texture_cache_get_size (StTextureCache *self);
|
||||
|
||||
void st_texture_cache_load_cache (StTextureCache *self,
|
||||
const char *filename);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _ST_TEXTURE_CACHE */
|
620
src/st/st-texture-frame.c
Normal file
620
src/st/st-texture-frame.c
Normal file
@ -0,0 +1,620 @@
|
||||
/*
|
||||
* st-texture-frame.h: Expandible texture actor
|
||||
*
|
||||
* Copyright 2007 OpenedHand
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-texture-frame
|
||||
* @short_description: Stretch a texture to fit the entire allocation
|
||||
*
|
||||
* #StTextureFrame
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
#include "st-texture-frame.h"
|
||||
#include "st-private.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_PARENT_TEXTURE,
|
||||
|
||||
PROP_TOP,
|
||||
PROP_RIGHT,
|
||||
PROP_BOTTOM,
|
||||
PROP_LEFT
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StTextureFrame, st_texture_frame, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
#define ST_TEXTURE_FRAME_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_TEXTURE_FRAME, StTextureFramePrivate))
|
||||
|
||||
struct _StTextureFramePrivate
|
||||
{
|
||||
ClutterTexture *parent_texture;
|
||||
|
||||
gfloat top;
|
||||
gfloat right;
|
||||
gfloat bottom;
|
||||
gfloat left;
|
||||
};
|
||||
|
||||
static void
|
||||
st_texture_frame_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
|
||||
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
{
|
||||
if (min_width_p)
|
||||
*min_width_p = 0;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClutterActorClass *klass;
|
||||
|
||||
/* by directly querying the parent texture's class implementation
|
||||
* we are going around any override mechanism the parent texture
|
||||
* might have in place, and we ask directly for the original
|
||||
* preferred width
|
||||
*/
|
||||
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
|
||||
klass->get_preferred_width (CLUTTER_ACTOR (priv->parent_texture),
|
||||
for_height,
|
||||
min_width_p,
|
||||
natural_width_p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_get_preferred_height (ClutterActor *self,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
|
||||
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
{
|
||||
if (min_height_p)
|
||||
*min_height_p = 0;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClutterActorClass *klass;
|
||||
|
||||
/* by directly querying the parent texture's class implementation
|
||||
* we are going around any override mechanism the parent texture
|
||||
* might have in place, and we ask directly for the original
|
||||
* preferred height
|
||||
*/
|
||||
klass = CLUTTER_ACTOR_GET_CLASS (priv->parent_texture);
|
||||
klass->get_preferred_height (CLUTTER_ACTOR (priv->parent_texture),
|
||||
for_width,
|
||||
min_height_p,
|
||||
natural_height_p);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_paint (ClutterActor *self)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (self)->priv;
|
||||
CoglHandle cogl_texture = COGL_INVALID_HANDLE;
|
||||
CoglHandle cogl_material = COGL_INVALID_HANDLE;
|
||||
ClutterActorBox box = { 0, };
|
||||
gfloat width, height;
|
||||
gfloat tex_width, tex_height;
|
||||
gfloat ex, ey;
|
||||
gfloat tx1, ty1, tx2, ty2;
|
||||
guint8 opacity;
|
||||
|
||||
/* no need to paint stuff if we don't have a texture */
|
||||
if (G_UNLIKELY (priv->parent_texture == NULL))
|
||||
return;
|
||||
|
||||
/* parent texture may have been hidden, so need to make sure it gets
|
||||
* realized
|
||||
*/
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent_texture))
|
||||
clutter_actor_realize (CLUTTER_ACTOR (priv->parent_texture));
|
||||
|
||||
cogl_texture = clutter_texture_get_cogl_texture (priv->parent_texture);
|
||||
if (cogl_texture == COGL_INVALID_HANDLE)
|
||||
return;
|
||||
cogl_material = clutter_texture_get_cogl_material (priv->parent_texture);
|
||||
if (cogl_material == COGL_INVALID_HANDLE)
|
||||
return;
|
||||
|
||||
tex_width = cogl_texture_get_width (cogl_texture);
|
||||
tex_height = cogl_texture_get_height (cogl_texture);
|
||||
|
||||
clutter_actor_get_allocation_box (self, &box);
|
||||
width = box.x2 - box.x1;
|
||||
height = box.y2 - box.y1;
|
||||
|
||||
tx1 = priv->left / tex_width;
|
||||
tx2 = (tex_width - priv->right) / tex_width;
|
||||
ty1 = priv->top / tex_height;
|
||||
ty2 = (tex_height - priv->bottom) / tex_height;
|
||||
|
||||
ex = width - priv->right;
|
||||
if (ex < 0)
|
||||
ex = priv->right; /* FIXME ? */
|
||||
|
||||
ey = height - priv->bottom;
|
||||
if (ey < 0)
|
||||
ey = priv->bottom; /* FIXME ? */
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (self);
|
||||
|
||||
/* Paint using the parent texture's material. It should already have
|
||||
the cogl texture set as the first layer */
|
||||
/* NB: for correct blending we need set a preumultiplied color here: */
|
||||
cogl_material_set_color4ub (cogl_material,
|
||||
opacity, opacity, opacity, opacity);
|
||||
cogl_set_source (cogl_material);
|
||||
|
||||
{
|
||||
GLfloat rectangles[] =
|
||||
{
|
||||
/* top left corner */
|
||||
0, 0, priv->left, priv->top,
|
||||
0.0, 0.0,
|
||||
tx1, ty1,
|
||||
|
||||
/* top middle */
|
||||
priv->left, 0, ex, priv->top,
|
||||
tx1, 0.0,
|
||||
tx2, ty1,
|
||||
|
||||
/* top right */
|
||||
ex, 0, width, priv->top,
|
||||
tx2, 0.0,
|
||||
1.0, ty1,
|
||||
|
||||
/* mid left */
|
||||
0, priv->top, priv->left, ey,
|
||||
0.0, ty1,
|
||||
tx1, ty2,
|
||||
|
||||
/* center */
|
||||
priv->left, priv->top, ex, ey,
|
||||
tx1, ty1,
|
||||
tx2, ty2,
|
||||
|
||||
/* mid right */
|
||||
ex, priv->top, width, ey,
|
||||
tx2, ty1,
|
||||
1.0, ty2,
|
||||
|
||||
/* bottom left */
|
||||
0, ey, priv->left, height,
|
||||
0.0, ty2,
|
||||
tx1, 1.0,
|
||||
|
||||
/* bottom center */
|
||||
priv->left, ey, ex, height,
|
||||
tx1, ty2,
|
||||
tx2, 1.0,
|
||||
|
||||
/* bottom right */
|
||||
ex, ey, width, height,
|
||||
tx2, ty2,
|
||||
1.0, 1.0
|
||||
};
|
||||
|
||||
cogl_rectangles_with_texture_coords (rectangles, 9);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
st_texture_frame_set_frame_internal (StTextureFrame *frame,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left)
|
||||
{
|
||||
StTextureFramePrivate *priv = frame->priv;
|
||||
GObject *gobject = G_OBJECT (frame);
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_object_freeze_notify (gobject);
|
||||
|
||||
if (priv->top != top)
|
||||
{
|
||||
priv->top = top;
|
||||
g_object_notify (gobject, "top");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->right != right)
|
||||
{
|
||||
priv->right = right;
|
||||
g_object_notify (gobject, "right");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->bottom != bottom)
|
||||
{
|
||||
priv->bottom = bottom;
|
||||
g_object_notify (gobject, "bottom");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (priv->left != left)
|
||||
{
|
||||
priv->left = left;
|
||||
g_object_notify (gobject, "left");
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
if (changed && CLUTTER_ACTOR_IS_VISIBLE (frame))
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (frame));
|
||||
|
||||
g_object_thaw_notify (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StTextureFrame *frame = ST_TEXTURE_FRAME (gobject);
|
||||
StTextureFramePrivate *priv = frame->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PARENT_TEXTURE:
|
||||
st_texture_frame_set_parent_texture (frame,
|
||||
g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_TOP:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
g_value_get_float (value),
|
||||
priv->right,
|
||||
priv->bottom,
|
||||
priv->left);
|
||||
break;
|
||||
|
||||
case PROP_RIGHT:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
priv->top,
|
||||
g_value_get_float (value),
|
||||
priv->bottom,
|
||||
priv->left);
|
||||
break;
|
||||
|
||||
case PROP_BOTTOM:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
priv->top,
|
||||
priv->right,
|
||||
g_value_get_float (value),
|
||||
priv->left);
|
||||
break;
|
||||
|
||||
case PROP_LEFT:
|
||||
st_texture_frame_set_frame_internal (frame,
|
||||
priv->top,
|
||||
priv->right,
|
||||
priv->bottom,
|
||||
g_value_get_float (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (gobject)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PARENT_TEXTURE:
|
||||
g_value_set_object (value, priv->parent_texture);
|
||||
break;
|
||||
|
||||
case PROP_LEFT:
|
||||
g_value_set_float (value, priv->left);
|
||||
break;
|
||||
|
||||
case PROP_TOP:
|
||||
g_value_set_float (value, priv->top);
|
||||
break;
|
||||
|
||||
case PROP_RIGHT:
|
||||
g_value_set_float (value, priv->right);
|
||||
break;
|
||||
|
||||
case PROP_BOTTOM:
|
||||
g_value_set_float (value, priv->bottom);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_dispose (GObject *gobject)
|
||||
{
|
||||
StTextureFramePrivate *priv = ST_TEXTURE_FRAME (gobject)->priv;
|
||||
|
||||
if (priv->parent_texture)
|
||||
{
|
||||
g_object_unref (priv->parent_texture);
|
||||
priv->parent_texture = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_texture_frame_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_class_init (StTextureFrameClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (StTextureFramePrivate));
|
||||
|
||||
actor_class->get_preferred_width =
|
||||
st_texture_frame_get_preferred_width;
|
||||
actor_class->get_preferred_height =
|
||||
st_texture_frame_get_preferred_height;
|
||||
actor_class->paint = st_texture_frame_paint;
|
||||
|
||||
gobject_class->set_property = st_texture_frame_set_property;
|
||||
gobject_class->get_property = st_texture_frame_get_property;
|
||||
gobject_class->dispose = st_texture_frame_dispose;
|
||||
|
||||
pspec = g_param_spec_object ("parent-texture",
|
||||
"Parent Texture",
|
||||
"The parent ClutterTexture",
|
||||
CLUTTER_TYPE_TEXTURE,
|
||||
ST_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT);
|
||||
g_object_class_install_property (gobject_class, PROP_PARENT_TEXTURE, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("left",
|
||||
"Left",
|
||||
"Left offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_LEFT, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("top",
|
||||
"Top",
|
||||
"Top offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_TOP, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("bottom",
|
||||
"Bottom",
|
||||
"Bottom offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_BOTTOM, pspec);
|
||||
|
||||
pspec = g_param_spec_float ("right",
|
||||
"Right",
|
||||
"Right offset",
|
||||
0, G_MAXFLOAT,
|
||||
0,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_RIGHT, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
st_texture_frame_init (StTextureFrame *self)
|
||||
{
|
||||
StTextureFramePrivate *priv;
|
||||
|
||||
self->priv = priv = ST_TEXTURE_FRAME_GET_PRIVATE (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_new:
|
||||
* @texture: a #ClutterTexture or %NULL
|
||||
* @left: left margin preserving its content
|
||||
* @top: top margin preserving its content
|
||||
* @right: right margin preserving its content
|
||||
* @bottom: bottom margin preserving its content
|
||||
*
|
||||
* A #StTextureFrame is a specialized texture that efficiently clones
|
||||
* an area of the given @texture while keeping preserving portions of the
|
||||
* same texture.
|
||||
*
|
||||
* A #StTextureFrame can be used to make a rectangular texture fit a
|
||||
* given size without stretching its borders.
|
||||
*
|
||||
* Return value: the newly created #StTextureFrame
|
||||
*/
|
||||
ClutterActor*
|
||||
st_texture_frame_new (ClutterTexture *texture,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left)
|
||||
{
|
||||
g_return_val_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture), NULL);
|
||||
|
||||
return g_object_new (ST_TYPE_TEXTURE_FRAME,
|
||||
"parent-texture", texture,
|
||||
"top", top,
|
||||
"right", right,
|
||||
"bottom", bottom,
|
||||
"left", left,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_get_parent_texture:
|
||||
* @frame: A #StTextureFrame
|
||||
*
|
||||
* Return the texture used by the #StTextureFrame
|
||||
*
|
||||
* Returns: a #ClutterTexture owned by the #StTextureFrame
|
||||
*/
|
||||
ClutterTexture *
|
||||
st_texture_frame_get_parent_texture (StTextureFrame *frame)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_TEXTURE_FRAME (frame), NULL);
|
||||
|
||||
return frame->priv->parent_texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_set_parent_texture:
|
||||
* @frame: A #StTextureFrame
|
||||
* @texture: A #ClutterTexture
|
||||
*
|
||||
* Set the #ClutterTexture used by this #StTextureFrame
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_texture_frame_set_parent_texture (StTextureFrame *frame,
|
||||
ClutterTexture *texture)
|
||||
{
|
||||
StTextureFramePrivate *priv;
|
||||
gboolean was_visible;
|
||||
|
||||
g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
|
||||
g_return_if_fail (texture == NULL || CLUTTER_IS_TEXTURE (texture));
|
||||
|
||||
priv = frame->priv;
|
||||
|
||||
was_visible = CLUTTER_ACTOR_IS_VISIBLE (frame);
|
||||
|
||||
if (priv->parent_texture == texture)
|
||||
return;
|
||||
|
||||
if (priv->parent_texture)
|
||||
{
|
||||
g_object_unref (priv->parent_texture);
|
||||
priv->parent_texture = NULL;
|
||||
|
||||
if (was_visible)
|
||||
clutter_actor_hide (CLUTTER_ACTOR (frame));
|
||||
}
|
||||
|
||||
if (texture)
|
||||
{
|
||||
priv->parent_texture = g_object_ref_sink (texture);
|
||||
|
||||
if (was_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->parent_texture))
|
||||
clutter_actor_show (CLUTTER_ACTOR (frame));
|
||||
}
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
|
||||
|
||||
g_object_notify (G_OBJECT (frame), "parent-texture");
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_set_frame:
|
||||
* @frame: A #StTextureFrame
|
||||
* @top: width of the top slice
|
||||
* @right: width of the right slice
|
||||
* @bottom: width of the bottom slice
|
||||
* @left: width of the left slice
|
||||
*
|
||||
* Set the slice lines of the specified frame. The slices are calculated as
|
||||
* widths from the edge of the frame.
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_texture_frame_set_frame (StTextureFrame *frame,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left)
|
||||
{
|
||||
g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
|
||||
|
||||
st_texture_frame_set_frame_internal (frame, top, right, bottom, left);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_frame_get_frame:
|
||||
* @frame: A #StTextureFrame
|
||||
* @top: width of the top slice
|
||||
* @right: width of the right slice
|
||||
* @bottom: width of the bottom slice
|
||||
* @left: width of the left slice
|
||||
*
|
||||
* Retrieve the current slice lines from the specified frame.
|
||||
*
|
||||
*/
|
||||
void
|
||||
st_texture_frame_get_frame (StTextureFrame *frame,
|
||||
gfloat *top,
|
||||
gfloat *right,
|
||||
gfloat *bottom,
|
||||
gfloat *left)
|
||||
{
|
||||
StTextureFramePrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_TEXTURE_FRAME (frame));
|
||||
|
||||
priv = frame->priv;
|
||||
|
||||
if (top)
|
||||
*top = priv->top;
|
||||
|
||||
if (right)
|
||||
*right = priv->right;
|
||||
|
||||
if (bottom)
|
||||
*bottom = priv->bottom;
|
||||
|
||||
if (left)
|
||||
*left = priv->left;
|
||||
}
|
93
src/st/st-texture-frame.h
Normal file
93
src/st/st-texture-frame.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* st-texture-frame.h: Expandible texture actor
|
||||
*
|
||||
* Copyright 2007, 2008 OpenedHand Ltd
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_TEXTURE_FRAME_H__
|
||||
#define __ST_TEXTURE_FRAME_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_TEXTURE_FRAME (st_texture_frame_get_type ())
|
||||
#define ST_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_TEXTURE_FRAME, StTextureFrame))
|
||||
#define ST_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_TEXTURE_FRAME, StTextureFrameClass))
|
||||
#define ST_IS_TEXTURE_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_TEXTURE_FRAME))
|
||||
#define ST_IS_TEXTURE_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_TEXTURE_FRAME))
|
||||
#define ST_TEXTURE_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_TEXTURE_FRAME, StTextureFrameClass))
|
||||
|
||||
typedef struct _StTextureFrame StTextureFrame;
|
||||
typedef struct _StTextureFramePrivate StTextureFramePrivate;
|
||||
typedef struct _StTextureFrameClass StTextureFrameClass;
|
||||
|
||||
/**
|
||||
* StTextureFrame:
|
||||
*
|
||||
* The contents of this structure are private and should only be accessed
|
||||
* through the public API.
|
||||
*/
|
||||
struct _StTextureFrame
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActor parent_instance;
|
||||
|
||||
StTextureFramePrivate *priv;
|
||||
};
|
||||
|
||||
struct _StTextureFrameClass
|
||||
{
|
||||
ClutterActorClass parent_class;
|
||||
|
||||
/* padding for future expansion */
|
||||
void (*_clutter_box_1) (void);
|
||||
void (*_clutter_box_2) (void);
|
||||
void (*_clutter_box_3) (void);
|
||||
void (*_clutter_box_4) (void);
|
||||
};
|
||||
|
||||
GType st_texture_frame_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor * st_texture_frame_new (ClutterTexture *texture,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left);
|
||||
void st_texture_frame_set_parent_texture (StTextureFrame *frame,
|
||||
ClutterTexture *texture);
|
||||
ClutterTexture *st_texture_frame_get_parent_texture (StTextureFrame *frame);
|
||||
void st_texture_frame_set_frame (StTextureFrame *frame,
|
||||
gfloat top,
|
||||
gfloat right,
|
||||
gfloat bottom,
|
||||
gfloat left);
|
||||
void st_texture_frame_get_frame (StTextureFrame *frame,
|
||||
gfloat *top,
|
||||
gfloat *right,
|
||||
gfloat *bottom,
|
||||
gfloat *left);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_TEXTURE_FRAME_H__ */
|
710
src/st/st-tooltip.c
Normal file
710
src/st/st-tooltip.c
Normal file
@ -0,0 +1,710 @@
|
||||
/*
|
||||
* st-tooltip.c: Plain tooltip actor
|
||||
*
|
||||
* Copyright 2008, 2009 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Written by: Thomas Wood <thomas@linux.intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-tooltip
|
||||
* @short_description: A tooltip widget
|
||||
*
|
||||
* #StTooltip implements a single tooltip. It should not normally be created
|
||||
* by the application but by the widget implementing tooltip capabilities, for
|
||||
* example, #st_button_set_tooltip().
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "st-tooltip.h"
|
||||
|
||||
#include "st-widget.h"
|
||||
#include "st-stylable.h"
|
||||
#include "st-private.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_LABEL,
|
||||
PROP_TIP_AREA
|
||||
};
|
||||
|
||||
#define ST_TOOLTIP_GET_PRIVATE(obj) \
|
||||
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_TOOLTIP, StTooltipPrivate))
|
||||
|
||||
struct _StTooltipPrivate
|
||||
{
|
||||
ClutterActor *label;
|
||||
|
||||
gfloat arrow_offset;
|
||||
gboolean actor_below;
|
||||
|
||||
ClutterGeometry *tip_area;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StTooltip, st_tooltip, ST_TYPE_WIDGET);
|
||||
|
||||
static void
|
||||
st_tooltip_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StTooltip *tooltip = ST_TOOLTIP (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LABEL:
|
||||
st_tooltip_set_label (tooltip, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_TIP_AREA:
|
||||
st_tooltip_set_tip_area (tooltip, g_value_get_boxed (value));
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StTooltipPrivate *priv = ST_TOOLTIP (gobject)->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_LABEL:
|
||||
g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->label)));
|
||||
break;
|
||||
|
||||
case PROP_TIP_AREA:
|
||||
g_value_set_boxed (value, priv->tip_area);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_style_changed (StWidget *self)
|
||||
{
|
||||
ClutterColor *color = NULL;
|
||||
StTooltipPrivate *priv;
|
||||
gchar *font_name;
|
||||
gchar *font_string;
|
||||
gint font_size;
|
||||
|
||||
priv = ST_TOOLTIP (self)->priv;
|
||||
|
||||
st_stylable_get (ST_STYLABLE (self),
|
||||
"color", &color,
|
||||
"font-family", &font_name,
|
||||
"font-size", &font_size,
|
||||
NULL);
|
||||
|
||||
if (color)
|
||||
{
|
||||
clutter_text_set_color (CLUTTER_TEXT (priv->label), color);
|
||||
clutter_color_free (color);
|
||||
}
|
||||
|
||||
if (font_name || font_size)
|
||||
{
|
||||
if (font_name && font_size)
|
||||
{
|
||||
font_string = g_strdup_printf ("%s %dpx", font_name, font_size);
|
||||
g_free (font_name);
|
||||
}
|
||||
else
|
||||
if (font_size)
|
||||
font_string = g_strdup_printf ("%dpx", font_size);
|
||||
else
|
||||
font_string = font_name;
|
||||
|
||||
clutter_text_set_font_name (CLUTTER_TEXT (priv->label), font_string);
|
||||
|
||||
g_free (font_string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_get_preferred_width (ClutterActor *self,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
|
||||
gfloat min_label_w, natural_label_w;
|
||||
gfloat label_height, arrow_height;
|
||||
ClutterActor *arrow_image;
|
||||
StPadding padding;
|
||||
|
||||
st_widget_get_padding (ST_WIDGET (self), &padding);
|
||||
|
||||
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
|
||||
if (arrow_image)
|
||||
{
|
||||
clutter_actor_get_preferred_height (arrow_image,
|
||||
-1,
|
||||
NULL,
|
||||
&arrow_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_height = 0;
|
||||
}
|
||||
|
||||
if (for_height > -1)
|
||||
{
|
||||
label_height = for_height - arrow_height - padding.top - padding.bottom;
|
||||
}
|
||||
else
|
||||
{
|
||||
label_height = -1;
|
||||
}
|
||||
|
||||
if (priv->label)
|
||||
{
|
||||
clutter_actor_get_preferred_width (priv->label,
|
||||
label_height,
|
||||
&min_label_w,
|
||||
&natural_label_w);
|
||||
}
|
||||
else
|
||||
{
|
||||
min_label_w = 0;
|
||||
natural_label_w = 0;
|
||||
}
|
||||
|
||||
|
||||
if (min_width_p)
|
||||
{
|
||||
*min_width_p = padding.left + padding.right + min_label_w;
|
||||
}
|
||||
|
||||
if (natural_width_p)
|
||||
{
|
||||
*natural_width_p = padding.left + padding.right + natural_label_w;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_get_preferred_height (ClutterActor *self,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
|
||||
gfloat arrow_height;
|
||||
gfloat min_label_h, natural_label_h;
|
||||
gfloat label_width;
|
||||
ClutterActor *arrow_image;
|
||||
StPadding padding;
|
||||
|
||||
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
|
||||
|
||||
if (arrow_image && !priv->actor_below)
|
||||
{
|
||||
clutter_actor_get_preferred_height (arrow_image,
|
||||
-1,
|
||||
NULL,
|
||||
&arrow_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_height = 0;
|
||||
}
|
||||
st_widget_get_padding (ST_WIDGET (self), &padding);
|
||||
|
||||
if (for_width > -1)
|
||||
{
|
||||
label_width = for_width - padding.left - padding.right;
|
||||
}
|
||||
else
|
||||
{
|
||||
label_width = -1;
|
||||
}
|
||||
|
||||
if (priv->label)
|
||||
{
|
||||
clutter_actor_get_preferred_height (priv->label,
|
||||
label_width,
|
||||
&min_label_h,
|
||||
&natural_label_h);
|
||||
}
|
||||
else
|
||||
{
|
||||
min_label_h = 0;
|
||||
natural_label_h = 0;
|
||||
}
|
||||
|
||||
if (min_height_p)
|
||||
{
|
||||
*min_height_p = padding.top + padding.bottom
|
||||
+ arrow_height + min_label_h;
|
||||
}
|
||||
|
||||
if (natural_height_p)
|
||||
{
|
||||
*natural_height_p = padding.top + padding.bottom
|
||||
+ arrow_height + natural_label_h;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
|
||||
ClutterActorBox child_box, arrow_box;
|
||||
gfloat arrow_height, arrow_width;
|
||||
ClutterActor *border_image, *arrow_image;
|
||||
StPadding padding;
|
||||
|
||||
CLUTTER_ACTOR_CLASS (st_tooltip_parent_class)->allocate (self,
|
||||
box,
|
||||
flags);
|
||||
|
||||
st_widget_get_padding (ST_WIDGET (self), &padding);
|
||||
|
||||
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
|
||||
|
||||
if (arrow_image && !priv->actor_below)
|
||||
{
|
||||
clutter_actor_get_preferred_height (arrow_image, -1, NULL, &arrow_height);
|
||||
clutter_actor_get_preferred_width (arrow_image, -1, NULL, &arrow_width);
|
||||
|
||||
arrow_box.x1 = (float)(priv->arrow_offset) - (int)(arrow_width / 2);
|
||||
arrow_box.y1 = 0;
|
||||
arrow_box.x2 = arrow_box.x1 + arrow_width;
|
||||
arrow_box.y2 = arrow_box.y1 + arrow_height;
|
||||
|
||||
clutter_actor_allocate (arrow_image, &arrow_box, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
arrow_height = 0;
|
||||
arrow_width = 0;
|
||||
}
|
||||
|
||||
child_box.x1 = child_box.y1 = 0;
|
||||
child_box.x2 = (box->x2 - box->x1);
|
||||
child_box.y2 = (box->y2 - box->y1);
|
||||
|
||||
/* remove the space that is used by the arrow */
|
||||
child_box.y1 += arrow_height;
|
||||
|
||||
border_image = st_widget_get_border_image (ST_WIDGET (self));
|
||||
if (border_image)
|
||||
clutter_actor_allocate (border_image, &child_box, flags);
|
||||
|
||||
if (priv->label)
|
||||
{
|
||||
/* now remove the padding */
|
||||
child_box.y1 += padding.top;
|
||||
child_box.x1 += padding.left;
|
||||
child_box.x2 -= padding.right;
|
||||
child_box.y2 -= padding.bottom;
|
||||
|
||||
clutter_actor_allocate (priv->label, &child_box, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
st_tooltip_paint (ClutterActor *self)
|
||||
{
|
||||
ClutterActor *border_image, *arrow_image;
|
||||
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
|
||||
|
||||
border_image = st_widget_get_border_image (ST_WIDGET (self));
|
||||
if (border_image)
|
||||
clutter_actor_paint (border_image);
|
||||
|
||||
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
|
||||
if (arrow_image && !priv->actor_below)
|
||||
clutter_actor_paint (arrow_image);
|
||||
|
||||
clutter_actor_paint (priv->label);
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_map (ClutterActor *self)
|
||||
{
|
||||
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
|
||||
ClutterActor *border_image, *arrow_image;
|
||||
|
||||
CLUTTER_ACTOR_CLASS (st_tooltip_parent_class)->map (self);
|
||||
|
||||
border_image = st_widget_get_border_image (ST_WIDGET (self));
|
||||
if (border_image)
|
||||
clutter_actor_map (border_image);
|
||||
|
||||
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
|
||||
if (arrow_image)
|
||||
clutter_actor_map (arrow_image);
|
||||
|
||||
clutter_actor_map (priv->label);
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_unmap (ClutterActor *self)
|
||||
{
|
||||
StTooltipPrivate *priv = ST_TOOLTIP (self)->priv;
|
||||
ClutterActor *border_image, *arrow_image;
|
||||
|
||||
CLUTTER_ACTOR_CLASS (st_tooltip_parent_class)->unmap (self);
|
||||
|
||||
border_image = st_widget_get_border_image (ST_WIDGET (self));
|
||||
if (border_image)
|
||||
clutter_actor_unmap (border_image);
|
||||
|
||||
arrow_image = st_widget_get_background_image (ST_WIDGET (self));
|
||||
if (arrow_image)
|
||||
clutter_actor_unmap (arrow_image);
|
||||
|
||||
clutter_actor_unmap (priv->label);
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_class_init (StTooltipClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
GParamSpec *pspec;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (StTooltipPrivate));
|
||||
|
||||
gobject_class->set_property = st_tooltip_set_property;
|
||||
gobject_class->get_property = st_tooltip_get_property;
|
||||
|
||||
actor_class->get_preferred_width = st_tooltip_get_preferred_width;
|
||||
actor_class->get_preferred_height = st_tooltip_get_preferred_height;
|
||||
actor_class->allocate = st_tooltip_allocate;
|
||||
actor_class->paint = st_tooltip_paint;
|
||||
actor_class->map = st_tooltip_map;
|
||||
actor_class->unmap = st_tooltip_unmap;
|
||||
|
||||
pspec = g_param_spec_string ("label",
|
||||
"Label",
|
||||
"Label of the tooltip",
|
||||
NULL, G_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_LABEL, pspec);
|
||||
|
||||
pspec = g_param_spec_boxed ("tip-area",
|
||||
"Tip Area",
|
||||
"Area on the stage the tooltip applies to",
|
||||
CLUTTER_TYPE_GEOMETRY,
|
||||
ST_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_TIP_AREA, pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_init (StTooltip *tooltip)
|
||||
{
|
||||
tooltip->priv = ST_TOOLTIP_GET_PRIVATE (tooltip);
|
||||
|
||||
tooltip->priv->label = g_object_new (CLUTTER_TYPE_TEXT,
|
||||
"line-alignment", PANGO_ALIGN_CENTER,
|
||||
"ellipsize", PANGO_ELLIPSIZE_END,
|
||||
"use-markup", TRUE,
|
||||
NULL);
|
||||
|
||||
tooltip->priv->tip_area = NULL;
|
||||
|
||||
clutter_actor_set_parent (CLUTTER_ACTOR (tooltip->priv->label),
|
||||
CLUTTER_ACTOR (tooltip));
|
||||
|
||||
g_object_set (tooltip, "show-on-set-parent", FALSE, NULL);
|
||||
|
||||
clutter_actor_set_reactive (CLUTTER_ACTOR (tooltip), FALSE);
|
||||
|
||||
g_signal_connect (tooltip, "style-changed",
|
||||
G_CALLBACK (st_tooltip_style_changed), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_update_position (StTooltip *tooltip)
|
||||
{
|
||||
StTooltipPrivate *priv = tooltip->priv;
|
||||
ClutterGeometry *tip_area = tooltip->priv->tip_area;
|
||||
gfloat tooltip_w, tooltip_h, tooltip_x, tooltip_y;
|
||||
gfloat stage_w, stage_h;
|
||||
ClutterActor *stage;
|
||||
|
||||
/* ensure the tooltip with is not fixed size */
|
||||
clutter_actor_set_size ((ClutterActor*) tooltip, -1, -1);
|
||||
|
||||
/* if no area set, just position ourselves top left */
|
||||
if (!priv->tip_area)
|
||||
{
|
||||
clutter_actor_set_position ((ClutterActor*) tooltip, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we need to have a style in case there are padding values to take into
|
||||
* account when calculating width/height */
|
||||
st_widget_ensure_style ((StWidget *) tooltip);
|
||||
|
||||
/* find out the tooltip's size */
|
||||
clutter_actor_get_size ((ClutterActor*) tooltip, &tooltip_w, &tooltip_h);
|
||||
|
||||
/* attempt to place the tooltip */
|
||||
tooltip_x = (int)(tip_area->x + (tip_area->width / 2) - (tooltip_w / 2));
|
||||
tooltip_y = (int)(tip_area->y + tip_area->height);
|
||||
|
||||
stage = clutter_actor_get_stage ((ClutterActor *) tooltip);
|
||||
if (!stage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
clutter_actor_get_size (stage, &stage_w, &stage_h);
|
||||
|
||||
/* make sure the tooltip is not off screen vertically */
|
||||
if (tooltip_w > stage_w)
|
||||
{
|
||||
tooltip_x = 0;
|
||||
clutter_actor_set_width ((ClutterActor*) tooltip, stage_w);
|
||||
}
|
||||
else if (tooltip_x < 0)
|
||||
{
|
||||
tooltip_x = 0;
|
||||
}
|
||||
else if (tooltip_x + tooltip_w > stage_w)
|
||||
{
|
||||
tooltip_x = (int)(stage_w) - tooltip_w;
|
||||
}
|
||||
|
||||
/* make sure the tooltip is not off screen horizontally */
|
||||
if (tooltip_y + tooltip_h > stage_h)
|
||||
{
|
||||
priv->actor_below = TRUE;
|
||||
|
||||
/* re-query size as may have changed */
|
||||
clutter_actor_get_preferred_height ((ClutterActor*) tooltip,
|
||||
-1, NULL, &tooltip_h);
|
||||
tooltip_y = tip_area->y - tooltip_h;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->actor_below = FALSE;
|
||||
}
|
||||
|
||||
/* calculate the arrow offset */
|
||||
priv->arrow_offset = tip_area->x + tip_area->width / 2 - tooltip_x;
|
||||
|
||||
clutter_actor_set_position ((ClutterActor*) tooltip, tooltip_x, tooltip_y);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_tooltip_get_label:
|
||||
* @tooltip: a #StTooltip
|
||||
*
|
||||
* Get the text displayed on the tooltip
|
||||
*
|
||||
* Returns: the text for the tooltip. This must not be freed by the application
|
||||
*/
|
||||
G_CONST_RETURN gchar *
|
||||
st_tooltip_get_label (StTooltip *tooltip)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_TOOLTIP (tooltip), NULL);
|
||||
|
||||
return clutter_text_get_text (CLUTTER_TEXT (tooltip->priv->label));
|
||||
}
|
||||
|
||||
/**
|
||||
* st_tooltip_set_label:
|
||||
* @tooltip: a #StTooltip
|
||||
* @text: text to set the label to
|
||||
*
|
||||
* Sets the text displayed on the tooltip
|
||||
*/
|
||||
void
|
||||
st_tooltip_set_label (StTooltip *tooltip,
|
||||
const gchar *text)
|
||||
{
|
||||
StTooltipPrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_TOOLTIP (tooltip));
|
||||
|
||||
priv = tooltip->priv;
|
||||
|
||||
clutter_text_set_text (CLUTTER_TEXT (priv->label), text);
|
||||
|
||||
g_object_notify (G_OBJECT (tooltip), "label");
|
||||
}
|
||||
|
||||
/**
|
||||
* st_tooltip_show:
|
||||
* @tooltip: a #StTooltip
|
||||
*
|
||||
* Show the tooltip relative to the associated widget.
|
||||
*/
|
||||
void
|
||||
st_tooltip_show (StTooltip *tooltip)
|
||||
{
|
||||
StTooltipPrivate *priv;
|
||||
ClutterActor *parent;
|
||||
ClutterActor *stage;
|
||||
ClutterActor *self = CLUTTER_ACTOR (tooltip);
|
||||
ClutterAnimation *animation;
|
||||
|
||||
/* make sure we're not currently already animating (e.g. hiding) */
|
||||
animation = clutter_actor_get_animation (CLUTTER_ACTOR (tooltip));
|
||||
if (animation)
|
||||
clutter_animation_completed (animation);
|
||||
|
||||
priv = tooltip->priv;
|
||||
parent = clutter_actor_get_parent (self);
|
||||
stage = clutter_actor_get_stage (self);
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
g_warning ("StTooltip is not on any stage.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure we're parented on the stage */
|
||||
if (G_UNLIKELY (parent != stage))
|
||||
{
|
||||
g_object_ref (self);
|
||||
clutter_actor_unparent (self);
|
||||
clutter_actor_set_parent (self, stage);
|
||||
g_object_unref (self);
|
||||
parent = stage;
|
||||
}
|
||||
|
||||
/* raise the tooltip to the top */
|
||||
clutter_container_raise_child (CLUTTER_CONTAINER (stage),
|
||||
CLUTTER_ACTOR (tooltip),
|
||||
NULL);
|
||||
|
||||
st_tooltip_update_position (tooltip);
|
||||
|
||||
/* finally show the tooltip... */
|
||||
CLUTTER_ACTOR_CLASS (st_tooltip_parent_class)->show (self);
|
||||
|
||||
/* and give it some bounce! */
|
||||
g_object_set (G_OBJECT (self),
|
||||
"scale-center-x", priv->arrow_offset,
|
||||
"scale-center-y", (priv->actor_below) ? clutter_actor_get_height (self) : 0,
|
||||
NULL);
|
||||
clutter_actor_set_scale (self, 0.0, 0.0);
|
||||
clutter_actor_animate (self, CLUTTER_EASE_OUT_ELASTIC,
|
||||
500,
|
||||
"scale-x", 1.0,
|
||||
"scale-y", 1.0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
st_tooltip_hide_complete (ClutterAnimation *animation,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
CLUTTER_ACTOR_CLASS (st_tooltip_parent_class)->hide (actor);
|
||||
g_signal_handlers_disconnect_by_func (actor,
|
||||
st_tooltip_hide_complete,
|
||||
actor);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_tooltip_hide:
|
||||
* @tooltip: a #StTooltip
|
||||
*
|
||||
* Hide the tooltip
|
||||
*/
|
||||
void
|
||||
st_tooltip_hide (StTooltip *tooltip)
|
||||
{
|
||||
ClutterAnimation *animation;
|
||||
|
||||
g_return_if_fail (ST_TOOLTIP (tooltip));
|
||||
|
||||
/* make sure we're not currently already animating (e.g. hiding) */
|
||||
animation = clutter_actor_get_animation (CLUTTER_ACTOR (tooltip));
|
||||
if (animation)
|
||||
clutter_animation_completed (animation);
|
||||
|
||||
g_object_set (G_OBJECT (tooltip),
|
||||
"scale-center-x", tooltip->priv->arrow_offset,
|
||||
NULL);
|
||||
animation =
|
||||
clutter_actor_animate (CLUTTER_ACTOR (tooltip), CLUTTER_EASE_IN_SINE,
|
||||
150,
|
||||
"scale-x", 0.0,
|
||||
"scale-y", 0.0,
|
||||
NULL);
|
||||
g_signal_connect (animation, "completed",
|
||||
G_CALLBACK (st_tooltip_hide_complete), tooltip);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_tooltip_set_tip_area:
|
||||
* @tooltip: A #StTooltip
|
||||
* @area: A #ClutterGeometry
|
||||
*
|
||||
* Set the area on the stage that the tooltip applies to.
|
||||
*/
|
||||
void
|
||||
st_tooltip_set_tip_area (StTooltip *tooltip,
|
||||
const ClutterGeometry *area)
|
||||
{
|
||||
g_return_if_fail (ST_IS_TOOLTIP (tooltip));
|
||||
|
||||
if (tooltip->priv->tip_area)
|
||||
g_boxed_free (CLUTTER_TYPE_GEOMETRY, tooltip->priv->tip_area);
|
||||
tooltip->priv->tip_area = g_boxed_copy (CLUTTER_TYPE_GEOMETRY, area);
|
||||
|
||||
st_tooltip_update_position (tooltip);
|
||||
}
|
||||
|
||||
/**
|
||||
* st_tooltip_get_tip_area:
|
||||
* @tooltip: A #StTooltip
|
||||
*
|
||||
* Retrieve the area on the stage that the tooltip currently applies to
|
||||
*
|
||||
* Returns: the #ClutterGeometry, owned by the tooltip which must not be freed
|
||||
* by the application.
|
||||
*/
|
||||
G_CONST_RETURN ClutterGeometry*
|
||||
st_tooltip_get_tip_area (StTooltip *tooltip)
|
||||
{
|
||||
g_return_val_if_fail (ST_IS_TOOLTIP (tooltip), NULL);
|
||||
|
||||
return tooltip->priv->tip_area;
|
||||
}
|
80
src/st/st-tooltip.h
Normal file
80
src/st/st-tooltip.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* st-tooltip.h: Plain tooltip actor
|
||||
*
|
||||
* Copyright 2008, 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Written by: Thomas Wood <thomas@linux.intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_TOOLTIP_H__
|
||||
#define __ST_TOOLTIP_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#include <st/st-bin.h>
|
||||
|
||||
#define ST_TYPE_TOOLTIP (st_tooltip_get_type ())
|
||||
#define ST_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_TOOLTIP, StTooltip))
|
||||
#define ST_IS_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_TOOLTIP))
|
||||
#define ST_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_TOOLTIP, StTooltipClass))
|
||||
#define ST_IS_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_TOOLTIP))
|
||||
#define ST_TOOLTIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_TOOLTIP, StTooltipClass))
|
||||
|
||||
typedef struct _StTooltip StTooltip;
|
||||
typedef struct _StTooltipPrivate StTooltipPrivate;
|
||||
typedef struct _StTooltipClass StTooltipClass;
|
||||
|
||||
/**
|
||||
* StTooltip:
|
||||
*
|
||||
* The contents of this structure is private and should only be accessed using
|
||||
* the provided API.
|
||||
*/
|
||||
struct _StTooltip
|
||||
{
|
||||
/*< private >*/
|
||||
StBin parent_instance;
|
||||
|
||||
StTooltipPrivate *priv;
|
||||
};
|
||||
|
||||
struct _StTooltipClass
|
||||
{
|
||||
StBinClass parent_class;
|
||||
};
|
||||
|
||||
GType st_tooltip_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_CONST_RETURN gchar *st_tooltip_get_label (StTooltip *tooltip);
|
||||
void st_tooltip_set_label (StTooltip *tooltip,
|
||||
const gchar *text);
|
||||
void st_tooltip_show (StTooltip *tooltip);
|
||||
void st_tooltip_hide (StTooltip *tooltip);
|
||||
|
||||
void st_tooltip_set_tip_area (StTooltip *tooltip,
|
||||
const ClutterGeometry *area);
|
||||
G_CONST_RETURN ClutterGeometry* st_tooltip_get_tip_area (StTooltip *tooltip);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_TOOLTIP_H__ */
|
73
src/st/st-types.h
Normal file
73
src/st/st-types.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:st-types
|
||||
* @short_description: type definitions used throughout St
|
||||
*
|
||||
* Common types for StWidgets.
|
||||
*/
|
||||
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_TYPES_H__
|
||||
#define __ST_TYPES_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_BORDER_IMAGE (st_border_image_get_type ())
|
||||
#define ST_TYPE_PADDING (st_padding_get_type ())
|
||||
|
||||
typedef struct _StPadding StPadding;
|
||||
|
||||
GType st_border_image_get_type (void) G_GNUC_CONST;
|
||||
|
||||
/**
|
||||
* StPadding:
|
||||
* @top: padding from the top
|
||||
* @right: padding from the right
|
||||
* @bottom: padding from the bottom
|
||||
* @left: padding from the left
|
||||
*
|
||||
* The padding from the internal border of the parent container.
|
||||
*/
|
||||
struct _StPadding
|
||||
{
|
||||
gfloat top;
|
||||
gfloat right;
|
||||
gfloat bottom;
|
||||
gfloat left;
|
||||
};
|
||||
|
||||
GType st_padding_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum {
|
||||
ST_ALIGN_START,
|
||||
ST_ALIGN_MIDDLE,
|
||||
ST_ALIGN_END
|
||||
} StAlign;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_TYPES_H__ */
|
1357
src/st/st-widget.c
Normal file
1357
src/st/st-widget.c
Normal file
File diff suppressed because it is too large
Load Diff
108
src/st/st-widget.h
Normal file
108
src/st/st-widget.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* st-widget.h: Base class for St actors
|
||||
*
|
||||
* Copyright 2007 OpenedHand
|
||||
* Copyright 2008, 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||
#error "Only <st/st.h> can be included directly.h"
|
||||
#endif
|
||||
|
||||
#ifndef __ST_WIDGET_H__
|
||||
#define __ST_WIDGET_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <st/st-types.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_WIDGET (st_widget_get_type ())
|
||||
#define ST_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_WIDGET, StWidget))
|
||||
#define ST_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_WIDGET))
|
||||
#define ST_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_WIDGET, StWidgetClass))
|
||||
#define ST_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_WIDGET))
|
||||
#define ST_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_WIDGET, StWidgetClass))
|
||||
|
||||
typedef struct _StWidget StWidget;
|
||||
typedef struct _StWidgetPrivate StWidgetPrivate;
|
||||
typedef struct _StWidgetClass StWidgetClass;
|
||||
|
||||
/**
|
||||
* StWidget:
|
||||
*
|
||||
* Base class for stylable actors. The contents of the #StWidget
|
||||
* structure are private and should only be accessed through the
|
||||
* public API.
|
||||
*/
|
||||
struct _StWidget
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActor parent_instance;
|
||||
|
||||
StWidgetPrivate *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* StWidgetClass:
|
||||
*
|
||||
* Base class for stylable actors.
|
||||
*/
|
||||
struct _StWidgetClass
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterActorClass parent_class;
|
||||
|
||||
/* vfuncs */
|
||||
void (* draw_background) (StWidget *self,
|
||||
ClutterActor *background,
|
||||
const ClutterColor *color);
|
||||
};
|
||||
|
||||
GType st_widget_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void st_widget_set_style_pseudo_class (StWidget *actor,
|
||||
const gchar *pseudo_class);
|
||||
G_CONST_RETURN gchar *st_widget_get_style_pseudo_class (StWidget *actor);
|
||||
void st_widget_set_style_class_name (StWidget *actor,
|
||||
const gchar *style_class);
|
||||
G_CONST_RETURN gchar *st_widget_get_style_class_name (StWidget *actor);
|
||||
|
||||
void st_widget_set_has_tooltip (StWidget *widget,
|
||||
gboolean has_tooltip);
|
||||
gboolean st_widget_get_has_tooltip (StWidget *widget);
|
||||
void st_widget_set_tooltip_text (StWidget *widget,
|
||||
const gchar *text);
|
||||
const gchar* st_widget_get_tooltip_text (StWidget *widget);
|
||||
|
||||
void st_widget_show_tooltip (StWidget *widget);
|
||||
void st_widget_hide_tooltip (StWidget *widget);
|
||||
|
||||
void st_widget_ensure_style (StWidget *widget);
|
||||
|
||||
|
||||
/* Only to be used by sub-classes of StWidget */
|
||||
ClutterActor *st_widget_get_background_image (StWidget *actor);
|
||||
ClutterActor *st_widget_get_border_image (StWidget *actor);
|
||||
void st_widget_get_padding (StWidget *widget,
|
||||
StPadding *padding);
|
||||
void st_widget_draw_background (StWidget *widget);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_WIDGET_H__ */
|
Loading…
Reference in New Issue
Block a user