summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCosimo Cecchi <cosimoc@gnome.org>2013-09-01 13:03:59 -0700
committerCosimo Cecchi <cosimoc@gnome.org>2015-10-12 15:40:30 -0400
commit672ca8850a670b16cdf2eb4df8192f075da4b6b4 (patch)
tree9948bd436aac7e1546324434568f9288358f96bb
parent674ae262c855ca113fc2058ceabe881c97cc2115 (diff)
downloadgnome-shell-wip/fullscreen.tar.gz
windowManager: add animations for fullscreen and unfullscreenwip/fullscreen
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
-rw-r--r--js/ui/windowManager.js116
-rw-r--r--src/shell-util.c55
-rw-r--r--src/shell-util.h4
3 files changed, 175 insertions, 0 deletions
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 7c96d0654..718f72f18 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -692,6 +692,7 @@ const WindowManager = new Lang.Class({
this._minimizeWindowDone(shellwm, actor);
this._mapWindowDone(shellwm, actor);
this._destroyWindowDone(shellwm, actor);
+ this._sizeChangeWindowDone(shellwm, actor);
}));
this._shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
@@ -1218,9 +1219,124 @@ const WindowManager = new Lang.Class({
},
_sizeChangeWindow : function(shellwm, actor, whichChange, oldFrameRect, oldBufferRect) {
+ let types = [Meta.WindowType.NORMAL];
+ if (!this._shouldAnimateActor(actor, types)) {
+ shellwm.completed_size_change(actor);
+ return;
+ }
+
+ if (whichChange == Meta.SizeChange.FULLSCREEN)
+ this._fullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
+ else if (whichChange == Meta.SizeChange.UNFULLSCREEN)
+ this._unfullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
+ else
+ shellwm.completed_size_change(actor);
+ },
+
+ _fullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
+ let targetRect = actor.meta_window.get_frame_rect();
+ let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect);
+ let actorClone = new St.Widget({ content: actorContent });
+ actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+ actorClone.set_position(oldFrameRect.x, oldFrameRect.y);
+ actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
+ Main.uiGroup.add_actor(actorClone);
+
+ actor.__fullscreenClone = actorClone;
+
+ let scaleX = targetRect.width / oldFrameRect.width;
+ let scaleY = targetRect.height / oldFrameRect.height;
+
+ Tweener.addTween(actorClone,
+ { x: targetRect.x,
+ y: targetRect.y,
+ scaleX: scaleX,
+ scaleY: scaleY,
+ opacity: 0,
+ time: WINDOW_ANIMATION_TIME,
+ transition: 'easeOutQuad',
+ onComplete: this._sizeChangeWindowDone,
+ 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_size_change(actor);
+ },
+
+ _unfullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
+ let targetRect = actor.meta_window.get_frame_rect();
+ let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect);
+ let actorClone = new St.Widget({ content: actorContent });
+ actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
+ actorClone.set_position(oldFrameRect.x, oldFrameRect.y);
+ actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
+ Main.uiGroup.add_actor(actorClone);
+
+ actor.__unfullscreenClone = actorClone;
+
+ let scaleX = targetRect.width / oldFrameRect.width;
+ let scaleY = targetRect.height / oldFrameRect.height;
+
+ Tweener.addTween(actorClone,
+ { x: targetRect.x,
+ y: targetRect.y,
+ scaleX: scaleX,
+ scaleY: scaleY,
+ opacity: 0,
+ time: WINDOW_ANIMATION_TIME,
+ transition: 'easeOutQuad',
+ onComplete: this._sizeChangeWindowDone,
+ 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_size_change(actor);
},
+ _sizeChangeWindowDone: function(shellwm, actor) {
+ Tweener.removeTweens(actor);
+
+ let actorClone = actor.__fullscreenClone;
+ if (actorClone) {
+ actorClone.destroy();
+ delete actor.__fullscreenClone;
+ }
+
+ 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/shell-util.c b/src/shell-util.c
index 33de0200f..5cd225822 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 4474a0d6d..80a1dc75a 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__ */