[gnome-shell] StScrollView: Implement real fade effect



commit 00ba93717141ce149e1708594bdb24b12a7653c3
Author: Adel Gadllah <adel gadllah gmail com>
Date:   Thu Jan 20 20:25:21 2011 +0100

    StScrollView: Implement real fade effect
    
    Implement an edge fade effect (top/bottom) using a
    ClutterOffscreenEffect subclass, replacing the former
    shadow hack.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=639460

 js/ui/appDisplay.js                     |    2 +-
 js/ui/messageTray.js                    |    2 +-
 js/ui/searchDisplay.js                  |    2 +-
 src/Makefile-st.am                      |    8 +-
 src/Makefile.am                         |    2 +-
 src/st/st-scroll-view-fade.c            |  348 +++++++++++++++++++++++++++++++
 src/st/st-scroll-view-fade.h            |   40 ++++
 src/st/st-scroll-view.c                 |  179 ++++-------------
 src/st/st-scroll-view.h                 |    4 +-
 tests/interactive/scroll-view-sizing.js |   18 +-
 10 files changed, 446 insertions(+), 159 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 4b460fc..f1d44eb 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -40,7 +40,7 @@ AlphabeticalView.prototype = {
         this.actor = new St.ScrollView({ x_fill: true,
                                          y_fill: false,
                                          y_align: St.Align.START,
-                                         vshadows: true });
+                                         vfade: true });
         this.actor.add_actor(box);
         this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
     },
diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js
index c158c03..073b87a 100644
--- a/js/ui/messageTray.js
+++ b/js/ui/messageTray.js
@@ -386,7 +386,7 @@ Notification.prototype = {
             this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
                                                    vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
                                                    hscrollbar_policy: Gtk.PolicyType.NEVER,
-                                                   vshadows: true });
+                                                   vfade: true });
             this.actor.add(this._scrollArea, { row: 1,
                                                col: 1 });
             this._contentArea = new St.BoxLayout({ name: 'notification-body',
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
index fe6c760..f85eb67 100644
--- a/js/ui/searchDisplay.js
+++ b/js/ui/searchDisplay.js
@@ -166,7 +166,7 @@ SearchResults.prototype = {
 
         let scrollView = new St.ScrollView({ x_fill: true,
                                              y_fill: false,
-                                             vshadows: true });
+                                             vfade: true });
         scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
         scrollView.add_actor(this._content);
 
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index 225ff5b..cb54ef4 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -159,11 +159,17 @@ st_source_c =					\
 	st/st-widget.c				\
 	$(NULL)
 
+st_non_gir_sources =           \
+	st/st-scroll-view-fade.c	\
+	st/st-scroll-view-fade.h	\
+	$(NULL)
+
 noinst_LTLIBRARIES += libst-1.0.la
 
 libst_1_0_la_LIBADD = -lm $(ST_LIBS)
 libst_1_0_la_SOURCES =				\
-	$(st_source_c)				\
+	$(st_source_c)					\
+	$(st_non_gir_sources)			\
 	$(st_source_private_h)			\
 	$(st_source_private_c)			\
 	$(st_source_h)				\
diff --git a/src/Makefile.am b/src/Makefile.am
index f252e5b..5bfa8c7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -262,7 +262,7 @@ St-1.0.gir: $(mutter) $(G_IR_SCANNER) libst-1.0.la Makefile
 	        --libtool="$(LIBTOOL)"						\
 	        --library=libst-1.0.la						\
 	        -DST_COMPILATION						\
-	        $(filter-out %-private.h, $(addprefix $(srcdir)/,$(st_source_h))) \
+	        $(filter-out %-private.h $(st_non_gir_sources), $(addprefix $(srcdir)/,$(st_source_h))) \
 	        $(addprefix $(srcdir)/,$(st_source_c))				\
 	        $(srcdir)/st-enum-types.h					\
 	        $(st_cflags)							\
diff --git a/src/st/st-scroll-view-fade.c b/src/st/st-scroll-view-fade.c
new file mode 100644
index 0000000..050cea5
--- /dev/null
+++ b/src/st/st-scroll-view-fade.c
@@ -0,0 +1,348 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * st-scroll-view-fade.h: Edge fade effect for StScrollView
+ *
+ * Copyright 2010 Intel Corporation.
+ * Copyright 2011 Adel Gadllah
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#define ST_SCROLL_VIEW_FADE_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFadeClass))
+#define ST_IS_SCROLL_VIEW_FADE_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_SCROLL_VIEW_FADE))
+#define ST_SCROLL_VIEW_FADE_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFadeClass))
+
+#include "st-scroll-view-fade.h"
+#include "st-scroll-view.h"
+#include "st-scroll-bar.h"
+#include "st-scrollable.h"
+
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+
+typedef struct _StScrollViewFadeClass  StScrollViewFadeClass;
+
+#define FADE_OFFSET 68.0f
+
+static const gchar *fade_glsl_shader =
+"uniform sampler2D tex;\n"
+"uniform float height;\n"
+"uniform float width;\n"
+"uniform float scrollbar_width;\n"
+"uniform float offset_bottom;\n"
+"uniform float offset_top;\n"
+"\n"
+"void main ()\n"
+"{\n"
+" vec4 color = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));\n"
+" float y = height * cogl_tex_coord_in[0].y;\n"
+" float x = width * cogl_tex_coord_in[0].x;\n"
+" float ratio = 0.0;\n"
+" float fade_bottom_start = height - offset_bottom;\n"
+" \n"
+" if (offset_top != 0.0 && y < offset_top && x < (width - scrollbar_width)) {\n"
+"  ratio = y / offset_top;\n"
+"  cogl_color_out = color * ratio;\n"
+" }\n"
+" else if (offset_bottom != 0.0 && y > fade_bottom_start && x < (width - scrollbar_width)) {\n"
+"  ratio = (height - y)/(height - fade_bottom_start);\n"
+"  cogl_color_out = color * ratio;\n"
+" }\n"
+" else { \n"
+"  cogl_color_out = color;\n"
+" }\n"
+"}\n";
+
+struct _StScrollViewFade
+{
+  ClutterOffscreenEffect parent_instance;
+
+  /* a back pointer to our actor, so that we can query it */
+  ClutterActor *actor;
+
+  CoglHandle shader;
+  CoglHandle program;
+
+  gint tex_uniform;
+  gint height_uniform;
+  gint width_uniform;
+  gint scrollbar_width_uniform;
+  gint offset_top_uniform;
+  gint offset_bottom_uniform;
+
+  StAdjustment *vadjustment;
+
+  guint is_attached : 1;
+};
+
+struct _StScrollViewFadeClass
+{
+  ClutterOffscreenEffectClass parent_class;
+};
+
+G_DEFINE_TYPE (StScrollViewFade,
+               st_scroll_view_fade,
+               CLUTTER_TYPE_OFFSCREEN_EFFECT);
+
+static gboolean
+st_scroll_view_fade_pre_paint (ClutterEffect *effect)
+{
+  StScrollViewFade *self = ST_SCROLL_VIEW_FADE (effect);
+  ClutterEffectClass *parent_class;
+
+  if (self->shader == COGL_INVALID_HANDLE)
+    return FALSE;
+
+  if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
+    return FALSE;
+
+  if (self->actor == NULL)
+    return FALSE;
+
+  if (self->program == COGL_INVALID_HANDLE)
+    self->program = cogl_create_program ();
+
+  if (!self->is_attached)
+    {
+      g_assert (self->shader != COGL_INVALID_HANDLE);
+      g_assert (self->program != COGL_INVALID_HANDLE);
+
+      cogl_program_attach_shader (self->program, self->shader);
+      cogl_program_link (self->program);
+
+      cogl_handle_unref (self->shader);
+
+      self->is_attached = TRUE;
+
+      self->tex_uniform =
+        cogl_program_get_uniform_location (self->program, "tex");
+      self->height_uniform =
+        cogl_program_get_uniform_location (self->program, "height");
+      self->width_uniform =
+        cogl_program_get_uniform_location (self->program, "width");
+      self->scrollbar_width_uniform =
+        cogl_program_get_uniform_location (self->program, "scrollbar_width");
+      self->offset_top_uniform =
+        cogl_program_get_uniform_location (self->program, "offset_top");
+      self->offset_bottom_uniform =
+        cogl_program_get_uniform_location (self->program, "offset_bottom");
+    }
+
+  parent_class = CLUTTER_EFFECT_CLASS (st_scroll_view_fade_parent_class);
+  return parent_class->pre_paint (effect);
+}
+
+static CoglHandle
+st_scroll_view_fade_create_texture (ClutterOffscreenEffect *effect,
+                                    gfloat                  min_width,
+                                    gfloat                  min_height)
+{
+  return cogl_texture_new_with_size (min_width,
+                                     min_height,
+                                     COGL_TEXTURE_NO_SLICING,
+                                     COGL_PIXEL_FORMAT_RGBA_8888_PRE);
+}
+
+static void
+st_scroll_view_fade_paint_target (ClutterOffscreenEffect *effect)
+{
+  StScrollViewFade *self = ST_SCROLL_VIEW_FADE (effect);
+  ClutterOffscreenEffectClass *parent;
+  CoglHandle material;
+
+  gdouble value, lower, upper, page_size;
+  ClutterActor *vscroll = st_scroll_view_get_vscroll_bar (ST_SCROLL_VIEW (self->actor));
+
+  if (self->program == COGL_INVALID_HANDLE)
+    goto out;
+
+  st_adjustment_get_values (self->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
+
+  if (self->offset_top_uniform > -1) {
+    if (value > lower + 0.1)
+      cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, FADE_OFFSET);
+    else
+      cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, 0.0f);
+  }
+
+  if (self->offset_bottom_uniform > -1) {
+    if (value < upper - page_size - 0.1)
+      cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, FADE_OFFSET);
+    else
+      cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, 0.0f);
+  }
+
+  if (self->tex_uniform > -1)
+    cogl_program_set_uniform_1i (self->program, self->tex_uniform, 0);
+  if (self->height_uniform > -1)
+    cogl_program_set_uniform_1f (self->program, self->height_uniform, clutter_actor_get_height (self->actor));
+  if (self->width_uniform > -1)
+    cogl_program_set_uniform_1f (self->program, self->width_uniform, clutter_actor_get_width (self->actor));
+  if (self->scrollbar_width_uniform > -1)
+    cogl_program_set_uniform_1f (self->program, self->scrollbar_width_uniform, clutter_actor_get_width (vscroll));
+
+  material = clutter_offscreen_effect_get_target (effect);
+  cogl_material_set_user_program (material, self->program);
+
+out:
+  parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (st_scroll_view_fade_parent_class);
+  parent->paint_target (effect);
+}
+
+static void
+on_vadjustment_changed (StAdjustment *adjustment,
+                        ClutterEffect *effect)
+{
+  gdouble value, lower, upper, page_size;
+  gboolean needs_fade;
+
+  st_adjustment_get_values (adjustment, &value, &lower, &upper, NULL, NULL, &page_size);
+  needs_fade = (value > lower + 0.1) || (value < upper - page_size - 0.1);
+
+  clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), needs_fade);
+}
+
+static void
+st_scroll_view_fade_set_actor (ClutterActorMeta *meta,
+                               ClutterActor *actor)
+{
+  StScrollViewFade *self = ST_SCROLL_VIEW_FADE (meta);
+  ClutterActorMetaClass *parent;
+
+  g_return_if_fail (actor == NULL || ST_IS_SCROLL_VIEW (actor));
+
+  if (self->shader == COGL_INVALID_HANDLE)
+    {
+      clutter_actor_meta_set_enabled (meta, FALSE);
+      return;
+    }
+
+  if (self->vadjustment)
+    {
+      g_signal_handlers_disconnect_by_func (self->vadjustment,
+                                            (gpointer)on_vadjustment_changed,
+                                            self);
+      self->vadjustment = NULL;
+    }
+
+  if (actor)
+    {
+        StScrollView *scroll_view = ST_SCROLL_VIEW (actor);
+        StScrollBar *vscroll = ST_SCROLL_BAR (st_scroll_view_get_vscroll_bar (scroll_view));
+        self->vadjustment = ST_ADJUSTMENT (st_scroll_bar_get_adjustment (vscroll));
+
+        g_signal_connect (self->vadjustment, "changed",
+                          G_CALLBACK (on_vadjustment_changed),
+                          self);
+
+        on_vadjustment_changed (self->vadjustment, CLUTTER_EFFECT (self));
+    }
+
+  parent = CLUTTER_ACTOR_META_CLASS (st_scroll_view_fade_parent_class);
+  parent->set_actor (meta, actor);
+
+  /* we keep a back pointer here, to avoid going through the ActorMeta */
+  self->actor = clutter_actor_meta_get_actor (meta);
+}
+
+static void
+st_scroll_view_fade_dispose (GObject *gobject)
+{
+  StScrollViewFade *self = ST_SCROLL_VIEW_FADE (gobject);
+
+  if (self->program != COGL_INVALID_HANDLE)
+    {
+      cogl_handle_unref (self->program);
+
+      self->program = COGL_INVALID_HANDLE;
+      self->shader = COGL_INVALID_HANDLE;
+    }
+
+  if (self->vadjustment)
+    {
+      g_signal_handlers_disconnect_by_func (self->vadjustment,
+                                            (gpointer)on_vadjustment_changed,
+                                            self);
+      self->vadjustment = NULL;
+    }
+
+  self->actor = NULL;
+
+  G_OBJECT_CLASS (st_scroll_view_fade_parent_class)->dispose (gobject);
+}
+
+static void
+st_scroll_view_fade_class_init (StScrollViewFadeClass *klass)
+{
+  ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  ClutterOffscreenEffectClass *offscreen_class;
+  ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
+
+  gobject_class->dispose = st_scroll_view_fade_dispose;
+
+  meta_class->set_actor = st_scroll_view_fade_set_actor;
+
+  effect_class->pre_paint = st_scroll_view_fade_pre_paint;
+
+  offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
+  offscreen_class->create_texture = st_scroll_view_fade_create_texture;
+  offscreen_class->paint_target = st_scroll_view_fade_paint_target;
+}
+
+
+static void
+st_scroll_view_fade_init (StScrollViewFade *self)
+{
+  static CoglHandle shader = COGL_INVALID_HANDLE;
+
+  if (shader == COGL_INVALID_HANDLE)
+    {
+      if (clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
+        {
+          shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
+          cogl_shader_source (shader, fade_glsl_shader);
+          cogl_shader_compile (shader);
+          if (!cogl_shader_is_compiled (shader))
+            {
+              gchar *log_buf = cogl_shader_get_info_log (shader);
+
+              g_warning (G_STRLOC ": Unable to compile the fade shader: %s",
+                         log_buf);
+              g_free (log_buf);
+
+              cogl_handle_unref (shader);
+              shader = COGL_INVALID_HANDLE;
+          }
+        }
+    }
+
+  self->shader = shader;
+  self->is_attached = FALSE;
+  self->tex_uniform = -1;
+  self->height_uniform = -1;
+  self->width_uniform = -1;
+  self->scrollbar_width_uniform = -1;
+  self->offset_top_uniform = -1;
+  self->offset_bottom_uniform = -1;
+
+  if (shader != COGL_INVALID_HANDLE)
+    cogl_handle_ref (self->shader);
+}
+
+ClutterEffect *
+st_scroll_view_fade_new (void)
+{
+  return g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
+}
diff --git a/src/st/st-scroll-view-fade.h b/src/st/st-scroll-view-fade.h
new file mode 100644
index 0000000..f8ec2d5
--- /dev/null
+++ b/src/st/st-scroll-view-fade.h
@@ -0,0 +1,40 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * st-scroll-view-fade.h: Edge fade effect for StScrollView
+ *
+ * Copyright 2010 Intel Corporation.
+ * Copyright 2011 Adel Gadllah
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ST_SCROLL_VIEW_FADE_H__
+#define __ST_SCROLL_VIEW_FADE_H__
+
+#include <clutter/clutter.h>
+
+G_BEGIN_DECLS
+
+#define ST_TYPE_SCROLL_VIEW_FADE        (st_scroll_view_fade_get_type ())
+#define ST_SCROLL_VIEW_FADE(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFade))
+#define ST_IS_SCROLL_VIEW_FADE(obj)     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_SCROLL_VIEW_FADE))
+
+typedef struct _StScrollViewFade       StScrollViewFade;
+
+GType st_scroll_view_fade_get_type (void) G_GNUC_CONST;
+
+ClutterEffect *st_scroll_view_fade_new (void);
+
+G_END_DECLS
+
+#endif /* __ST_SCROLL_VIEW_FADE_H__ */
diff --git a/src/st/st-scroll-view.c b/src/st/st-scroll-view.c
index 14df600..c56182e 100644
--- a/src/st/st-scroll-view.c
+++ b/src/st/st-scroll-view.c
@@ -62,6 +62,7 @@
 #include "st-marshal.h"
 #include "st-scroll-bar.h"
 #include "st-scrollable.h"
+#include "st-scroll-view-fade.h"
 #include <clutter/clutter.h>
 #include <math.h>
 
@@ -93,20 +94,17 @@ struct _StScrollViewPrivate
   GtkPolicyType hscrollbar_policy;
   GtkPolicyType vscrollbar_policy;
 
-  ClutterActor *top_shadow;
-  ClutterActor *bottom_shadow;
-
   gfloat        row_size;
   gfloat        column_size;
 
-  gboolean      vshadows;
+  gboolean      vfade;
+  StScrollViewFade *vfade_effect;
+
   gboolean      row_size_set : 1;
   gboolean      column_size_set : 1;
   guint         mouse_scroll : 1;
   guint         hscrollbar_visible : 1;
   guint         vscrollbar_visible : 1;
-  guint         top_shadow_visible : 1;
-  guint         bottom_shadow_visible : 1;
 };
 
 enum {
@@ -117,7 +115,7 @@ enum {
   PROP_HSCROLLBAR_POLICY,
   PROP_VSCROLLBAR_POLICY,
   PROP_MOUSE_SCROLL,
-  PROP_VSHADOWS
+  PROP_VFADE
 };
 
 static void
@@ -145,80 +143,50 @@ st_scroll_view_get_property (GObject    *object,
     case PROP_MOUSE_SCROLL:
       g_value_set_boolean (value, priv->mouse_scroll);
       break;
-    case PROP_VSHADOWS:
-      g_value_set_boolean (value, priv->vshadows);
+    case PROP_VFADE:
+      g_value_set_boolean (value, priv->vfade);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
 }
 
-static void
-update_shadow_visibility (StScrollView *scroll)
-{
-  StScrollViewPrivate *priv = scroll->priv;
-
-  if (priv->vshadows)
-    {
-      gdouble value, lower, upper, page_size;
-
-      st_adjustment_get_values (priv->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
-
-      priv->top_shadow_visible = value > lower + 0.1;
-      priv->bottom_shadow_visible = value < upper - page_size - 0.1;
-    }
-  else
-    {
-      priv->top_shadow_visible = FALSE;
-      priv->bottom_shadow_visible = FALSE;
-    }
-}
-
 /**
- * st_scroll_view_set_vshadows:
+ * st_scroll_view_set_vfade:
  * @self: a #StScrollView
- * @vshadows: Whether to enable vertical shadows
+ * @vfade: Whether to enable the vertical fade effect
  *
- * Sets whether to show shadows at the top and bottom of the area. Shadows
- * are omitted when fully scrolled to that edge.
+ * Sets whether to fade the content at the top and bottom of the area when not
+ * fully scrolled to that edge.
  */
 void
-st_scroll_view_set_vshadows (StScrollView *self,
-                             gboolean      vshadows)
+st_scroll_view_set_vfade (StScrollView *self,
+                          gboolean vfade)
 {
   StScrollViewPrivate *priv = ST_SCROLL_VIEW (self)->priv;
 
-  vshadows = vshadows != FALSE;
-  if (priv->vshadows == vshadows)
+  vfade = vfade != FALSE;
+  if (priv->vfade == vfade)
     return;
 
-  priv->vshadows = vshadows;
+  priv->vfade = vfade;
 
-  if (vshadows)
+  if (vfade)
     {
-      if (priv->top_shadow)
-        {
-          clutter_actor_show (priv->top_shadow);
-          clutter_actor_show (priv->bottom_shadow);
-        }
-      else
-        {
-          priv->top_shadow = g_object_new (ST_TYPE_BIN, "style-class", "top-shadow", NULL);
-          priv->bottom_shadow = g_object_new (ST_TYPE_BIN, "style-class", "bottom-shadow", NULL);
+      if (priv->vfade_effect == NULL)
+        priv->vfade_effect = g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
 
-          clutter_actor_set_parent (priv->bottom_shadow, CLUTTER_ACTOR (self));
-          clutter_actor_set_parent (priv->top_shadow, CLUTTER_ACTOR (self));
-        }
+      clutter_actor_add_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
     }
-  else
+   else
     {
-      clutter_actor_hide (priv->top_shadow);
-      clutter_actor_hide (priv->bottom_shadow);
+      clutter_actor_remove_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
+      priv->vfade_effect = NULL;
     }
 
-  update_shadow_visibility (self);
+  clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
 
-  g_object_notify (G_OBJECT (self), "vshadows");
+  g_object_notify (G_OBJECT (self), "vfade");
 }
 
 static void
@@ -232,8 +200,8 @@ st_scroll_view_set_property (GObject      *object,
 
   switch (property_id)
     {
-    case PROP_VSHADOWS:
-      st_scroll_view_set_vshadows (self, g_value_get_boolean (value));
+    case PROP_VFADE:
+      st_scroll_view_set_vfade (self, g_value_get_boolean (value));
       break;
     case PROP_MOUSE_SCROLL:
       st_scroll_view_set_mouse_scrolling (self,
@@ -259,6 +227,12 @@ st_scroll_view_dispose (GObject *object)
 {
   StScrollViewPrivate *priv = ST_SCROLL_VIEW (object)->priv;
 
+  if (priv->vfade_effect)
+    {
+      clutter_actor_remove_effect (CLUTTER_ACTOR (object), CLUTTER_EFFECT (priv->vfade_effect));
+      priv->vfade_effect = NULL;
+    }
+
   if (priv->vscroll)
     clutter_actor_destroy (priv->vscroll);
 
@@ -284,20 +258,6 @@ st_scroll_view_dispose (GObject *object)
       priv->vadjustment = NULL;
     }
 
-  /* since it's impossible to get a handle to these actors, we can
-   * just directly unparent them and not go through destroy/remove */
-  if (priv->top_shadow)
-    {
-      clutter_actor_unparent (priv->top_shadow);
-      priv->top_shadow = NULL;
-    }
-
-  if (priv->bottom_shadow)
-    {
-      clutter_actor_unparent (priv->bottom_shadow);
-      priv->bottom_shadow = NULL;
-    }
-
   G_OBJECT_CLASS (st_scroll_view_parent_class)->dispose (object);
 }
 
@@ -314,11 +274,6 @@ st_scroll_view_paint (ClutterActor *actor)
     clutter_actor_paint (priv->hscroll);
   if (priv->vscrollbar_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
     clutter_actor_paint (priv->vscroll);
-
-  if (priv->top_shadow_visible)
-    clutter_actor_paint (priv->top_shadow);
-  if (priv->bottom_shadow_visible)
-    clutter_actor_paint (priv->bottom_shadow);
 }
 
 static void
@@ -532,18 +487,6 @@ st_scroll_view_get_preferred_height (ClutterActor *actor,
   st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
 }
 
-static gfloat
-get_shadow_height (ClutterActor *shadow)
-{
-  gfloat natural_height;
-
-  /* The shadows are empty StBin and have no height-for-width behavior */
-
-  clutter_actor_get_preferred_height (shadow, -1, NULL, &natural_height);
-
-  return natural_height;
-}
-
 static void
 st_scroll_view_allocate (ClutterActor          *actor,
                          const ClutterActorBox *box,
@@ -688,25 +631,6 @@ st_scroll_view_allocate (ClutterActor          *actor,
   if (priv->child)
     clutter_actor_allocate (priv->child, &child_box, flags);
 
-  /* Shadows */
-  if (priv->top_shadow && CLUTTER_ACTOR_IS_VISIBLE (priv->top_shadow))
-    {
-      child_box.x1 = content_box.x1;
-      child_box.y1 = content_box.y1;
-      child_box.x2 = MAX (child_box.x1, content_box.x2 - sb_width);
-      child_box.y2 = content_box.y1 + get_shadow_height (priv->top_shadow);
-      clutter_actor_allocate (priv->top_shadow, &child_box, flags);
-    }
-
-  if (priv->bottom_shadow && CLUTTER_ACTOR_IS_VISIBLE (priv->bottom_shadow))
-    {
-      child_box.x1 = content_box.x1;
-      child_box.y1 = content_box.y2 - sb_height - get_shadow_height (priv->bottom_shadow);
-      child_box.x2 = MAX (content_box.x1, content_box.x2 - sb_width);
-      child_box.y2 = content_box.y2 - sb_height;
-      clutter_actor_allocate (priv->bottom_shadow, &child_box, flags);
-    }
-
   priv->hscrollbar_visible = hscrollbar_visible;
   priv->vscrollbar_visible = vscrollbar_visible;
 }
@@ -719,12 +643,6 @@ st_scroll_view_style_changed (StWidget *widget)
   st_widget_style_changed (ST_WIDGET (priv->hscroll));
   st_widget_style_changed (ST_WIDGET (priv->vscroll));
 
-  if (priv->top_shadow)
-    {
-      st_widget_style_changed (ST_WIDGET (priv->top_shadow));
-      st_widget_style_changed (ST_WIDGET (priv->bottom_shadow));
-    }
-
   ST_WIDGET_CLASS (st_scroll_view_parent_class)->style_changed (widget);
 }
 
@@ -857,32 +775,17 @@ st_scroll_view_class_init (StScrollViewClass *klass)
                                    PROP_MOUSE_SCROLL,
                                    pspec);
 
-  pspec = g_param_spec_boolean ("vshadows",
+  pspec = g_param_spec_boolean ("vfade",
                                 "Vertical Shadows",
-                                "Show shadows at the top and and bottom of the area unless fully scrolled to that edge",
+                                "Fade the content at the top and and bottom of the area unless fully scrolled to that edge",
                                 FALSE,
                                 G_PARAM_READWRITE);
   g_object_class_install_property (object_class,
-                                   PROP_VSHADOWS,
+                                   PROP_VFADE,
                                    pspec);
 }
 
 static void
-child_adjustment_changed_cb (StAdjustment *adjustment,
-                             StScrollView *scroll)
-{
-  update_shadow_visibility (scroll);
-}
-
-static void
-child_adjustment_notify_value (GObject      *gobject,
-                               GParamSpec   *pspec,
-                               StScrollView *scroll)
-{
-  update_shadow_visibility (scroll);
-}
-
-static void
 st_scroll_view_init (StScrollView *self)
 {
   StScrollViewPrivate *priv = self->priv = SCROLL_VIEW_PRIVATE (self);
@@ -897,10 +800,6 @@ st_scroll_view_init (StScrollView *self)
                                 NULL);
 
   priv->vadjustment = g_object_new (ST_TYPE_ADJUSTMENT, NULL);
-  g_signal_connect (priv->vadjustment, "changed",
-                    G_CALLBACK (child_adjustment_changed_cb), self);
-  g_signal_connect (priv->vadjustment, "notify::value",
-                    G_CALLBACK (child_adjustment_notify_value), self);
   priv->vscroll = g_object_new (ST_TYPE_SCROLL_BAR,
                                 "adjustment", priv->vadjustment,
                                 "vertical", TRUE,
@@ -988,12 +887,6 @@ st_scroll_view_foreach_with_internals (ClutterContainer *container,
 
   if (priv->vscroll != NULL)
     callback (priv->vscroll, user_data);
-
-  if (priv->top_shadow)
-    {
-      callback (priv->top_shadow, user_data);
-      callback (priv->bottom_shadow, user_data);
-    }
 }
 
 static void
diff --git a/src/st/st-scroll-view.h b/src/st/st-scroll-view.h
index ddb1ebb..f0a03fe 100644
--- a/src/st/st-scroll-view.h
+++ b/src/st/st-scroll-view.h
@@ -84,8 +84,8 @@ void          st_scroll_view_set_policy          (StScrollView   *scroll,
                                                   GtkPolicyType   hscroll,
                                                   GtkPolicyType   vscroll);
 
-void          st_scroll_view_set_vshadows        (StScrollView *self,
-                                                  gboolean      vshadows);
+void          st_scroll_view_set_vfade           (StScrollView *self,
+                                                  gboolean      vfade);
 
 G_END_DECLS
 
diff --git a/tests/interactive/scroll-view-sizing.js b/tests/interactive/scroll-view-sizing.js
index c7c8c95..4ea5b8a 100644
--- a/tests/interactive/scroll-view-sizing.js
+++ b/tests/interactive/scroll-view-sizing.js
@@ -319,17 +319,17 @@ function togglePolicy(button) {
 hpolicy.connect('clicked', function() { togglePolicy(hpolicy); });
 vpolicy.connect('clicked', function() { togglePolicy(vpolicy); });
 
-let shadowsBox = new St.BoxLayout({ vertical: false });
-mainBox.add(shadowsBox);
+let fadeBox = new St.BoxLayout({ vertical: false });
+mainBox.add(fadeBox);
 
 spacer = new St.Bin();
-shadowsBox.add(spacer, { expand: true });
+fadeBox.add(spacer, { expand: true });
 
-shadowsBox.add(new St.Label({ text: 'Vertical Shadows: '}));
-let vshadows = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' });
-shadowsBox.add(vshadows);
+fadeBox.add(new St.Label({ text: 'Vertical Fade: '}));
+let vfade = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' });
+fadeBox.add(vfade);
 
-function toggleShadows(button) {
+function toggleFade(button) {
     switch(button.label) {
     case 'No':
 	button.label = 'Yes';
@@ -338,10 +338,10 @@ function toggleShadows(button) {
 	button.label = 'No';
 	break;
     }
-    scrollView.set_vshadows(vshadows.label == 'Yes');
+    scrollView.set_vfade(vfade.label == 'Yes');
 }
 
-vshadows.connect('clicked', function() { toggleShadows(vshadows); });
+vfade.connect('clicked', function() { toggleFade(vfade); });
 
 stage.show();
 Clutter.main();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]