[gnome-shell] Add a radial background shade for modal dialogs



commit 7e9ecf4eb2ace6668be5aa53d17597fa859d9f62
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sat Dec 15 02:41:03 2012 +0100

    Add a radial background shade for modal dialogs
    
    Use a new ShellGLSLQuad actor class to build a RadialEffect that can be
    enabled on Lightboxes to achieve a radial effect similar to the overview
    one. Then enable it for modal dialogs.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=669798

 js/ui/lightbox.js     |   40 +++++++++++-
 js/ui/modalDialog.js  |    3 +-
 src/Makefile.am       |    2 +
 src/shell-glsl-quad.c |  166 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-glsl-quad.h |   64 +++++++++++++++++++
 5 files changed, 270 insertions(+), 5 deletions(-)
---
diff --git a/js/ui/lightbox.js b/js/ui/lightbox.js
index 48a3c8e..e8d391f 100644
--- a/js/ui/lightbox.js
+++ b/js/ui/lightbox.js
@@ -5,12 +5,38 @@ const Lang = imports.lang;
 const Meta = imports.gi.Meta;
 const Signals = imports.signals;
 const St = imports.gi.St;
+const Shell = imports.gi.Shell;
 
 const Params = imports.misc.params;
 const Tweener = imports.ui.tweener;
 
 const DEFAULT_FADE_FACTOR = 0.4;
 
