[gnome-shell/wip/fullscreen] windowManager: add animations for fullscreen and unfullscreen



commit a96e113d1420ff7a5386e47ce29481ba9ab8ac0c
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Sun Sep 1 13:03:59 2013 -0700

    windowManager: add animations for fullscreen and unfullscreen
    
    We use the newly introduced feature from Mutter to hook up our own
    fullscreen and unfullscreen animations.
    To give the illusion of a transition as smooth as possible, we create a
    snapshot of the current contents of the actor before its state is
    changed, and crossfade between the two states while the size changes.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707248

 js/ui/windowManager.js   |  120 ++++++++++++++++++++++++++++++++++++++++++++++
 src/gnome-shell-plugin.c |   30 +++++++++++
 src/shell-util.c         |   55 +++++++++++++++++++++
 src/shell-util.h         |    4 ++
 src/shell-wm-private.h   |    8 +++
 src/shell-wm.c           |   64 ++++++++++++++++++++++++
 src/shell-wm.h           |    4 ++
 7 files changed, 285 insertions(+), 0 deletions(-)
---
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 5a86d5a..dd62cef 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -643,6 +643,8 @@ const WindowManager = new Lang.Class({
             this._unmaximizeWindowDone(shellwm, actor);
             this._mapWindowDone(shellwm, actor);
             this._destroyWindowDone(shellwm, actor);
+            this._fullscreenWindowDone(shellwm, actor);
+            this._unfullscreenWindowDone(shellwm, actor);
         }));
 
         this._shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
