Import Big

We want this for the BigBox primarily; rounded corners, etc.

http://bugzilla.gnome.org/show_bug.cgi?id=562923

svn path=/trunk/; revision=103
This commit is contained in:
Colin Walters 2008-12-01 23:01:52 +00:00
parent a8cfd47a50
commit 25116779f9
12 changed files with 4740 additions and 5 deletions

View File

@ -18,6 +18,7 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 metacity-plugins gjs-gi-1.0)
PKG_CHECK_MODULES(TIDY, clutter-0.8)
PKG_CHECK_MODULES(BIG, clutter-cairo-0.8 gtk+-2.0 librsvg-2.0)
PKG_CHECK_MODULES(TRAY, gtk+-2.0)
# Sets GLIB_GENMARSHAL and GLIB_MKENUMS

67
src/Makefile-big.am Normal file
View File

@ -0,0 +1,67 @@
big_cflags = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
-DLIBDIR=\""$(libdir)"\" \
-DG_DISABLE_DEPRECATED \
-DG_LOG_DOMAIN=\"Big\" \
$(BIG_CFLAGS) \
$(NULL)
big_built_sources = \
big-enum-types.h \
big-enum-types.c \
$(NULL)
BUILT_SOURCES += $(big_built_sources)
BIG_STAMP_FILES = stamp-big-marshal.h stamp-big-enum-types.h
# please, keep this sorted alphabetically
big_source_h = \
big/box.h \
big/rectangle.h \
big/theme-image.h \
$(NULL)
# please, keep this sorted alphabetically
big_source_c = \
big/box.c \
big/rectangle.c \
big/theme-image.c \
$(NULL)
big-enum-types.h: stamp-big-enum-types.h Makefile
@true
stamp-big-enum-types.h: $(big_source_h) big/big-enum-types.h.in
( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/big/big-enum-types.h.in \
$(big_source_h) ) >> xgen-teth && \
(cmp xgen-teth big-enum-types.h || cp xgen-teth big-enum-types.h) && \
rm -f xgen-teth && \
echo timestamp > $(@F)
big-enum-types.c: stamp-big-enum-types.h big/big-enum-types.c.in
( cd $(srcdir) && \
$(GLIB_MKENUMS) \
--template $(srcdir)/big/big-enum-types.c.in \
$(big_source_h) ) >> xgen-tetc && \
cp xgen-tetc big-enum-types.c && \
rm -f xgen-tetc
noinst_LTLIBRARIES += libbig-1.0.la
libbig_1_0_la_LIBADD = $(BIG_LIBS)
libbig_1_0_la_SOURCES = \
$(big_source_c) \
$(big_source_h) \
$(big_built_sources) \
$(NULL)
libbig_1_0_la_CPPFLAGS = $(big_cflags)
libbig_1_0_la_LDFLAGS = $(LDADD)
CLEANFILES += $(BIG_STAMP_FILES) $(BUILT_SOURCES)
EXTRA_DIST += \
big/big-enum-types.h.in \
big/big-enum-types.c.in

View File

@ -1,5 +1,3 @@
NULL =
tidy_cflags = \
-I$(top_srcdir)/src \
-DPREFIX=\""$(prefix)"\" \
@ -85,7 +83,7 @@ tidy-enum-types.c: stamp-tidy-enum-types.h tidy/tidy-enum-types.c.in
cp xgen-tetc tidy-enum-types.c && \
rm -f xgen-tetc
noinst_LTLIBRARIES = libtidy-1.0.la
noinst_LTLIBRARIES += libtidy-1.0.la
libtidy_1_0_la_LIBADD = $(TIDY_LIBS)
libtidy_1_0_la_SOURCES = \
@ -99,7 +97,7 @@ libtidy_1_0_la_LDFLAGS = $(LDADD)
CLEANFILES += $(TIDY_STAMP_FILES) $(BUILT_SOURCES)
EXTRA_DIST = \
EXTRA_DIST += \
tidy/tidy-enum-types.h.in \
tidy/tidy-enum-types.c.in \
tidy/tidy-private.h \

View File

@ -1,7 +1,11 @@
NULL =
BUILT_SOURCES =
CLEANFILES =
EXTRA_DIST =
noinst_LTLIBRARIES =
include Makefile-tidy.am
include Makefile-big.am
include Makefile-tray.am
gnome_shell_cflags = \
@ -60,12 +64,13 @@ shell-marshal.c: Makefile shell-marshal.list
libgnome_shell_la_LDFLAGS = -avoid-version -module
libgnome_shell_la_LIBADD = \
$(MUTTER_PLUGIN_LIBS) \
libbig-1.0.la \
libtidy-1.0.la \
libtray.la
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
typelibdir = $(pkglibdir)
typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib
typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib Big-1.0.typelib
Shell-0.1.gir: $(metacity) $(G_IR_SCANNER) libgnome-shell.la Makefile
$(G_IR_SCANNER) \
@ -103,3 +108,20 @@ CLEANFILES += Tidy-1.0.gir
Tidy-1.0.typelib: libtidy-1.0.la Tidy-1.0.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Tidy-1.0.gir -o $@
CLEANFILES += Tidy-1.0.typelib
Big-1.0.gir: $(metacity) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
$(G_IR_SCANNER) \
--namespace=Big \
--nsversion=1.0 \
--include=ClutterCairo-0.8 \
--program=metacity \
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
$(big_source_h) \
$(big_source_c) \
$(big_cflags) \
-o $@
CLEANFILES += Big-1.0.gir
Big-1.0.typelib: libbig-1.0.la Big-1.0.gir
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Big-1.0.gir -o $@
CLEANFILES += Big-1.0.typelib