+const GLSL_DIM_EFFECT_DECLARATIONS = '\
+float compute_dim_factor (const vec2 coords) {\
+   vec2 dist = coords - vec2(0.5, 0.5); \
+   float elipse_radius = 0.5; \
+   /* interpolate darkening value, based on distance from screen center */ \
+   float val = min(length(dist), elipse_radius); \
+   return mix(0.3, 1.0, val / elipse_radius) * 0.4; \
+}';
+const GLSL_DIM_EFFECT_CODE = '\
+   float a = compute_dim_factor (cogl_tex_coord0_in.xy);\
+   cogl_color_out = vec4(0, 0, 0, cogl_color_in.a * a);'
+;
+
+const RadialShaderQuad = new Lang.Class({
+    Name: 'RadialShaderQuad',
+    Extends: Shell.GLSLQuad,
+
+    vfunc_build_pipeline: function() {
+        this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT,
+                              GLSL_DIM_EFFECT_DECLARATIONS,
+                              GLSL_DIM_EFFECT_CODE,
+                              true);
+    },
+});
+
 /**
  * Lightbox:
  * @container: parent Clutter.Container
@@ -43,15 +69,21 @@ const Lightbox = new Lang.Class({
                                         width: null,
                                         height: null,
                                         fadeFactor: DEFAULT_FADE_FACTOR,
+                                        radialEffect: false,
                                       });
 
         this._container = container;
         this._children = container.get_children();
         this._fadeFactor = params.fadeFactor;
-        this.actor = new St.Bin({ x: 0,
-                                  y: 0,
-                                  style_class: 'lightbox',
-                                  reactive: params.inhibitEvents });
+        if (params.radialEffect)
+            this.actor = new RadialShaderQuad({ x: 0,
+                                                y: 0,
+                                                reactive: params.inhibitEvents });
+        else
+            this.actor = new St.Bin({ x: 0,
+                                      y: 0,
+                                      style_class: 'lightbox',
+                                      reactive: params.inhibitEvents });
 
         container.add_actor(this.actor);
         this.actor.raise_top();
diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js
index 4e444f1..366e425 100644
--- a/js/ui/modalDialog.js
+++ b/js/ui/modalDialog.js
@@ -89,7 +89,8 @@ const ModalDialog = new Lang.Class({
 
         if (!this._shellReactive) {
             this._lightbox = new Lightbox.Lightbox(this._group,
-                                                   { inhibitEvents: true });
+                                                   { inhibitEvents: true,
+                                                     radialEffect: true });
             this._lightbox.highlight(this._backgroundBin);
 
             this._eventBlocker = new Clutter.Actor({ reactive: true });
diff --git a/src/Makefile.am b/src/Makefile.am
index f240343..59c9d8f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -92,6 +92,7 @@ shell_public_headers_h =              \
        shell-app-usage.h               \
        shell-embedded-window.h         \
        shell-generic-container.h       \
+       shell-glsl-quad.h               \
        shell-gtk-embed.h               \
        shell-global.h                  \
        shell-invert-lightness-effect.h \
@@ -128,6 +129,7 @@ libgnome_shell_base_la_SOURCES =    \
        shell-embedded-window-private.h \
        shell-embedded-window.c         \
        shell-generic-container.c       \
+       shell-glsl-quad.c               \
        shell-invert-lightness-effect.c \
        shell-keyring-prompt.h          \
        shell-keyring-prompt.c          \
diff --git a/src/shell-glsl-quad.c b/src/shell-glsl-quad.c
new file mode 100644
index 0000000..5e3ce18
--- /dev/null
+++ b/src/shell-glsl-quad.c
@@ -0,0 +1,166 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+/**
+ * SECTION:shell-glsl-quad
+ * @short_description: Draw a rectangle using GLSL
+ *
+ * A #ShellGLSLQuad draws one single rectangle, sized to the allocation
+ * box, but allows running custom GLSL to the vertex and fragment
+ * stages of the graphic pipeline.
+ *
+ * To ease writing the shader, a single texture layer is also used.
+ */
+
+#include "config.h"
+
+#define CLUTTER_ENABLE_EXPERIMENTAL_API
+#define COGL_ENABLE_EXPERIMENTAL_API
+
+#include <cogl/cogl.h>
+#include "shell-glsl-quad.h"
+
+G_DEFINE_TYPE (ShellGLSLQuad, shell_glsl_quad, CLUTTER_TYPE_ACTOR);
+
+struct _ShellGLSLQuadPrivate
+{
+  CoglPipeline  *pipeline;
+  CoglTexture2D *texture;
+};
+
+static void
+shell_glsl_quad_paint (ClutterActor *actor)
+{
+  ShellGLSLQuad *self = SHELL_GLSL_QUAD (actor);
+  ShellGLSLQuadPrivate *priv;
+  guint8 paint_opacity;
+  ClutterActorBox box;
+
+  priv = self->priv;
+
+  paint_opacity = clutter_actor_get_paint_opacity (actor);
+  clutter_actor_get_allocation_box (actor, &box);
+
+  /* semi-transparent black */
+  cogl_pipeline_set_color4ub (priv->pipeline,
+                              0, 0, 0,
+                              paint_opacity);
+  cogl_framebuffer_draw_rectangle (cogl_get_draw_framebuffer (),
+                                   priv->pipeline,
+                                   box.x1, box.y1,
+                                   box.x2, box.y2);
+}
+
+
+/**
+ * shell_glsl_quad_add_glsl_snippet:
+ * @quad: a #ShellGLSLQuad
+ * @hook: where to insert the code
+ * @declarations: GLSL declarations
+ * @code: GLSL code
+ * @is_replace: wheter Cogl code should be replaced by the custom shader
+ *
+ * Adds a GLSL snippet to the pipeline used for drawing the actor texture.
+ * See #CoglSnippet for details.
+ *
+ * This is only valid inside the a call to the build_pipeline() virtual
+ * function.
+ */
+void
+shell_glsl_quad_add_glsl_snippet (ShellGLSLQuad    *quad,
+                                  ShellSnippetHook  hook,
+                                  const char       *declarations,
+                                  const char       *code,
+                                  gboolean          is_replace)
+{
+  ShellGLSLQuadClass *klass = SHELL_GLSL_QUAD_GET_CLASS (quad);
+  CoglSnippet *snippet;
+
+  g_return_if_fail (klass->base_pipeline != NULL);
+
+  if (is_replace)
+    {
+      snippet = cogl_snippet_new (hook, declarations, NULL);
+      cogl_snippet_set_replace (snippet, code);
+    }
+  else
+    {
+      snippet = cogl_snippet_new (hook, declarations, code);
+    }
+
+  if (hook == SHELL_SNIPPET_HOOK_VERTEX ||
+      hook == SHELL_SNIPPET_HOOK_FRAGMENT)
+    cogl_pipeline_add_snippet (klass->base_pipeline, snippet);
+  else
+    cogl_pipeline_add_layer_snippet (klass->base_pipeline, 0, snippet);
+
+  cogl_object_unref (snippet);
+}
+
+static void
+shell_glsl_quad_dispose (GObject *gobject)
+{
+  ShellGLSLQuad *self = SHELL_GLSL_QUAD (gobject);
+  ShellGLSLQuadPrivate *priv;
+
+  priv = self->priv;
+
+  g_clear_pointer (&priv->pipeline, cogl_object_unref);
+  g_clear_pointer (&priv->texture, cogl_object_unref);
+
+  G_OBJECT_CLASS (shell_glsl_quad_parent_class)->dispose (gobject);
+}
+
+static void
+shell_glsl_quad_init (ShellGLSLQuad *quad)
+{
+  quad->priv = G_TYPE_INSTANCE_GET_PRIVATE (quad, SHELL_TYPE_GLSL_QUAD, ShellGLSLQuadPrivate);
+}
+
+static void
+shell_glsl_quad_constructed (GObject *object)
+{
+  ShellGLSLQuad *self;
+  ShellGLSLQuadClass *klass;
+  CoglContext *ctx =
+    clutter_backend_get_cogl_context (clutter_get_default_backend ());
+  static const uint8_t tex_data[] = { 0, 0, 0, 0 };
+
+  G_OBJECT_CLASS (shell_glsl_quad_parent_class)->constructed (object);
+
+  /* Note that, differently from ClutterBlurEffect, we are calling
+     this inside constructed, not init, so klass points to the most-derived
+     GTypeClass, not ShellGLSLQuadClass.
+  */
+  klass = SHELL_GLSL_QUAD_GET_CLASS (object);
+  self = SHELL_GLSL_QUAD (object);
+
+  if (G_UNLIKELY (klass->base_pipeline == NULL))
+    {
+      klass->base_pipeline = cogl_pipeline_new (ctx);
+
+      if (klass->build_pipeline != NULL)
+        klass->build_pipeline (self);
+    }
+
+  self->priv->pipeline = cogl_pipeline_copy (klass->base_pipeline);
+
+  self->priv->texture = cogl_texture_2d_new_from_data (ctx, 1, 1,
+                                                       COGL_PIXEL_FORMAT_RGBA_8888,
+                                                       0, tex_data, NULL);
+  cogl_pipeline_set_layer_texture (self->priv->pipeline, 0,
+                                   COGL_TEXTURE (self->priv->texture));
+}
+
+static void
+shell_glsl_quad_class_init (ShellGLSLQuadClass *klass)
+{
+  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->constructed = shell_glsl_quad_constructed;
+  gobject_class->dispose = shell_glsl_quad_dispose;
+
+  actor_class->paint = shell_glsl_quad_paint;
+
+  g_type_class_add_private (klass, sizeof (ShellGLSLQuadPrivate));
+}
diff --git a/src/shell-glsl-quad.h b/src/shell-glsl-quad.h
new file mode 100644
index 0000000..04a9362
--- /dev/null
+++ b/src/shell-glsl-quad.h
@@ -0,0 +1,64 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __SHELL_GLSL_QUAD_H__
+#define __SHELL_GLSL_QUAD_H__
+
+#include "st.h"
+#include <gtk/gtk.h>
+
+/**
+ * ShellSnippetHook:
+ * Temporary hack to work around Cogl not exporting CoglSnippetHook in
+ * the 1.0 API. Don't use.
+ */
+typedef enum {
+  /* Per pipeline vertex hooks */
+  SHELL_SNIPPET_HOOK_VERTEX = 0,
+  SHELL_SNIPPET_HOOK_VERTEX_TRANSFORM,
+
+  /* Per pipeline fragment hooks */
+  SHELL_SNIPPET_HOOK_FRAGMENT = 2048,
+
+  /* Per layer vertex hooks */
+  SHELL_SNIPPET_HOOK_TEXTURE_COORD_TRANSFORM = 4096,
+
+  /* Per layer fragment hooks */
+  SHELL_SNIPPET_HOOK_LAYER_FRAGMENT = 6144,
+  SHELL_SNIPPET_HOOK_TEXTURE_LOOKUP
+} ShellSnippetHook;
+
+#define SHELL_TYPE_GLSL_QUAD                 (shell_glsl_quad_get_type ())
+#define SHELL_GLSL_QUAD(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_GLSL_QUAD, 
ShellGLSLQuad))
+#define SHELL_GLSL_QUAD_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_GLSL_QUAD, 
ShellGLSLQuadClass))
+#define SHELL_IS_GLSL_QUAD(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_GLSL_QUAD))
+#define SHELL_IS_GLSL_QUAD_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_GLSL_QUAD))
+#define SHELL_GLSL_QUAD_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_GLSL_QUAD, 
ShellGLSLQuadClass))
+
+typedef struct _ShellGLSLQuad        ShellGLSLQuad;
+typedef struct _ShellGLSLQuadClass   ShellGLSLQuadClass;
+typedef struct _ShellGLSLQuadPrivate ShellGLSLQuadPrivate;
+
+struct _ShellGLSLQuad
+{
+  ClutterActor parent;
+
+  ShellGLSLQuadPrivate *priv;
+};
+
+struct _ShellGLSLQuadClass
+{
+  ClutterActorClass parent_class;
+
+  CoglPipeline *base_pipeline;
+
+  void (*build_pipeline) (ShellGLSLQuad *effect);
+};
+
+GType shell_glsl_quad_get_type (void) G_GNUC_CONST;
+
+void shell_glsl_quad_add_glsl_snippet (ShellGLSLQuad    *quad,
+                                       ShellSnippetHook  hook,
+                                       const char       *declarations,
+                                       const char       *code,
+                                       gboolean          is_replace);
+
+#endif /* __SHELL_GLSL_QUAD_H__ */


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