From f0efad6b79c8407024997c3abeccd4268f59a24c Mon Sep 17 00:00:00 2001 From: Iain Holmes Date: Tue, 6 Jun 2006 18:19:11 +0000 Subject: [PATCH] 2006-06-06 Iain Holmes * gtk/: Add a gtk widget for clutter. * configure.ac: Add GTK checks * Makefile.am: Go into gtk/ --- ChangeLog | 8 ++ Makefile.am | 4 +- configure.ac | 8 ++ gtk/Makefile.am | 22 +++++ gtk/gtk-clutter-test.c | 209 +++++++++++++++++++++++++++++++++++++++++ gtk/gtk-clutter.c | 115 +++++++++++++++++++++++ gtk/gtk-clutter.h | 80 ++++++++++++++++ gtk/redhand.png | Bin 0 -> 8250 bytes 8 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 gtk/Makefile.am create mode 100644 gtk/gtk-clutter-test.c create mode 100644 gtk/gtk-clutter.c create mode 100644 gtk/gtk-clutter.h create mode 100644 gtk/redhand.png diff --git a/ChangeLog b/ChangeLog index c3f6b0a4e..6a7eef5fe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-06-06 Iain Holmes + + * gtk/: Add a gtk widget for clutter. + + * configure.ac: Add GTK checks + + * Makefile.am: Go into gtk/ + 2006-06-05 Matthew Allum * clutter/clutter-group.c: (clutter_group_remove): diff --git a/Makefile.am b/Makefile.am index 5f19271de..75850fc97 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=clutter bindings doc examples +SUBDIRS=clutter gtk bindings doc examples pcfiles = clutter-@CLUTTER_MAJORMINOR@.pc @@ -17,4 +17,4 @@ DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc # Extra clean files so that maintainer-clean removes *everything* MAINTAINERCLEANFILES = aclocal.m4 compile config.guess config.sub \ configure depcomp install-sh ltmain.sh \ - Makefile.in missing config.h.in \ No newline at end of file + Makefile.in missing config.h.in diff --git a/configure.ac b/configure.ac index 97b687856..e9513f7f7 100644 --- a/configure.ac +++ b/configure.ac @@ -104,6 +104,11 @@ GST_LIBS="$GST_LIBS -lgstinterfaces-$GST_MAJORMINOR -lgstvideo-$GST_MAJORMINOR - dnl ======================================================================== +pkg_modules="gtk+-2.0" +PKG_CHECK_MODULES(GTK, [$pkg_modules]) + +dnl ======================================================================== + if test "x$GCC" = "xyes"; then GCC_FLAGS="-g -Wall" fi @@ -175,6 +180,8 @@ dnl ======================================================================== AC_SUBST(GCC_FLAGS) AC_SUBST(GST_CFLAGS) AC_SUBST(GST_LIBS) +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) CLUTTER_CFLAGS="$GLX_CLAGS $CLUTTER_CFLAGS" CLUTTER_LIBS="$GLX_LIBS $CLUTTER_LIBS" @@ -184,6 +191,7 @@ AC_SUBST(CLUTTER_LIBS) AC_OUTPUT([Makefile clutter/Makefile +gtk/Makefile bindings/Makefile bindings/python/Makefile examples/Makefile diff --git a/gtk/Makefile.am b/gtk/Makefile.am new file mode 100644 index 000000000..8ffe77d8e --- /dev/null +++ b/gtk/Makefile.am @@ -0,0 +1,22 @@ +INCLUDES = @GCC_FLAGS@ @CLUTTER_CFLAGS@ $(GST_CFLAGS) $(GTK_CFLAGS) + +lib_LTLIBRARIES = libgtkclutter-@CLUTTER_MAJORMINOR@.la + +libgtkclutter_@CLUTTER_MAJORMINOR@_la_SOURCES = gtk-clutter.c + +libgtkclutter_@CLUTTER_MAJORMINOR@_la_LIBADD = @CLUTTER_LIBS@ $(GST_LIBS) $(GTK_LIBS) +libgtkclutter_@CLUTTER_MAJORMINOR@_la_LDFLAGS = @CLUTTER_LT_LDFLAGS@ + +gtkclutterheadersdir = $(includedir)/gtk-clutter-@CLUTTER_MAJORMINOR@/gtk-clutter +gtkclutterheaders_DATA = gtk-clutter.h + +noinst_PROGRAMS = gtk-clutter-test + +gtk_clutter_test_SOURCES = gtk-clutter-test.c +gtk_clutter_test_LDADD = libgtkclutter-@CLUTTER_MAJORMINOR@.la \ + $(CLUTTER_LIBS) \ + $(GST_LIBS) \ + $(GTK_LIBS) \ + $(top_builddir)/clutter/libclutter-@CLUTTER_MAJORMINOR@.la + +gtk_clutter_test_CFLAGS = $(CLUTTER_CFLAGS) $(GST_CFLAGS) $(GTK_CFLAGS) diff --git a/gtk/gtk-clutter-test.c b/gtk/gtk-clutter-test.c new file mode 100644 index 000000000..d567f6c8f --- /dev/null +++ b/gtk/gtk-clutter-test.c @@ -0,0 +1,209 @@ +#include +#include +#include + +#include "gtk-clutter.h" + +#define TRAILS 0 +#define NHANDS 6 +#define WINWIDTH 800 +#define WINHEIGHT 800 +#define RADIUS 250 + +typedef struct SuperOH +{ + ClutterElement *hand[NHANDS], *bgtex; + ClutterGroup *group; + GdkPixbuf *bgpixb; + +} SuperOH; + +/* input handler */ +void +input_cb (ClutterStage *stage, + ClutterEvent *event, + gpointer data) +{ + SuperOH *oh = (SuperOH *)data; + + if (event->type == CLUTTER_BUTTON_PRESS) + { + ClutterButtonEvent *bev = (ClutterButtonEvent *) event; + ClutterElement *e; + + g_print ("*** button press event (button:%d) ***\n", + bev->button); + + e = clutter_stage_get_element_at_pos (stage, + clutter_button_event_x (event), + clutter_button_event_y (event)); + + if (e) + clutter_element_hide(e); + } + else if (event->type == CLUTTER_KEY_PRESS) + { + ClutterKeyEvent *kev = (ClutterKeyEvent *) event; + + g_print ("*** key press event (key:%c) ***\n", + clutter_key_event_symbol (kev)); + + if (clutter_key_event_symbol (kev) == CLUTTER_q) + clutter_main_quit (); + } +} + + +/* Timeline handler */ +void +frame_cb (ClutterTimeline *timeline, + gint frame_num, + gpointer data) +{ + SuperOH *oh = (SuperOH *)data; + ClutterElement *stage = clutter_stage_get_default (); + gint i; + +#if TRAILS + oh->bgpixb = clutter_stage_snapshot (CLUTTER_STAGE (stage), + 0, 0, + WINWIDTH, + WINHEIGHT); + clutter_texture_set_pixbuf (CLUTTER_TEXTURE (oh->bgtex), oh->bgpixb); + g_object_unref (G_OBJECT (oh->bgpixb)); + g_object_unref (stage); +#endif + + /* Rotate everything clockwise about stage center*/ + clutter_element_rotate_z (CLUTTER_ELEMENT(oh->group), + frame_num, + WINWIDTH/2, + WINHEIGHT/2); + for (i = 0; i < NHANDS; i++) + { + /* rotate each hand around there centers */ + clutter_element_rotate_z (oh->hand[i], + - 6.0 * frame_num, + clutter_element_get_width (oh->hand[i])/2, + clutter_element_get_height (oh->hand[i])/2); + } + + /* + clutter_element_rotate_x (CLUTTER_ELEMENT(oh->group), + 75.0, + WINHEIGHT/2, 0); + */ +} + +int +main (int argc, char *argv[]) +{ + ClutterTimeline *timeline; + ClutterElement *stage; + ClutterColor stage_color = { 0x61, 0x64, 0x8c, 0xff }; + GtkWidget *window, *plug, *clutter; + GtkWidget *label, *button, *vbox; + GdkPixbuf *pixbuf; + SuperOH *oh; + gint i; + + clutter_init (&argc, &argv); + gtk_init (&argc, &argv); + + + pixbuf = gdk_pixbuf_new_from_file ("redhand.png", NULL); + + if (!pixbuf) + g_error("pixbuf load failed"); + + clutter = g_object_new (GTK_TYPE_CLUTTER, NULL); + stage = gtk_clutter_get_stage (GTK_CLUTTER (clutter)); + + /* Set our stage size */ + clutter_element_set_size (stage, WINWIDTH, WINHEIGHT); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_main_quit), NULL); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_container_add (GTK_CONTAINER (window), vbox); + + gtk_container_add (GTK_CONTAINER (vbox), clutter); + + label = gtk_label_new ("This is a label"); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("This is a button...clicky"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + + /* and its background color */ + + clutter_stage_set_color (CLUTTER_STAGE (stage), + &stage_color); + + oh = g_new(SuperOH, 1); + +#if TRAILS + oh->bgtex = clutter_texture_new(); + clutter_element_set_size (oh->bgtex, WINWIDTH, WINHEIGHT); + clutter_element_set_opacity (oh->bgtex, 0x99); + clutter_group_add (CLUTTER_GROUP (stage), oh->bgtex); +#endif + + /* create a new group to hold multiple elements in a group */ + oh->group = clutter_group_new(); + + for (i = 0; i < NHANDS; i++) + { + gint x, y, w, h; + + /* Create a texture from pixbuf, then clone in to same resources */ + if (i == 0) + oh->hand[i] = clutter_texture_new_from_pixbuf (pixbuf); + else + oh->hand[i] = clutter_clone_texture_new (CLUTTER_TEXTURE(oh->hand[0])); + + /* Place around a circle */ + w = clutter_element_get_width (oh->hand[0]); + h = clutter_element_get_height (oh->hand[0]); + + x = WINWIDTH/2 + RADIUS * cos (i * M_PI / (NHANDS/2)) - w/2; + y = WINHEIGHT/2 + RADIUS * sin (i * M_PI / (NHANDS/2)) - h/2; + + clutter_element_set_position (oh->hand[i], x, y); + + /* Add to our group group */ + clutter_group_add (oh->group, oh->hand[i]); + } + + /* Add the group to the stage */ + clutter_group_add (CLUTTER_GROUP (stage), CLUTTER_ELEMENT(oh->group)); + + /* Show everying ( and map window ) */ + clutter_group_show_all (oh->group); + clutter_group_show_all (CLUTTER_GROUP (stage)); + + g_signal_connect (stage, "button-press-event", + G_CALLBACK (input_cb), + oh); + g_signal_connect (stage, "key-release-event", + G_CALLBACK (input_cb), + oh); + + gtk_widget_show_all (window); + + /* Create a timeline to manage animation */ + timeline = clutter_timeline_new (360, 60); /* num frames, fps */ + g_object_set(timeline, "loop", TRUE, 0); /* have it loop */ + + /* fire a callback for frame change */ + g_signal_connect(timeline, "new-frame", G_CALLBACK (frame_cb), oh); + + /* and start it */ + clutter_timeline_start (timeline); + + gtk_main(); + + return 0; +} diff --git a/gtk/gtk-clutter.c b/gtk/gtk-clutter.c new file mode 100644 index 000000000..5ac1f7536 --- /dev/null +++ b/gtk/gtk-clutter.c @@ -0,0 +1,115 @@ +/* + * GTK-Clutter. + * + * GTK+ widget for Clutter. + * + * Authored By Iain Holmes + * + * Copyright (C) 2006 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include + +#include "gtk-clutter.h" + +#define GTK_CLUTTER_GET_PRIVATE(obj) \ +(G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CLUTTER, GtkClutterPrivate)) + +struct _GtkClutterPrivate { + ClutterElement *stage; + gboolean anchored; +}; + +static GtkSocketClass *parent_class; + +static void +dispose (GObject *object) +{ + GtkClutter *clutter; + GtkClutterPrivate *priv; + + clutter = GTK_CLUTTER (object); + priv = GTK_CLUTTER_GET_PRIVATE (clutter); + + if (priv->stage) { + g_object_unref (G_OBJECT (priv->stage)); + priv->stage = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +hierarchy_changed (GtkWidget *widget, + GtkWidget *parent) +{ + GtkClutter *clutter; + GtkClutterPrivate *priv; + + clutter = GTK_CLUTTER (widget); + priv = GTK_CLUTTER_GET_PRIVATE (clutter); + + if (!priv->anchored) { + /* Now we can add our stage to the socket */ + gtk_socket_add_id + (GTK_SOCKET (clutter), (GdkNativeWindow) clutter_stage_get_xwindow (CLUTTER_STAGE (priv->stage))); + + priv->anchored = TRUE; + } +} + +static void +gtk_clutter_class_init (GtkClutterClass *klass) +{ + GObjectClass *gobject_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + gobject_class->dispose = dispose; + + widget_class->hierarchy_changed = hierarchy_changed; + + g_type_class_add_private (gobject_class, sizeof (GtkClutterPrivate)); + + parent_class = g_type_class_peek_parent (klass); +} + +static void +gtk_clutter_init (GtkClutter *clutter) +{ + GtkClutterPrivate *priv; + + clutter->priv = priv = GTK_CLUTTER_GET_PRIVATE (clutter); + + priv->stage = clutter_stage_get_default (); + priv->anchored = FALSE; +} + +G_DEFINE_TYPE (GtkClutter, gtk_clutter, GTK_TYPE_SOCKET); + +ClutterElement * +gtk_clutter_get_stage (GtkClutter *clutter) +{ + g_return_val_if_fail (GTK_IS_CLUTTER (clutter), NULL); + + return clutter->priv->stage; +} diff --git a/gtk/gtk-clutter.h b/gtk/gtk-clutter.h new file mode 100644 index 000000000..a6cf46d12 --- /dev/null +++ b/gtk/gtk-clutter.h @@ -0,0 +1,80 @@ +/* + * GTK-Clutter. + * + * GTK+ widget for Clutter. + * + * Authored By Iain Holmes + * + * Copyright (C) 2006 OpenedHand + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _HAVE_GTK_CLUTTER_H +#define _HAVE_GTK_CLUTTER_H + +#include + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_CLUTTER gtk_clutter_get_type () + +#define GTK_CLUTTER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GTK_TYPE_CLUTTER, GtkClutter)) + +#define GTK_CLUTTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CASE ((klass), \ + GTK_TYPE_CLUTTER, GtkClutterClass)) + +#define GTK_IS_CLUTTER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GTK_TYPE_CLUTTER)) + +#define GTK_IS_CLUTTER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GTK_TYPE_CLUTTER)) + +#define GTK_CLUTTER_STAGE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GTK_TYPE_CLUTTER, GtkClutterClass)) + +typedef struct _GtkClutterPrivate GtkClutterPrivate; +typedef struct _GtkClutter GtkClutter; +typedef struct _GtkClutterClass GtkClutterClass; + +struct _GtkClutter +{ + GtkSocket parent; + + /*< private >*/ + GtkClutterPrivate *priv; +}; + +struct _GtkClutterClass +{ + GtkSocketClass parent_class; +}; + +GType gtk_clutter_get_type (void); + +ClutterElement *gtk_clutter_get_stage (GtkClutter *clutter); + +G_END_DECLS + +#endif diff --git a/gtk/redhand.png b/gtk/redhand.png new file mode 100644 index 0000000000000000000000000000000000000000..c07d8acd33d54996512f6e2b6ca4d17b5ffc4f20 GIT binary patch literal 8250 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 E2il-`3jhEB literal 0 HcmV?d00001