View File

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

View File

@ -0,0 +1,25 @@
/*** BEGIN file-header ***/
#ifndef __BIG_ENUM_TYPES_H__
#define __BIG_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 /* !__BIG_ENUM_TYPES_H__ */
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define BIG_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/

3050
src/big/box.c Normal file

File diff suppressed because it is too large Load Diff

129
src/big/box.h Normal file
View File

@ -0,0 +1,129 @@
/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* big-box.h: Box container.
Copyright (C) 2006-2008 Red Hat, Inc.
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __BIG_BOX_H__
#define __BIG_BOX_H__
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define BIG_TYPE_BOX (big_box_get_type ())
#define BIG_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BIG_TYPE_BOX, BigBox))
#define BIG_IS_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BIG_TYPE_BOX))
#define BIG_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BIG_TYPE_BOX, BigBoxClass))
#define BIG_IS_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BIG_TYPE_BOX))
#define BIG_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BIG_TYPE_BOX, BigBoxClass))
typedef struct _BigBox BigBox;
typedef struct _BigBoxPrivate BigBoxPrivate;
typedef struct _BigBoxClass BigBoxClass;
typedef enum
{
BIG_BOX_PACK_NONE = 0,
BIG_BOX_PACK_EXPAND = 1 << 0,
BIG_BOX_PACK_END = 1 << 1,
BIG_BOX_PACK_IF_FITS = 1 << 2,
BIG_BOX_PACK_FIXED = 1 << 3,
BIG_BOX_PACK_ALLOCATE_WHEN_HIDDEN = 1 << 4
} BigBoxPackFlags;
typedef enum
{
BIG_BOX_ALIGNMENT_FIXED = 0,
BIG_BOX_ALIGNMENT_FILL = 1,
BIG_BOX_ALIGNMENT_START = 2,
BIG_BOX_ALIGNMENT_END = 3,
BIG_BOX_ALIGNMENT_CENTER = 4
} BigBoxAlignment;
typedef enum
{
BIG_BOX_ORIENTATION_VERTICAL = 1,
BIG_BOX_ORIENTATION_HORIZONTAL = 2
} BigBoxOrientation;
typedef enum
{
BIG_BOX_BACKGROUND_REPEAT_NONE = 0,
BIG_BOX_BACKGROUND_REPEAT_X = 1,
BIG_BOX_BACKGROUND_REPEAT_Y = 2,
BIG_BOX_BACKGROUND_REPEAT_BOTH = 3,
} BigBoxBackgroundRepeat;
struct _BigBox
{
ClutterActor parent_instance;
BigBoxPrivate *priv;
};
struct _BigBoxClass
{
ClutterActorClass parent_class;
};
GType big_box_get_type (void) G_GNUC_CONST;
ClutterActor *big_box_new (BigBoxOrientation orientation);
void big_box_prepend (BigBox *box,
ClutterActor *child,
BigBoxPackFlags flags);
void big_box_append (BigBox *box,
ClutterActor *child,
BigBoxPackFlags flags);
gboolean big_box_is_empty (BigBox *box);
void big_box_remove_all (BigBox *box);
void big_box_insert_after (BigBox *box,
ClutterActor *child,
ClutterActor *ref_child,
BigBoxPackFlags flags);
void big_box_insert_before (BigBox *box,
ClutterActor *child,
ClutterActor *ref_child,
BigBoxPackFlags flags);
void big_box_set_child_packing (BigBox *box,
ClutterActor *child,
BigBoxPackFlags flags);
void big_box_set_child_align (BigBox *box,
ClutterActor *child,
BigBoxAlignment fixed_x_align,
BigBoxAlignment fixed_y_align);
void big_box_set_padding (BigBox *box,
int padding);
void big_box_set_border_width (BigBox *box,
int border_width);
G_END_DECLS
#endif /* __BIG_BOX_H__ */

537
src/big/rectangle.c Normal file
View File

