[gnome-shell] [St] Add StThemeNodeTransition
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] [St] Add StThemeNodeTransition
- Date: Tue, 8 Jun 2010 16:05:23 +0000 (UTC)
commit 0deffbaaf05bff5da2ca987546d4539887fea4cb
Author: Florian Müllner <fmuellner gnome org>
Date: Tue May 25 16:10:37 2010 +0200
[St] Add StThemeNodeTransition
Introduce a small helper class in order to add transitions between
theme nodes to StWidget.
https://bugzilla.gnome.org/show_bug.cgi?id=619025
transition update
src/Makefile-st.am | 4 +-
src/st/st-theme-node-transition.c | 411 +++++++++++++++++++++++++++++++++++++
src/st/st-theme-node-transition.h | 51 +++++
3 files changed, 465 insertions(+), 1 deletions(-)
---
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index b3cc7aa..5cefa7b 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -110,7 +110,8 @@ st_source_private_h = \
st/st-private.h \
st/st-table-private.h \
st/st-theme-private.h \
- st/st-theme-node-private.h
+ st/st-theme-node-private.h \
+ st/st-theme-node-transition.h
# please, keep this sorted alphabetically
st_source_c = \
@@ -142,6 +143,7 @@ st_source_c = \
st/st-theme-context.c \
st/st-theme-node.c \
st/st-theme-node-drawing.c \
+ st/st-theme-node-transition.c \
st/st-tooltip.c \
st/st-widget.c \
$(NULL)
diff --git a/src/st/st-theme-node-transition.c b/src/st/st-theme-node-transition.c
new file mode 100644
index 0000000..379d04d
--- /dev/null
+++ b/src/st/st-theme-node-transition.c
@@ -0,0 +1,411 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* Theme node transitions for StWidget.
+ *
+ * Copyright (C) 2010 Florian Müllner <fmuellner gnome org>
+ *
+ * The St 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 St 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 St; 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 "st-theme-node-transition.h"
+
+enum {
+ COMPLETED,
+ NEW_FRAME,
+ LAST_SIGNAL
+};
+
+#define ST_THEME_NODE_TRANSITION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_THEME_NODE_TRANSITION, StThemeNodeTransitionPrivate))
+
+struct _StThemeNodeTransitionPrivate {
+ StThemeNode *old_theme_node;
+ StThemeNode *new_theme_node;
+
+ CoglHandle *old_texture;
+ CoglHandle *new_texture;
+
+ CoglHandle *old_offscreen;
+ CoglHandle *new_offscreen;
+
+ CoglHandle *material;
+
+ ClutterAlpha *alpha;
+ ClutterTimeline *timeline;
+
+ guint timeline_completed_id;
+ guint timeline_new_frame_id;
+
+ ClutterActorBox last_allocation;
+ ClutterActorBox offscreen_box;
+ guint8 last_opacity;
+
+ gboolean needs_setup;
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (StThemeNodeTransition, st_theme_node_transition, G_TYPE_OBJECT);
+
+
+static void
+on_timeline_completed (ClutterTimeline *timeline,
+ StThemeNodeTransition *transition)
+{
+ g_signal_emit (transition, signals[COMPLETED], 0);
+}
+
+static void
+on_timeline_new_frame (ClutterTimeline *timeline,
+ gint frame_num,
+ StThemeNodeTransition *transition)
+{
+ g_signal_emit (transition, signals[NEW_FRAME], 0);
+}
+
+StThemeNodeTransition *
+st_theme_node_transition_new (StThemeNode *from_node,
+ StThemeNode *to_node,
+ guint duration)
+{
+ StThemeNodeTransition *transition;
+
+ g_return_val_if_fail (ST_IS_THEME_NODE (from_node), NULL);
+ g_return_val_if_fail (ST_IS_THEME_NODE (to_node), NULL);
+
+ duration = st_theme_node_get_transition_duration (to_node);
+
+ transition = g_object_new (ST_TYPE_THEME_NODE_TRANSITION,
+ NULL);
+
+ transition->priv->old_theme_node = g_object_ref (from_node);
+ transition->priv->new_theme_node = g_object_ref (to_node);
+
+ transition->priv->alpha = clutter_alpha_new ();
+ transition->priv->timeline = clutter_timeline_new (duration);
+
+ transition->priv->timeline_completed_id =
+ g_signal_connect (transition->priv->timeline, "completed",
+ G_CALLBACK (on_timeline_completed), transition);
+ transition->priv->timeline_new_frame_id =
+ g_signal_connect (transition->priv->timeline, "new-frame",
+ G_CALLBACK (on_timeline_new_frame), transition);
+
+ clutter_alpha_set_mode (transition->priv->alpha, CLUTTER_EASE_IN_OUT_QUAD);
+ clutter_alpha_set_timeline (transition->priv->alpha,
+ transition->priv->timeline);
+
+ clutter_timeline_start (transition->priv->timeline);
+
+ return transition;
+}
+
+void
+st_theme_node_transition_update (StThemeNodeTransition *transition,
+ StThemeNode *new_node)
+{
+ StThemeNodeTransitionPrivate *priv = transition->priv;
+ StThemeNode *old_node;
+ ClutterTimelineDirection direction;
+
+ g_return_if_fail (ST_IS_THEME_NODE_TRANSITION (transition));
+ g_return_if_fail (ST_IS_THEME_NODE (new_node));
+
+ direction = clutter_timeline_get_direction (priv->timeline);
+ old_node = (direction == CLUTTER_TIMELINE_FORWARD) ? priv->old_theme_node
+ : priv->new_theme_node;
+
+ /* If the update is the reversal of the current transition,
+ * we reverse the timeline.
+ * Otherwise, we should initiate a new transition from the
+ * current state to the new one; this is hard to do, so we
+ * just cancel the ongoing transition in that case.
+ * Note that reversing a timeline before any time elapsed
+ * results in the timeline's time position being set to the
+ * full duration - this is not what we want, so we cancel the
+ * transition as well in that case.
+ */
+ if (st_theme_node_equal (new_node, old_node)
+ && clutter_timeline_get_elapsed_time (priv->timeline) > 0)
+ {
+ if (direction == CLUTTER_TIMELINE_FORWARD)
+ clutter_timeline_set_direction (priv->timeline,
+ CLUTTER_TIMELINE_BACKWARD);
+ else
+ clutter_timeline_set_direction (priv->timeline,
+ CLUTTER_TIMELINE_FORWARD);
+ }
+ else
+ {
+ clutter_timeline_stop (priv->timeline);
+ g_signal_emit (transition, signals[COMPLETED], 0);
+ }
+}
+
+static void
+calculate_offscreen_box (StThemeNodeTransition *transition,
+ const ClutterActorBox *allocation)
+{
+ StThemeNodeTransitionPrivate *priv = transition->priv;
+ ClutterActorBox old_node_box, new_node_box;
+
+ st_theme_node_get_paint_box (priv->old_theme_node,
+ allocation,
+ &old_node_box);
+
+ st_theme_node_get_paint_box (priv->new_theme_node,
+ allocation,
+ &new_node_box);
+
+ priv->offscreen_box.x1 = MIN (old_node_box.x1, new_node_box.x1)
+ - allocation->x1;
+ priv->offscreen_box.y1 = MIN (old_node_box.y1, new_node_box.y1)
+ - allocation->y1;
+ priv->offscreen_box.x2 = MAX (old_node_box.x2, new_node_box.x2)
+ - allocation->x1;
+ priv->offscreen_box.y2 = MAX (old_node_box.y2, new_node_box.y2)
+ - allocation->y1;
+}
+
+static void
+setup_framebuffers (StThemeNodeTransition *transition,
+ const ClutterActorBox *allocation,
+ guint8 paint_opacity)
+{
+ StThemeNodeTransitionPrivate *priv = transition->priv;
+ CoglColor clear_color = { 0, 0, 0, 0 };
+ guint width, height;
+
+ width = priv->offscreen_box.x2 - priv->offscreen_box.x1;
+ height = priv->offscreen_box.y2 - priv->offscreen_box.y1;
+
+ if (priv->old_texture)
+ cogl_handle_unref (priv->old_texture);
+ priv->old_texture = cogl_texture_new_with_size (width, height,
+ COGL_TEXTURE_NO_SLICING,
+ COGL_PIXEL_FORMAT_ANY);
+
+ if (priv->new_texture)
+ cogl_handle_unref (priv->new_texture);
+ priv->new_texture = cogl_texture_new_with_size (width, height,
+ COGL_TEXTURE_NO_SLICING,
+ COGL_PIXEL_FORMAT_ANY);
+
+ if (priv->old_offscreen)
+ cogl_handle_unref (priv->old_offscreen);
+ priv->old_offscreen = cogl_offscreen_new_to_texture (priv->old_texture);
+
+ if (priv->new_offscreen)
+ cogl_handle_unref (priv->new_offscreen);
+ priv->new_offscreen = cogl_offscreen_new_to_texture (priv->new_texture);
+
+ if (priv->material)
+ cogl_handle_unref (priv->material);
+ priv->material = cogl_material_new ();
+
+ cogl_material_set_layer_combine (priv->material, 1,
+ "RGBA = INTERPOLATE (PREVIOUS, "
+ "TEXTURE, "
+ "CONSTANT[A])",
+ NULL);
+
+ cogl_material_set_layer (priv->material, 0, priv->new_texture);
+ cogl_material_set_layer (priv->material, 1, priv->old_texture);
+
+ cogl_push_framebuffer (priv->old_offscreen);
+ cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
+ cogl_ortho (priv->offscreen_box.x1, priv->offscreen_box.x2,
+ priv->offscreen_box.y2, priv->offscreen_box.y1,
+ 0.0, 1.0);
+ st_theme_node_paint (priv->old_theme_node,
+ allocation,
+ paint_opacity);
+ cogl_pop_framebuffer ();
+
+ cogl_push_framebuffer (priv->new_offscreen);
+ cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
+ cogl_ortho (priv->offscreen_box.x1, priv->offscreen_box.x2,
+ priv->offscreen_box.y2, priv->offscreen_box.y1,
+ 0.0, 1.0);
+ st_theme_node_paint (priv->new_theme_node,
+ allocation,
+ paint_opacity);
+ cogl_pop_framebuffer ();
+}
+
+void
+st_theme_node_transition_paint (StThemeNodeTransition *transition,
+ ClutterActorBox *allocation,
+ guint8 paint_opacity)
+{
+ StThemeNodeTransitionPrivate *priv = transition->priv;
+
+ guint width, height;
+ CoglColor constant = { 0, 0, 0, 0 };
+ float tex_coords[] = {
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ };
+
+ g_return_if_fail (ST_IS_THEME_NODE (priv->old_theme_node));
+ g_return_if_fail (ST_IS_THEME_NODE (priv->new_theme_node));
+
+ if (!clutter_actor_box_equal (allocation, &priv->last_allocation) ||
+ paint_opacity != priv->last_opacity)
+ priv->needs_setup = TRUE;
+
+ if (priv->needs_setup)
+ {
+ priv->last_allocation = *allocation;
+ priv->last_opacity = paint_opacity;
+
+ calculate_offscreen_box (transition, allocation);
+ setup_framebuffers (transition, allocation, paint_opacity);
+
+ priv->needs_setup = FALSE;
+ }
+
+ width = cogl_texture_get_width (priv->old_texture);
+ height = cogl_texture_get_height (priv->old_texture);
+
+ constant.alpha = clutter_alpha_get_alpha (priv->alpha) * paint_opacity;
+
+ cogl_material_set_layer_combine_constant (priv->material, 1, &constant);
+
+ cogl_set_source (priv->material);
+ cogl_rectangle_with_multitexture_coords (priv->offscreen_box.x1,
+ priv->offscreen_box.y1,
+ priv->offscreen_box.x2,
+ priv->offscreen_box.y2,
+ tex_coords, 8);
+}
+
+static void
+st_theme_node_transition_dispose (GObject *object)
+{
+ StThemeNodeTransitionPrivate *priv = ST_THEME_NODE_TRANSITION (object)->priv;
+
+ if (priv->old_theme_node)
+ {
+ g_object_unref (priv->old_theme_node);
+ priv->old_theme_node = NULL;
+ }
+
+ if (priv->new_theme_node)
+ {
+ g_object_unref (priv->new_theme_node);
+ priv->new_theme_node = NULL;
+ }
+
+ if (priv->old_texture)
+ {
+ cogl_handle_unref (priv->old_texture);
+ priv->old_texture = NULL;
+ }
+
+ if (priv->new_texture)
+ {
+ cogl_handle_unref (priv->new_texture);
+ priv->new_texture = NULL;
+ }
+
+ if (priv->old_offscreen)
+ {
+ cogl_handle_unref (priv->old_offscreen);
+ priv->old_offscreen = NULL;
+ }
+
+ if (priv->new_offscreen)
+ {
+ cogl_handle_unref (priv->new_offscreen);
+ priv->new_offscreen = NULL;
+ }
+
+ if (priv->material)
+ {
+ cogl_handle_unref (priv->material);
+ priv->material = NULL;
+ }
+
+ if (priv->timeline)
+ {
+ if (priv->timeline_completed_id != 0)
+ g_signal_handler_disconnect (priv->timeline,
+ priv->timeline_completed_id);
+ if (priv->timeline_new_frame_id != 0)
+ g_signal_handler_disconnect (priv->timeline,
+ priv->timeline_new_frame_id);
+
+ g_object_unref (priv->timeline);
+ priv->timeline = NULL;
+ }
+
+ priv->timeline_completed_id = 0;
+ priv->timeline_new_frame_id = 0;
+
+ if (priv->alpha)
+ {
+ g_object_unref (priv->alpha);
+ priv->alpha = NULL;
+ }
+
+ G_OBJECT_CLASS (st_theme_node_transition_parent_class)->dispose (object);
+}
+
+static void
+st_theme_node_transition_init (StThemeNodeTransition *transition)
+{
+ transition->priv = ST_THEME_NODE_TRANSITION_GET_PRIVATE (transition);
+
+ transition->priv->old_theme_node = NULL;
+ transition->priv->new_theme_node = NULL;
+
+ transition->priv->old_texture = NULL;
+ transition->priv->new_texture = NULL;
+
+ transition->priv->old_offscreen = NULL;
+ transition->priv->new_offscreen = NULL;
+
+ transition->priv->needs_setup = TRUE;
+
+ transition->priv->alpha = NULL;
+}
+
+static void
+st_theme_node_transition_class_init (StThemeNodeTransitionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (StThemeNodeTransitionPrivate));
+
+ object_class->dispose = st_theme_node_transition_dispose;
+
+ signals[COMPLETED] =
+ g_signal_new ("completed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (StThemeNodeTransitionClass, completed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[NEW_FRAME] =
+ g_signal_new ("new-frame",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (StThemeNodeTransitionClass, new_frame),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
diff --git a/src/st/st-theme-node-transition.h b/src/st/st-theme-node-transition.h
new file mode 100644
index 0000000..2f237b1
--- /dev/null
+++ b/src/st/st-theme-node-transition.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __ST_THEME_NODE_TRANSITION_H__
+#define __ST_THEME_NODE_TRANSITION_H__
+
+#include <clutter/clutter.h>
+
+#include "st-widget.h"
+#include "st-theme-node.h"
+
+G_BEGIN_DECLS
+
+#define ST_TYPE_THEME_NODE_TRANSITION (st_theme_node_transition_get_type ())
+#define ST_THEME_NODE_TRANSITION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), ST_TYPE_THEME_NODE_TRANSITION, StThemeNodeTransition))
+#define ST_IS_THEME_NODE_TRANSITION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), ST_TYPE_THEME_NODE_TRANSITION))
+#define ST_THEME_NODE_TRANSITION_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), ST_TYPE_THEME_NODE_TRANSITION, StThemeNodeTransitionClass))
+#define ST_IS_THEME_NODE_TRANSITION_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), ST_TYPE_THEME_NODE_TRANSITION))
+#define ST_THEME_NODE_TRANSITION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), ST_THEME_NODE_TRANSITION, StThemeNodeTransitionClass))
+
+typedef struct _StThemeNodeTransition StThemeNodeTransition;
+typedef struct _StThemeNodeTransitionClass StThemeNodeTransitionClass;
+typedef struct _StThemeNodeTransitionPrivate StThemeNodeTransitionPrivate;
+
+struct _StThemeNodeTransition {
+ GObject parent;
+
+ StThemeNodeTransitionPrivate *priv;
+};
+
+struct _StThemeNodeTransitionClass {
+ GObjectClass parent_class;
+
+ void (*completed) (StThemeNodeTransition *transition);
+ void (*new_frame) (StThemeNodeTransition *transition);
+};
+
+GType st_theme_node_transition_get_type (void) G_GNUC_CONST;
+
+StThemeNodeTransition *st_theme_node_transition_new (StThemeNode *from_node,
+ StThemeNode *to_node,
+ guint duration);
+
+void st_theme_node_transition_update (StThemeNodeTransition *transition,
+ StThemeNode *new_node);
+
+void st_theme_node_transition_paint (StThemeNodeTransition *transition,
+ ClutterActorBox *allocation,
+ guint8 paint_opacity);
+
+G_END_DECLS
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]