@@ -653,6 +655,8 @@ const WindowManager = new Lang.Class({
         this._shellwm.connect('unminimize', Lang.bind(this, this._unminimizeWindow));
         this._shellwm.connect('maximize', Lang.bind(this, this._maximizeWindow));
         this._shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
+        this._shellwm.connect('fullscreen', Lang.bind(this, this._fullscreenWindow));
+        this._shellwm.connect('unfullscreen', Lang.bind(this, this._unfullscreenWindow));
         this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
         this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
         this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
@@ -1180,6 +1184,122 @@ const WindowManager = new Lang.Class({
     _unmaximizeWindowDone : function(shellwm, actor) {
     },
 
+    _fullscreenWindow: function(shellwm, actor, oldRect, targetRect) {
+        if (!this._shouldAnimateActor(actor)) {
+            shellwm.completed_fullscreen(actor);
+            return;
+        }
+
+        let actorContent = Shell.util_get_content_for_window_actor(actor, oldRect);
+        let actorClone = new St.Widget({ content: actorContent });
+        actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+        actorClone.set_position(oldRect.x, oldRect.y);
+        actorClone.set_size(oldRect.width, oldRect.height);
+        Main.uiGroup.add_actor(actorClone);
+
+        actor.__fullscreenClone = actorClone;
+
+        let scaleX = targetRect.width / oldRect.width;
+        let scaleY = targetRect.height / oldRect.height;
+
+        Tweener.addTween(actorClone,
+                         { x: targetRect.x,
+                           y: targetRect.y,
+                           scaleX: scaleX,
+                           scaleY: scaleY,
+                           opacity: 0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: 'easeOutQuad',
+                           onComplete: this._fullscreenWindowDone,
+                           onCompleteScope: this,
+                           onCompleteParams: [shellwm, actor]
+                         });
+
+        actor.translation_x = actor.x;
+        actor.translation_y = actor.y;
+        actor.scaleX = 1 / scaleX;
+        actor.scaleY = 1 / scaleY;
+
+        Tweener.addTween(actor,
+                         { scaleX: 1.0,
+                           scaleY: 1.0,
+                           translation_x: 0,
+                           translation_y: 0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: 'easeOutQuad'
+                         });
+
+        shellwm.completed_fullscreen(actor);
+    },
+
+    _fullscreenWindowDone: function(shellwm, actor) {
+        Tweener.removeTweens(actor);
+
+        let actorClone = actor.__fullscreenClone;
+        if (actorClone) {
+            actorClone.destroy();
+            delete actor.__fullscreenClone;
+        }
+    },
+
+    _unfullscreenWindow: function(shellwm, actor, oldRect, targetRect) {
+        if (!this._shouldAnimateActor(actor)) {
+            shellwm.completed_unfullscreen(actor);
+            return;
+        }
+
+        let actorContent = Shell.util_get_content_for_window_actor(actor, oldRect);
+        let actorClone = new St.Widget({ content: actorContent });
+        actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+        actorClone.set_position(oldRect.x, oldRect.y);
+        actorClone.set_size(oldRect.width, oldRect.height);
+        Main.uiGroup.add_actor(actorClone);
+
+        actor.__unfullscreenClone = actorClone;
+
+        let scaleX = targetRect.width / oldRect.width;
+        let scaleY = targetRect.height / oldRect.height;
+
+        Tweener.addTween(actorClone,
+                         { x: targetRect.x,
+                           y: targetRect.y,
+                           scaleX: scaleX,
+                           scaleY: scaleY,
+                           opacity: 0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: 'easeOutQuad',
+                           onComplete: this._unfullscreenWindowDone,
+                           onCompleteScope: this,
+                           onCompleteParams: [shellwm, actor]
+                         });
+
+        actor.translation_x = -actor.x;
+        actor.translation_y = -actor.y;
+        actor.scaleX = 1 / scaleX;
+        actor.scaleY = 1 / scaleY;
+
+        Tweener.addTween(actor,
+                         { scaleX: 1.0,
+                           scaleY: 1.0,
+                           translation_x: 0,
+                           translation_y: 0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: 'easeOutQuad'
+                         });
+
+        shellwm.completed_unfullscreen(actor);
+    },
+
+    _unfullscreenWindowDone: function(shellwm, actor) {
+        Tweener.removeTweens(actor);
+
+        let actorClone = actor.__unfullscreenClone;
+        if (actorClone) {
+            actorClone.destroy();
+            delete actor.__unfullscreenClone;
+        }
+    },
+
     _hasAttachedDialogs: function(window, ignoreWindow) {
         var count = 0;
         window.foreach_transient(function(win) {
diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c
index a7266ef..3a7b11d 100644
--- a/src/gnome-shell-plugin.c
+++ b/src/gnome-shell-plugin.c
@@ -54,6 +54,14 @@ static void gnome_shell_plugin_unmaximize       (MetaPlugin          *plugin,
                                                  gint                 y,
                                                  gint                 width,
                                                  gint                 height);
+static void gnome_shell_plugin_fullscreen       (MetaPlugin          *plugin,
+                                                 MetaWindowActor     *actor,
+                                                 MetaRectangle       *old_rect,
+                                                 MetaRectangle       *target_rect);
+static void gnome_shell_plugin_unfullscreen     (MetaPlugin          *plugin,
+                                                 MetaWindowActor     *actor,
+                                                 MetaRectangle       *old_rect,
+                                                 MetaRectangle       *target_rect);
 static void gnome_shell_plugin_map              (MetaPlugin          *plugin,
                                                  MetaWindowActor     *actor);
 static void gnome_shell_plugin_destroy          (MetaPlugin          *plugin,
@@ -136,6 +144,8 @@ gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
   plugin_class->unminimize       = gnome_shell_plugin_unminimize;
   plugin_class->maximize         = gnome_shell_plugin_maximize;
   plugin_class->unmaximize       = gnome_shell_plugin_unmaximize;
+  plugin_class->fullscreen       = gnome_shell_plugin_fullscreen;
+  plugin_class->unfullscreen     = gnome_shell_plugin_unfullscreen;
   plugin_class->destroy          = gnome_shell_plugin_destroy;
 
   plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace;
@@ -305,6 +315,26 @@ gnome_shell_plugin_unmaximize (MetaPlugin         *plugin,
 }
 
 static void
+gnome_shell_plugin_fullscreen (MetaPlugin         *plugin,
+                               MetaWindowActor    *actor,
+                               MetaRectangle      *old_rect,
+                               MetaRectangle      *target_rect)
+{
+  _shell_wm_fullscreen (get_shell_wm (),
+                        actor, old_rect, target_rect);
+}
+
+static void
+gnome_shell_plugin_unfullscreen (MetaPlugin         *plugin,
+                                 MetaWindowActor    *actor,
+                                 MetaRectangle      *old_rect,
+                                 MetaRectangle      *target_rect)
+{
+  _shell_wm_unfullscreen (get_shell_wm (),
+                          actor, old_rect, target_rect);
+}
+
+static void
 gnome_shell_plugin_map (MetaPlugin         *plugin,
                         MetaWindowActor    *actor)
 {
diff --git a/src/shell-util.c b/src/shell-util.c
index ab8a0ce..efcc324 100644
--- a/src/shell-util.c
+++ b/src/shell-util.c
@@ -13,6 +13,7 @@
 #include <gtk/gtk.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gdk/gdkx.h>
+#include <meta/meta-shaped-texture.h>
 
 #include <locale.h>
 #ifdef HAVE__NL_TIME_FIRST_WEEKDAY
@@ -403,3 +404,57 @@ shell_util_text_insert_keyval (ClutterActor *actor,
 
   clutter_actor_event (actor, &event, FALSE);
 }
+
+static gboolean
+canvas_draw_cb (ClutterContent *content,
+                cairo_t        *cr,
+                gint            width,
+                gint            height,
+                gpointer        user_data)
+{
+  cairo_surface_t *surface = user_data;
+
+  cairo_set_source_surface (cr, surface, 0, 0);
+  cairo_paint (cr);
+
+  return FALSE;
+}
+
+/**
+ * shell_util_get_content_for_window_actor:
+ * @window_actor: a #MetaWindowActor
+ * @window_rect: a #MetaRectangle
+ *
+ * Returns: (transfer full): a new #ClutterContent
+ */
+ClutterContent *
+shell_util_get_content_for_window_actor (MetaWindowActor *window_actor,
+                                         MetaRectangle   *window_rect)
+{
+  ClutterActor *texture;
+  ClutterContent *content;
+  cairo_surface_t *surface;
+  cairo_rectangle_int_t clip;
+  gfloat actor_x, actor_y;
+
+  texture = meta_window_actor_get_texture (window_actor);
+  clutter_actor_get_position (CLUTTER_ACTOR (window_actor), &actor_x, &actor_y);
+
+  clip.x = window_rect->x - (gint) actor_x;
+  clip.y = window_rect->y - (gint) actor_y;
+  clip.width = window_rect->width;
+  clip.height = window_rect->height;
+
+  surface = meta_shaped_texture_get_image (META_SHAPED_TEXTURE (texture),
+                                           &clip);
+
+  content = clutter_canvas_new ();
+  clutter_canvas_set_size (CLUTTER_CANVAS (content),
+                           clip.width, clip.height);
+  g_signal_connect (content, "draw",
+                    G_CALLBACK (canvas_draw_cb), surface);
+  clutter_content_invalidate (content);
+  cairo_surface_destroy (surface);
+
+  return content;
+}
diff --git a/src/shell-util.h b/src/shell-util.h
index 4474a0d..80a1dc7 100644
--- a/src/shell-util.h
+++ b/src/shell-util.h
@@ -8,6 +8,7 @@
 #include <libsoup/soup.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <meta/meta-cursor-tracker.h>
+#include <meta/meta-window-actor.h>
 
 G_BEGIN_DECLS
 
@@ -50,6 +51,9 @@ gboolean shell_util_need_background_refresh (void);
 void shell_util_text_insert_keyval (ClutterActor *actor,
                                     guint         keyval);
 
+ClutterContent * shell_util_get_content_for_window_actor (MetaWindowActor *window_actor,
+                                                          MetaRectangle   *window_rect);
+
 G_END_DECLS
 
 #endif /* __SHELL_UTIL_H__ */
diff --git a/src/shell-wm-private.h b/src/shell-wm-private.h
index de260f2..6029190 100644
--- a/src/shell-wm-private.h
+++ b/src/shell-wm-private.h
@@ -24,6 +24,14 @@ void _shell_wm_unmaximize (ShellWM         *wm,
                            gint             y,
                            gint             width,
                            gint             height);
+void _shell_wm_fullscreen   (ShellWM         *wm,
+                             MetaWindowActor *actor,
+                             MetaRectangle   *old_rect,
+                             MetaRectangle   *target_rect);
+void _shell_wm_unfullscreen (ShellWM         *wm,
+                             MetaWindowActor *actor,
+                             MetaRectangle   *old_rect,
+                             MetaRectangle   *target_rect);
 void _shell_wm_map        (ShellWM         *wm,
                            MetaWindowActor *actor);
 void _shell_wm_destroy    (ShellWM         *wm,
diff --git a/src/shell-wm.c b/src/shell-wm.c
index 4b58df6..723d7be 100644
--- a/src/shell-wm.c
+++ b/src/shell-wm.c
@@ -22,6 +22,8 @@ enum
   UNMINIMIZE,
   MAXIMIZE,
   UNMAXIMIZE,
+  FULLSCREEN,
+  UNFULLSCREEN,
   MAP,
   DESTROY,
   SWITCH_WORKSPACE,
@@ -90,6 +92,22 @@ shell_wm_class_init (ShellWMClass *klass)
                   NULL, NULL, NULL,
                   G_TYPE_NONE, 5,
                   META_TYPE_WINDOW_ACTOR, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT);
+  shell_wm_signals[FULLSCREEN] =
+    g_signal_new ("fullscreen",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 3,
+                  META_TYPE_WINDOW_ACTOR, META_TYPE_RECTANGLE, META_TYPE_RECTANGLE);
+  shell_wm_signals[UNFULLSCREEN] =
+    g_signal_new ("unfullscreen",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL, NULL,
+                  G_TYPE_NONE, 3,
+                  META_TYPE_WINDOW_ACTOR, META_TYPE_RECTANGLE, META_TYPE_RECTANGLE);
   shell_wm_signals[MAP] =
     g_signal_new ("map",
                   G_TYPE_FROM_CLASS (klass),
@@ -249,6 +267,34 @@ shell_wm_completed_unmaximize (ShellWM         *wm,
 }
 
 /**
+ * shell_wm_completed_fullscreen:
+ * @wm: the ShellWM
+ * @actor: the MetaWindowActor actor
+ *
+ * The plugin must call this when it has completed a window fullscreen effect.
+ **/
+void
+shell_wm_completed_fullscreen (ShellWM         *wm,
+                               MetaWindowActor *actor)
+{
+  meta_plugin_fullscreen_completed (wm->plugin, actor);
+}
+
+/**
+ * shell_wm_completed_unfullscreen:
+ * @wm: the ShellWM
+ * @actor: the MetaWindowActor actor
+ *
+ * The plugin must call this when it has completed a window unfullscreen effect.
+ **/
+void
+shell_wm_completed_unfullscreen (ShellWM         *wm,
+                                 MetaWindowActor *actor)
+{
+  meta_plugin_unfullscreen_completed (wm->plugin, actor);
+}
+
+/**
  * shell_wm_completed_map:
  * @wm: the ShellWM
  * @actor: the MetaWindowActor actor
@@ -381,6 +427,24 @@ _shell_wm_unmaximize (ShellWM         *wm,
 }
 
 void
+_shell_wm_fullscreen (ShellWM         *wm,
+                      MetaWindowActor *actor,
+                      MetaRectangle   *old_rect,
+                      MetaRectangle   *target_rect)
+{
+  g_signal_emit (wm, shell_wm_signals[FULLSCREEN], 0, actor, old_rect, target_rect);
+}
+
+void
+_shell_wm_unfullscreen (ShellWM         *wm,
+                        MetaWindowActor *actor,
+                        MetaRectangle   *old_rect,
+                        MetaRectangle   *target_rect)
+{
+  g_signal_emit (wm, shell_wm_signals[UNFULLSCREEN], 0, actor, old_rect, target_rect);
+}
+
+void
 _shell_wm_map (ShellWM         *wm,
                MetaWindowActor *actor)
 {
diff --git a/src/shell-wm.h b/src/shell-wm.h
index 7cd8948..2aa8024 100644
--- a/src/shell-wm.h
+++ b/src/shell-wm.h
@@ -35,6 +35,10 @@ void     shell_wm_completed_maximize         (ShellWM         *wm,
                                               MetaWindowActor *actor);
 void     shell_wm_completed_unmaximize       (ShellWM         *wm,
                                               MetaWindowActor *actor);
+void     shell_wm_completed_fullscreen       (ShellWM         *wm,
+                                              MetaWindowActor *actor);
+void     shell_wm_completed_unfullscreen     (ShellWM         *wm,
+                                              MetaWindowActor *actor);
 void     shell_wm_completed_map              (ShellWM         *wm,
                                               MetaWindowActor *actor);
 void     shell_wm_completed_destroy          (ShellWM         *wm,


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