@ -0,0 +1,537 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* rectangle.c: Rounded rectangle.
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <math.h>
#include <glib.h>
#include <clutter/clutter.h>
#include <cogl/cogl.h>
#include <cairo/cairo.h>
#include "rectangle.h"
typedef struct {
gint ref_count;
ClutterColor color;
ClutterColor border_color;
int radius;
int border_width;
CoglHandle texture;
guint8 *data;
} Corner;
struct BigRectangle {
ClutterRectangle parent_instance;
ClutterUnit radius;
Corner *corner;
gboolean corners_dirty;
};
/* map of { radius, border_width, border_color, color } to Corner textures */
static GHashTable *all_corners = NULL;
struct BigRectangleClass {
ClutterRectangleClass parent_class;
};
G_DEFINE_TYPE(BigRectangle, big_rectangle, CLUTTER_TYPE_RECTANGLE)
enum
{
PROP_0,
PROP_CORNER_RADIUS
};
static gboolean
corner_equal(gconstpointer a,
gconstpointer b)
{
const Corner *corner_a;
const Corner *corner_b;
corner_a = a;
corner_b = b;
return *((guint32 *)&corner_a->color) == *((guint32 *)&corner_b->color) &&
*((guint32 *)&corner_a->border_color) == *((guint32 *)&corner_b->border_color) &&
corner_a->border_width == corner_b->border_width &&
corner_a->radius == corner_b->radius;
}
static guint
corner_hash(gconstpointer key)
{
const Corner *corner;
guint hashed[4];
corner = key;
hashed[0] = *((guint *)&(corner->color));
hashed[1] = *((guint *)&(corner->border_color));
hashed[2] = *((guint *)&(corner->border_width));
hashed[3] = *((guint *)&(corner->radius));
return hashed[0] ^ hashed[1] ^ hashed[2] ^ hashed[3];
}
static Corner *
create_corner_texture(Corner *src)
{
Corner *corner;
CoglHandle texture;
cairo_t *cr;
cairo_surface_t *surface;
guint x, y;
guint rowstride;
guint8 *data;
guint32 *src_p;
guint8 *dst_p;
guint size;
corner = g_memdup(src, sizeof(Corner));
size = 2 * MAX(corner->border_width, corner->radius);
rowstride = size * 4;
data = g_new0(guint8, size * rowstride);
surface = cairo_image_surface_create_for_data(data,
CAIRO_FORMAT_ARGB32,
size, size,
rowstride);
cr = cairo_create(surface);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_scale(cr, size, size);
if (corner->border_width < corner->radius) {
double internal_radius = 0.5 * (1.0 - (double) corner->border_width / corner->radius);
if (corner->border_width != 0) {
cairo_set_source_rgba(cr,
(double)corner->border_color.red / G_MAXUINT8,
(double)corner->border_color.green / G_MAXUINT8,
(double)corner->border_color.blue / G_MAXUINT8,
(double)corner->border_color.alpha / G_MAXUINT8);
cairo_arc(cr, 0.5, 0.5, 0.5, 0, 2 * M_PI);
cairo_fill(cr);
}
cairo_set_source_rgba(cr,
(double)corner->color.red / G_MAXUINT8,
(double)corner->color.green / G_MAXUINT8,
(double)corner->color.blue / G_MAXUINT8,
(double)corner->color.alpha / G_MAXUINT8);
cairo_arc(cr, 0.5, 0.5, internal_radius, 0, 2 * M_PI);
cairo_fill(cr);
} else {
double radius;
radius = (gdouble)corner->radius / corner->border_width;
cairo_set_source_rgba(cr,
(double)corner->border_color.red / G_MAXUINT8,
(double)corner->border_color.green / G_MAXUINT8,
(double)corner->border_color.blue / G_MAXUINT8,
(double)corner->border_color.alpha / G_MAXUINT8);
cairo_arc(cr, radius, radius, radius, M_PI, 3 * M_PI / 2);
cairo_line_to(cr, 1.0 - radius, 0.0);
cairo_arc(cr, 1.0 - radius, radius, radius, 3 * M_PI / 2, 2*M_PI);
cairo_line_to(cr, 1.0, 1.0 - radius);
cairo_arc(cr, 1.0 - radius, 1.0 - radius, radius, 0, M_PI / 2);
cairo_line_to(cr, radius, 1.0);
cairo_arc(cr, radius, 1.0 - radius, radius, M_PI / 2, M_PI);
cairo_fill(cr);
}
cairo_destroy(cr);
cairo_surface_destroy(surface);
corner->data = g_new0(guint8, size * rowstride);
/* cogl doesn't seem to support the conversion, do it manually */
/* borrowed from clutter-cairo, conversion from ARGB pre-multiplied
* to RGBA */
for (y = 0; y < size; y++) {
src_p = (guint32 *) (data + y * rowstride);
dst_p = corner->data + y * rowstride;
for (x = 0; x < size; x++) {
guint8 alpha = (*src_p >> 24) & 0xff;
if (alpha == 0) {
dst_p[0] = dst_p[1] = dst_p[2] = dst_p[3] = alpha;
} else {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
dst_p[0] = (((*src_p >> 16) & 0xff) * 255 ) / alpha;
dst_p[1] = (((*src_p >> 8) & 0xff) * 255 ) / alpha;
dst_p[2] = (((*src_p >> 0) & 0xff) * 255 ) / alpha;
dst_p[3] = alpha;
#elif G_BYTE_ORDER == G_BIG_ENDIAN
dst_p[0] = alpha;
dst_p[1] = (((*src_p >> 0) & 0xff) * 255 ) / alpha;
dst_p[2] = (((*src_p >> 8) & 0xff) * 255 ) / alpha;
dst_p[3] = (((*src_p >> 16) & 0xff) * 255 ) / alpha;
#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
#error unknown ENDIAN type
#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
}
dst_p += 4;
src_p++;
}
}
g_free(data);
texture = cogl_texture_new_from_data(size, size,
0,
FALSE,
COGL_PIXEL_FORMAT_RGBA_8888,
COGL_PIXEL_FORMAT_ANY,
rowstride,
corner->data);
g_assert(texture != COGL_INVALID_HANDLE);
corner->ref_count = 1;
corner->texture = texture;
g_hash_table_insert(all_corners, corner, corner);
return corner;
}
static void
corner_unref(Corner *corner)
{
corner->ref_count --;
if (corner->ref_count == 0) {
g_hash_table_remove(all_corners, corner);
cogl_texture_unref(corner->texture);
g_free(corner->data);
g_free(corner);
}
}
static Corner *
corner_get(guint radius,
ClutterColor *color,
guint border_width,
ClutterColor *border_color)
{
Corner key;
Corner *corner;
if (all_corners == NULL) {
all_corners = g_hash_table_new(corner_hash, corner_equal);
}
key.radius = radius;
key.color = *color;
key.border_color = *border_color;
key.border_width = border_width;
corner = g_hash_table_lookup(all_corners, &key);
if (!corner) {
corner = create_corner_texture(&key);
} else {
corner->ref_count ++;
}
return corner;
}
static void
big_rectangle_update_corners(BigRectangle *rectangle)
{
Corner *corner;
corner = NULL;
if (rectangle->radius != 0) {
ClutterColor *color;
ClutterColor *border_color;
guint border_width;
g_object_get(rectangle,
"border-color", &border_color,
"border-width", &border_width,
"color", &color,
NULL);
corner = corner_get(CLUTTER_UNITS_TO_DEVICE(rectangle->radius),
color,
border_width,
border_color);
clutter_color_free(border_color);
clutter_color_free(color);
}
if (rectangle->corner) {
corner_unref(rectangle->corner);
}
rectangle->corner = corner;
rectangle->corners_dirty = FALSE;
}
static void
big_rectangle_paint(ClutterActor *actor)
{
BigRectangle *rectangle;
ClutterColor *color;
ClutterColor *border_color;
guint border_width;
ClutterActorBox box;
ClutterFixed radiusx;
ClutterFixed widthx;
ClutterFixed heightx;
ClutterFixed border_widthx;
ClutterFixed max;
ClutterColor tmp_col;
rectangle = BIG_RECTANGLE(actor);
if (rectangle->radius == 0) {
/* In that case we are no different than our parent class,
* so don't bother */
CLUTTER_ACTOR_CLASS(big_rectangle_parent_class)->paint(actor);
return;
}
if (rectangle->corners_dirty)
big_rectangle_update_corners(rectangle);
g_object_get(rectangle,
"border-color", &border_color,
"border-width", &border_width,
"color", &color,
NULL);
clutter_actor_get_allocation_box(actor, &box);
/* translation was already done */
box.x2 -= box.x1;
box.y2 -= box.y1;
widthx = CLUTTER_UNITS_TO_FIXED(box.x2);
heightx = CLUTTER_UNITS_TO_FIXED(box.y2);
radiusx = CLUTTER_UNITS_TO_FIXED(rectangle->radius);
border_widthx = CLUTTER_INT_TO_FIXED(border_width);
max = MAX(border_widthx, radiusx);
if (radiusx != 0) {
tmp_col.red = 0xFF;
tmp_col.blue = 0xFF;
tmp_col.green = 0xFF;
tmp_col.alpha = clutter_actor_get_paint_opacity(actor);
cogl_color(&tmp_col);
/* NW */
cogl_texture_rectangle(rectangle->corner->texture,
0, 0,
max, max,
0, 0,
CFX_HALF, CFX_HALF);
/* NE */
cogl_texture_rectangle(rectangle->corner->texture,
widthx - max, 0,
widthx, max,
CFX_HALF, 0,
CFX_ONE, CFX_HALF);
/* SW */
cogl_texture_rectangle(rectangle->corner->texture,
0, heightx - max,
max, heightx,
0, CFX_HALF,
CFX_HALF, CFX_ONE);
/* SE */
cogl_texture_rectangle(rectangle->corner->texture,
widthx - max, heightx - max,
widthx, heightx,
CFX_HALF, CFX_HALF,
CFX_ONE, CFX_ONE);
}
if (border_width != 0) {
tmp_col = *border_color;
tmp_col.alpha = clutter_actor_get_paint_opacity(actor) * tmp_col.alpha / 255;
cogl_color(&tmp_col);
/* NORTH */
cogl_rectanglex(max, 0,
widthx - 2 * max, border_widthx);
/* EAST */
cogl_rectanglex(widthx - border_widthx, max,
border_widthx, heightx - 2 * max);
/* SOUTH */
cogl_rectanglex(max, heightx - border_widthx,
widthx - 2 * max, border_widthx);
/* WEST */
cogl_rectanglex(0, max,
border_widthx, heightx - 2 * max);
}
tmp_col = *color;
tmp_col.alpha = clutter_actor_get_paint_opacity(actor) * tmp_col.alpha / 255;
cogl_color(&tmp_col);
if (radiusx > border_widthx) {
cogl_rectanglex(radiusx, border_widthx,
widthx - radiusx - radiusx, radiusx - border_widthx);
cogl_rectanglex(radiusx, heightx - radiusx,
widthx - 2 * radiusx, radiusx - border_widthx);
}
cogl_rectanglex(border_widthx, MAX(radiusx, border_widthx),
widthx - 2 * border_widthx, heightx - 2 * MAX(radiusx, border_widthx));
clutter_color_free(border_color);
clutter_color_free(color);
}
static void
big_rectangle_notify(GObject *object,
GParamSpec *pspec)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
if (g_str_equal(pspec->name, "border-width") ||
g_str_equal(pspec->name, "color") ||
g_str_equal(pspec->name, "border-color")) {
rectangle->corners_dirty = TRUE;
}
}
static void
big_rectangle_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
switch (prop_id) {
case PROP_CORNER_RADIUS:
rectangle->radius = CLUTTER_UNITS_FROM_DEVICE(g_value_get_uint(value));
rectangle->corners_dirty = TRUE;
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_rectangle_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
switch (prop_id) {
case PROP_CORNER_RADIUS:
g_value_set_uint(value, CLUTTER_UNITS_TO_DEVICE(rectangle->radius));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_rectangle_dispose(GObject *object)
{
BigRectangle *rectangle;
rectangle = BIG_RECTANGLE(object);
rectangle->radius = 0;
big_rectangle_update_corners(rectangle);
if (G_OBJECT_CLASS(big_rectangle_parent_class)->dispose)
G_OBJECT_CLASS(big_rectangle_parent_class)->dispose(object);
}
static void
big_rectangle_class_init(BigRectangleClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->dispose = big_rectangle_dispose;
gobject_class->set_property = big_rectangle_set_property;
gobject_class->get_property = big_rectangle_get_property;
gobject_class->notify = big_rectangle_notify;
actor_class->paint = big_rectangle_paint;
g_object_class_install_property
(gobject_class,
PROP_CORNER_RADIUS,
g_param_spec_uint("corner-radius",
"Corner radius",
"Radius of the rectangle rounded corner",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
}
static void
big_rectangle_init(BigRectangle *rectangle)
{
}

42
src/big/rectangle.h Normal file
View File

@ -0,0 +1,42 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __BIG_RECTANGLE_H__
#define __BIG_RECTANGLE_H__
#include <glib-object.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define BIG_TYPE_RECTANGLE (big_rectangle_get_type ())
#define BIG_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BIG_TYPE_RECTANGLE, BigRectangle))
#define BIG_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BIG_TYPE_RECTANGLE, BigRectangleClass))
#define BIG_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BIG_TYPE_RECTANGLE))
#define BIG_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BIG_TYPE_RECTANGLE))
#define BIG_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BIG_TYPE_RECTANGLE, BigRectangleClass))
typedef struct BigRectangle BigRectangle;
typedef struct BigRectangleClass BigRectangleClass;
GType big_rectangle_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __BIG_RECTANGLE_H__ */

795
src/big/theme-image.c Normal file
View File

@ -0,0 +1,795 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* theme-image.c: Stretched image.
Copyright (C) 2005-2008 Red Hat, Inc.
Copyright (C) 2008 litl, LLC.
The libbigwidgets-lgpl is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The libbigwidgets-lgpl is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the libbigwidgets-lgpl; see the file COPYING.LIB.
If not, write to the Free Software Foundation, Inc., 59 Temple Place -
Suite 330, Boston, MA 02111-1307, USA.
*/
#include <glib.h>
#include <clutter/clutter-units.h>
#include <clutter/clutter-actor.h>
#include <clutter-cairo/clutter-cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <librsvg/rsvg.h>
#include <librsvg/rsvg-cairo.h>
#include "theme-image.h"
typedef enum {
BIG_THEME_IMAGE_UNSET,
BIG_THEME_IMAGE_SVG,
BIG_THEME_IMAGE_SURFACE
} BigThemeImageType;
struct BigThemeImage {
ClutterCairo parent_instance;
guint border_top;
guint border_bottom;
guint border_left;
guint border_right;
BigThemeImageType type;
union {
RsvgHandle *svg_handle;
cairo_surface_t *surface;
} u;
guint render_idle;
guint needs_render : 1;
};
struct BigThemeImageClass {
ClutterCairoClass parent_class;
};
G_DEFINE_TYPE(BigThemeImage, big_theme_image, CLUTTER_TYPE_CAIRO)
enum
{
PROP_0,
PROP_BORDER_TOP,
PROP_BORDER_BOTTOM,
PROP_BORDER_LEFT,
PROP_BORDER_RIGHT,
PROP_FILENAME,
PROP_PIXBUF
};
static void
big_theme_image_render(BigThemeImage *image)
{
int source_width = 0;
int source_height = 0;
int source_x1 = 0, source_x2 = 0, source_y1 = 0, source_y2 = 0;
int dest_x1 = 0, dest_x2 = 0, dest_y1 = 0, dest_y2 = 0;
int i, j;
int dest_width;
int dest_height;
ClutterGeometry geometry;
cairo_t *cr;
image->needs_render = FALSE;
if (image->render_idle) {
g_source_remove(image->render_idle);
image->render_idle = 0;
}
/* To draw a theme image, we divide the source and destination into 9
* pieces and draw each piece separately. (Some pieces may not exist
* if we have 0-width borders, in which case they'll be skipped)
*
* i=0 i=1 i=2
* border_left border_right
* +------------+--------------------+--------------+
* j=0: border_top | | | |
* +------------+--------------------+--------------+
* j=1 | | | |
* +------------+--------------------+--------------+
* j=2: border_bottom | | | |
* +------------+--------------------+--------------+
*
*/
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
if (!image->u.surface)
return;
source_width = cairo_image_surface_get_width(image->u.surface);
source_height = cairo_image_surface_get_height(image->u.surface);
break;
case BIG_THEME_IMAGE_SVG:
{
RsvgDimensionData dimensions;
if (!image->u.svg_handle)
return;
rsvg_handle_get_dimensions(image->u.svg_handle, &dimensions);
source_width = dimensions.width;
source_height = dimensions.height;
break;
}
default:
return;
}
clutter_actor_get_allocation_geometry(CLUTTER_ACTOR(image), &geometry);
dest_width = geometry.width;
dest_height = geometry.height;
cr = clutter_cairo_create(CLUTTER_CAIRO(image));
for (j = 0; j < 3; j++) {
switch (j) {
case 0:
source_y1 = 0;
source_y2 = image->border_top;
dest_y1 = 0;
dest_y2 = image->border_top;
break;
case 1:
source_y1 = image->border_top;
source_y2 = source_height - image->border_bottom;
dest_y1 = image->border_top;
dest_y2 = dest_height - image->border_bottom;
break;
case 2:
source_y1 = source_height - image->border_bottom;
source_y2 = source_height;
dest_y1 = dest_height - image->border_bottom;
dest_y2 = dest_height;
break;
}
if (dest_y2 <= dest_y1)
continue;
/* pixbuf-theme-engine has a nice interpretation of source_y2 == source_y1,
* dest_y2 != dest_y1, which is to linearly interpolate between the surrounding
* areas. We could do that for the surface case by setting
*
* source_y1 == y - 0.5
* source_y2 == y + 0.5
*
* but it's hard for the SVG case. source_y2 < source_y1 is pathological ... someone
* specified borders that sum up larger than the image.
*/
if (source_y2 <= source_y1)
continue;
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
source_x1 = 0;
source_x2 = image->border_left;
dest_x1 = 0;
dest_x2 = image->border_left;
break;
case 1:
source_x1 = image->border_left;
source_x2 = source_width - image->border_right;
dest_x1 = image->border_left;
dest_x2 = dest_width - image->border_right;
break;
case 2:
source_x1 = source_width - image->border_right;
source_x2 = source_width;
dest_x1 = dest_width - image->border_right;
dest_x2 = dest_width;
break;
}
if (dest_x2 <= dest_x1)
continue;
if (source_x2 <= source_x1)
continue;
cairo_save(cr);
cairo_rectangle(cr, dest_x1, dest_y1, dest_x2 - dest_x1, dest_y2 - dest_y1);
cairo_clip(cr);
cairo_translate(cr, dest_x1, dest_y1);
cairo_scale(cr,
(double)(dest_x2 - dest_x1) / (source_x2 - source_x1),
(double)(dest_y2 - dest_y1) / (source_y2 - source_y1));
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
cairo_set_source_surface(cr, image->u.surface, - source_x1, - source_y1);
cairo_paint(cr);
break;
case BIG_THEME_IMAGE_SVG:
cairo_translate(cr, - source_x1, - source_y1);
rsvg_handle_render_cairo(image->u.svg_handle, cr);
break;
default:
break;
}
cairo_restore(cr);
}
}
/* This will cause the surface content to be uploaded as
* new texture content */
cairo_destroy(cr);
}
static gboolean
big_theme_image_render_idle(gpointer data)
{
BigThemeImage *image;
image = data;
big_theme_image_render(image);
return FALSE;
}
static void
big_theme_image_queue_render(BigThemeImage *image)
{
image->needs_render = TRUE;
if (!image->render_idle)
image->render_idle = g_idle_add(big_theme_image_render_idle,
image);
}
static void
big_theme_image_paint(ClutterActor *actor)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(actor);
if (image->needs_render)
big_theme_image_render(image);
if (CLUTTER_ACTOR_CLASS(big_theme_image_parent_class)->paint)
CLUTTER_ACTOR_CLASS(big_theme_image_parent_class)->paint(actor);
}
static void
big_theme_image_allocate(ClutterActor *actor,
const ClutterActorBox *box,
gboolean absolute_origin_changed)
{
BigThemeImage *image;
guint old_width;
guint old_height;
guint width;
guint height;
image = BIG_THEME_IMAGE(actor);
width = ABS(CLUTTER_UNITS_TO_DEVICE(box->x2 - box->x1));
height = ABS(CLUTTER_UNITS_TO_DEVICE(box->y2 - box->y1));
g_object_get(actor,
"surface-width", &old_width,
"surface-height", &old_height,
NULL);
if (width != old_width || height != old_height) {
clutter_cairo_surface_resize(CLUTTER_CAIRO(actor), width, height);
big_theme_image_queue_render(image);
}
if (CLUTTER_ACTOR_CLASS(big_theme_image_parent_class))
CLUTTER_ACTOR_CLASS(big_theme_image_parent_class)->allocate(actor,
box,
absolute_origin_changed);
}
static void
big_theme_image_get_preferred_height(ClutterActor *actor,
ClutterUnit for_width,
ClutterUnit *min_height_p,
ClutterUnit *natural_height_p)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(actor);
if (min_height_p)
*min_height_p = 0;
if (!natural_height_p)
return;
*natural_height_p = 0;
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
if (!image->u.surface)
break;
*natural_height_p = CLUTTER_UNITS_FROM_DEVICE(
cairo_image_surface_get_height(image->u.surface));
break;
case BIG_THEME_IMAGE_SVG:
{
RsvgDimensionData dimensions;
if (!image->u.svg_handle)
return;
rsvg_handle_get_dimensions(image->u.svg_handle, &dimensions);
*natural_height_p =
CLUTTER_UNITS_FROM_DEVICE(dimensions.height);
break;
}
default:
break;
}
}
static void
big_theme_image_get_preferred_width(ClutterActor *actor,
ClutterUnit for_height,
ClutterUnit *min_width_p,
ClutterUnit *natural_width_p)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(actor);
if (min_width_p)
*min_width_p = 0;
if (!natural_width_p)
return;
*natural_width_p = 0;
switch (image->type) {
case BIG_THEME_IMAGE_SURFACE:
if (!image->u.surface)
break;
*natural_width_p = CLUTTER_UNITS_FROM_DEVICE(cairo_image_surface_get_width(image->u.surface));
break;
case BIG_THEME_IMAGE_SVG:
{
RsvgDimensionData dimensions;
if (!image->u.svg_handle)
return;
rsvg_handle_get_dimensions(image->u.svg_handle, &dimensions);
*natural_width_p = CLUTTER_UNITS_FROM_DEVICE(dimensions.width);
break;
}
default:
break;
}
}
static void
big_theme_image_set_border_value(BigThemeImage *image, guint *old_value, const GValue *new_value)
{
guint border_value;
border_value = g_value_get_uint(new_value);
if (*old_value != border_value) {
*old_value = border_value;
big_theme_image_queue_render(image);
}
}
static void
big_theme_image_set_filename(BigThemeImage *image, const char *filename)
{
if (!filename)
return;
if (g_str_has_suffix(filename, ".png") ||
g_str_has_suffix(filename, ".PNG")) {
image->type = BIG_THEME_IMAGE_SURFACE;
image->u.surface = cairo_image_surface_create_from_png(filename);
if (image->u.surface == NULL) {
g_warning("Error when loading PNG from file %s", filename);
}
} else if (g_str_has_suffix(filename, ".svg") ||
g_str_has_suffix(filename, ".SVG")) {
GError *error;
error = NULL;
image->u.svg_handle = rsvg_handle_new_from_file(filename, &error);
if (image->u.svg_handle == NULL) {
g_warning("Error when loading SVG from file %s: %s", filename,
error?error->message:"Error not set by RSVG");
if (error)
g_error_free(error);
return;
}
image->type = BIG_THEME_IMAGE_SVG;
} else {
g_warning("%s: Unsupported file type", filename);
return;
}
big_theme_image_queue_render(image);
}
static cairo_surface_t *
create_surface_from_pixbuf(const GdkPixbuf *pixbuf)
{
gint width = gdk_pixbuf_get_width (pixbuf);
gint height = gdk_pixbuf_get_height (pixbuf);
guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf);
int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
int n_channels = gdk_pixbuf_get_n_channels (pixbuf);
guchar *cairo_pixels;
cairo_format_t format;
cairo_surface_t *surface;
static const cairo_user_data_key_t key;
int j;
if (n_channels == 3)
format = CAIRO_FORMAT_RGB24;
else
format = CAIRO_FORMAT_ARGB32;
cairo_pixels = g_malloc (4 * width * height);
surface = cairo_image_surface_create_for_data((unsigned char *)cairo_pixels,
format,
width, height, 4 * width);
cairo_surface_set_user_data(surface, &key,
cairo_pixels, (cairo_destroy_func_t)g_free);
for (j = height; j; j--) {
guchar *p = gdk_pixels;
guchar *q = cairo_pixels;
if (n_channels == 3) {
guchar *end = p + 3 * width;
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
q[0] = p[2];
q[1] = p[1];
q[2] = p[0];
#else
q[1] = p[0];
q[2] = p[1];
q[3] = p[2];
#endif
p += 3;
q += 4;
}
} else {
guchar *end = p + 4 * width;
guint t1,t2,t3;
#define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END
while (p < end) {
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
MULT(q[0], p[2], p[3], t1);
MULT(q[1], p[1], p[3], t2);
MULT(q[2], p[0], p[3], t3);
q[3] = p[3];
#else
q[0] = p[3];
MULT(q[1], p[0], p[3], t1);
MULT(q[2], p[1], p[3], t2);
MULT(q[3], p[2], p[3], t3);
#endif
p += 4;
q += 4;
}
#undef MULT
}
gdk_pixels += gdk_rowstride;
cairo_pixels += 4 * width;
}
return surface;
}
static void
big_theme_image_set_pixbuf(BigThemeImage *image, GdkPixbuf *pixbuf)
{
if (!pixbuf)
return;
image->type = BIG_THEME_IMAGE_SURFACE;
image->u.surface = create_surface_from_pixbuf(pixbuf);
g_assert(image->u.surface != NULL);
big_theme_image_queue_render(image);
}
static void
big_theme_image_set_property(GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(object);
switch (prop_id) {
case PROP_BORDER_TOP:
big_theme_image_set_border_value(image, &image->border_top, value);
break;
case PROP_BORDER_BOTTOM:
big_theme_image_set_border_value(image, &image->border_bottom, value);
break;
case PROP_BORDER_LEFT:
big_theme_image_set_border_value(image, &image->border_left, value);
break;
case PROP_BORDER_RIGHT:
big_theme_image_set_border_value(image, &image->border_right, value);
break;
case PROP_FILENAME:
big_theme_image_set_filename(image, g_value_get_string(value));
break;
case PROP_PIXBUF:
big_theme_image_set_pixbuf(image, g_value_get_object(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_theme_image_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(object);
switch (prop_id) {
case PROP_BORDER_TOP:
g_value_set_uint(value, image->border_top);
break;
case PROP_BORDER_BOTTOM:
g_value_set_uint(value, image->border_bottom);
break;
case PROP_BORDER_LEFT:
g_value_set_uint(value, image->border_left);
break;
case PROP_BORDER_RIGHT:
g_value_set_uint(value, image->border_right);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
big_theme_image_dispose(GObject *object)
{
BigThemeImage *image;
image = BIG_THEME_IMAGE(object);
if (image->render_idle) {
g_source_remove(image->render_idle);
image->render_idle = 0;
}
switch (image->type) {
case BIG_THEME_IMAGE_SVG:
if (image->u.svg_handle) {
g_object_unref(image->u.svg_handle);
image->u.svg_handle = NULL;
}
break;
case BIG_THEME_IMAGE_SURFACE:
if (image->u.surface) {
cairo_surface_destroy(image->u.surface);
image->u.surface = NULL;
}
break;
default:
break;
}
if (G_OBJECT_CLASS(big_theme_image_parent_class)->dispose)
G_OBJECT_CLASS(big_theme_image_parent_class)->dispose(object);
}
static void
big_theme_image_class_init(BigThemeImageClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->dispose = big_theme_image_dispose;
gobject_class->set_property = big_theme_image_set_property;
gobject_class->get_property = big_theme_image_get_property;
actor_class->allocate = big_theme_image_allocate;
actor_class->get_preferred_width = big_theme_image_get_preferred_width;
actor_class->get_preferred_height = big_theme_image_get_preferred_height;
actor_class->paint = big_theme_image_paint;
g_object_class_install_property
(gobject_class,
PROP_BORDER_TOP,
g_param_spec_uint("border-top",
"Border top",
"Top dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_BORDER_BOTTOM,
g_param_spec_uint("border-bottom",
"Border bottom",
"Bottom dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_BORDER_LEFT,
g_param_spec_uint("border-left",
"Border left",
"Left dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_BORDER_RIGHT,
g_param_spec_uint("border-right",
"Border right",
"Right dimension of the image border "
"(none-scaled part)",
0, G_MAXUINT,
0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_FILENAME,
g_param_spec_string("filename",
"Filename",
"Name of the file",
NULL,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(gobject_class,
PROP_PIXBUF,
g_param_spec_object("pixbuf",
"Pixbuf",
"Pixbuf of the image",
GDK_TYPE_PIXBUF,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
}
static void
big_theme_image_init(BigThemeImage *image)
{
}
ClutterActor *
big_theme_image_new_from_file(const char *filename,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right)
{
ClutterActor *actor;
actor = g_object_new(BIG_TYPE_THEME_IMAGE,
/* FIXME ClutterCairo requires creating a bogus
* surface with nonzero size
*/
"surface-width", 1,
"surface-height", 1,
"filename", filename,
"border-top", border_top,
"border-bottom", border_bottom,
"border-left", border_left,
"border-right", border_right,
NULL);
return actor;
}
ClutterActor *
big_theme_image_new_from_pixbuf(GdkPixbuf *pixbuf,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right)
{
ClutterActor *actor;
actor = g_object_new(BIG_TYPE_THEME_IMAGE,
/* FIXME ClutterCairo requires creating a bogus
* surface with nonzero size
*/
"surface-width", 1,
"surface-height", 1,
"pixbuf", pixbuf,
"border-top", border_top,
"border-bottom", border_bottom,
"border-left", border_left,
"border-right", border_right,
NULL);
return actor;
}

39
src/big/theme-image.h Normal file
View File

@ -0,0 +1,39 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* Copyright 2008 litl, LLC. All Rights Reserved. */
#ifndef __BIG_THEME_IMAGE_H__
#define __BIG_THEME_IMAGE_H__
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define BIG_TYPE_THEME_IMAGE (big_theme_image_get_type ())
#define BIG_THEME_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), BIG_TYPE_THEME_IMAGE, BigThemeImage))
#define BIG_THEME_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), BIG_TYPE_THEME_IMAGE, BigThemeImageClass))
#define BIG_IS_THEME_IMAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), BIG_TYPE_THEME_IMAGE))
#define BIG_IS_THEME_IMAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), BIG_TYPE_THEME_IMAGE))
#define BIG_THEME_IMAGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), BIG_TYPE_THEME_IMAGE, BigThemeImageClass))
typedef struct BigThemeImage BigThemeImage;
typedef struct BigThemeImageClass BigThemeImageClass;
GType big_theme_image_get_type (void) G_GNUC_CONST;
ClutterActor * big_theme_image_new_from_file (const gchar *filename,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right);
ClutterActor * big_theme_image_new_from_pixbuf (GdkPixbuf *pixbuf,
guint border_top,
guint border_bottom,
guint border_left,
guint border_right);
G_END_DECLS
#endif /* __BIG_THEME_IMAGE_H__ */