Compare commits

...

7 Commits

Author SHA1 Message Date
Giovanni Campagna
3e79d293f7 LayoutManager: implement new design for the startup animation
The design calls for two different startup animations, in the GDM
and in the normal session case.
In both cases, we implement fading from the previous situation
by acquiring the root background pixmap and turning it into a TFP
texture, which is then animated and blended by Clutter as normal.

https://bugzilla.gnome.org/show_bug.cgi?id=682429
2013-02-05 00:11:19 +01:00
Giovanni Campagna
d457073c10 Util: add an accessor for the root background pixmap
The background of the root window is accessible as the _XROOTPMAP_ID
property on the root window. Given that the root window is always
fully covered by the Composite Overlay Window, we use that as temporary
storage while the COW is not mapped, that is, before the GDM greeter
is started and between killing the greeter and starting GDM from the
session.

https://bugzilla.gnome.org/show_bug.cgi?id=682429
2013-02-05 00:11:19 +01:00
Giovanni Campagna
8b2864ee70 Main: move the stage hierarchy initialization to LayoutManager
It is cleaner to concentrate all layout and chrome management
in one place, instead of having it scattered around the codebase.

https://bugzilla.gnome.org/show_bug.cgi?id=682429
2013-02-05 00:11:19 +01:00
Giovanni Campagna
af1c799246 ScreenShield: remove blur effect from the background
It's badly implemented, slow and actually not needed, now that we
have a different image.
Let's keep desaturation instead.

https://bugzilla.gnome.org/show_bug.cgi?id=688210
2013-02-05 00:11:18 +01:00
Giovanni Campagna
f6aa0ee532 ScreenShield: use different settings for the lock screen background
The design calls for the ability to set a different background in the
lock screen, to differentiate it from the normal desktop.

https://bugzilla.gnome.org/show_bug.cgi?id=688210
2013-02-05 00:11:18 +01:00
Giovanni Campagna
b0e22a795e Adapt for MetaBackgroundActor API changes
MetaBackgroundActor can now be constructed as a standard GObject, and
accepts a GnomeBG settings object, which we retrieve from the default
one to share textures.

https://bugzilla.gnome.org/show_bug.cgi?id=688210
2013-02-05 00:11:18 +01:00
Giovanni Campagna
f91671498b LayoutManager: Remove broken startup animation
It doesn't make sense to animate blindly a MetaBackgroundActor, given that
it shows the content of _XROOTPMAP_ID, so if gnome-settings-daemon is fast
we're animating the configured background, not the plymouth screen. And anyway
it would be animated on top of the standard MetaBackgroundActor...
It makes even less sense now that mutter renders the background on its own
(and blocks the first paint cycle until the background image is ready)
We need to do something better here, but for now, remove this.

https://bugzilla.gnome.org/show_bug.cgi?id=688210
2013-02-05 00:11:18 +01:00
9 changed files with 228 additions and 111 deletions

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const ClutterX11 = imports.gi.ClutterX11;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
@ -15,9 +16,9 @@ const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
const STARTUP_ANIMATION_TIME = 0.2;
const STARTUP_ANIMATION_TIME = 1;
const KEYBOARD_ANIMATION_TIME = 0.15;
const PLYMOUTH_TRANSITION_TIME = 1;
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
const MonitorConstraint = new Lang.Class({
Name: 'MonitorConstraint',
@ -111,7 +112,6 @@ const LayoutManager = new Lang.Class({
this.primaryIndex = -1;
this._keyboardIndex = -1;
this._hotCorners = [];
this._background = null;
this._leftPanelBarrier = 0;
this._rightPanelBarrier = 0;
@ -120,6 +120,42 @@ const LayoutManager = new Lang.Class({
this._trackedActors = [];
// Normally, the stage is always covered so Clutter doesn't need to clear
// it; however it becomes visible during the startup animation
// See the comment below for a longer explanation
global.stage.color = DEFAULT_BACKGROUND_COLOR;
// Set up stage hierarchy to group all UI actors under one container.
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
this.uiGroup.connect('allocate',
function (actor, box, flags) {
let children = actor.get_children();
for (let i = 0; i < children.length; i++)
children[i].allocate_preferred_size(flags);
});
this.uiGroup.connect('get-preferred-width',
function(actor, forHeight, alloc) {
let width = global.stage.width;
[alloc.min_size, alloc.natural_size] = [width, width];
});
this.uiGroup.connect('get-preferred-height',
function(actor, forWidth, alloc) {
let height = global.stage.height;
[alloc.min_size, alloc.natural_size] = [height, height];
});
global.window_group.reparent(this.uiGroup);
// Now, you might wonder why we went through all the hoops to implement
// the GDM greeter inside an X11 compositor, to do this at the end...
// However, hiding this is necessary to avoid showing the background during
// the initial animation, before Gdm.LoginDialog covers everything
if (Main.sessionMode.isGreeter)
global.window_group.hide();
global.overlay_group.reparent(this.uiGroup);
global.stage.add_child(this.uiGroup);
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
visible: false,
clip_to_allocation: true,
@ -161,7 +197,8 @@ const LayoutManager = new Lang.Class({
Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._startupAnimation();
this._prepareStartupAnimation();
},
_overviewShowing: function() {
@ -254,7 +291,7 @@ const LayoutManager = new Lang.Class({
if (!haveTopLeftCorner)
continue;
let corner = new HotCorner();
let corner = new HotCorner(this);
this._hotCorners.push(corner);
corner.actor.set_position(cornerX, cornerY);
this.addChrome(corner.actor);
@ -376,51 +413,106 @@ const LayoutManager = new Lang.Class({
return this._keyboardIndex;
},
_startupAnimation: function() {
this.panelBox.translation_y = -this.panelBox.height;
_acquireRootBackground: function() {
let rootpmap = Shell.util_get_root_background();
let texture = ClutterX11.TexturePixmap.new_with_pixmap(rootpmap);
// The texture size might not match the screen size, for example
// if the session has a different XRandR configuration than the greeter
texture.x = 0;
texture.y = 0;
texture.width = global.screen_width;
texture.height = global.screen_height;
texture.set_automatic(true);
let plymouthTransitionRunning = false;
// If we're the greeter, put up the xrootpmap actor
// and fade it out to have a nice transition from plymouth
// to the greeter. Otherwise, we'll just animate the panel,
// as usual.
if (Main.sessionMode.isGreeter) {
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
if (this._background != null) {
Main.uiGroup.add_actor(this._background);
Tweener.addTween(this._background,
{ opacity: 0,
time: PLYMOUTH_TRANSITION_TIME,
transition: 'linear',
onComplete: this._fadeBackgroundComplete,
onCompleteScope: this });
plymouthTransitionRunning = true;
}
}
if (!plymouthTransitionRunning)
this._fadeBackgroundComplete();
this._rootTexture = texture;
},
_fadeBackgroundComplete: function() {
// Startup Animations
//
// We have two different animations, depending on whether we're a greeter
// or a normal session.
//
// In the greeter, we want to animate the panel from the top, and smoothly
// fade the login dialog on top of whatever plymouth left on screen, which we
// grab as a X11 texture_from_pixmap.
// Here we just have the code to animate the panel, the login dialog animation
// is handled by modalDialog.js
//
// In a normal session, we want to take the root background, which now holds
// the final frame of the GDM greeter, and slide it from the bottom, while
// at the same time scaling the UI contents of the new shell on top of the
// stage background.
//
// Usually, we don't want to paint the stage background color because the
// MetaBackgroundActor inside global.window_group covers the entirety of the
// screen. So, we set no_clear_hint at the end of the animation.
_prepareStartupAnimation: function() {
// Set ourselves to FULLSCREEN input mode while the animation is running
// so events don't get delivered to X11 windows (which are distorted by the animation)
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
this._acquireRootBackground();
if (Main.sessionMode.isGreeter) {
global.stage.insert_child_below(this._rootTexture, null);
this._panelBox.translation_y = -this._panelBox.height;
} else {
global.stage.insert_child_above(this._rootTexture, null);
this.uiGroup.set_pivot_point(0.5, 0.5);
this.uiGroup.scale_x = this.uiGroup.scale_y = 0;
}
},
startupAnimation: function() {
if (Main.sessionMode.isGreeter)
this._startupAnimationGreeter();
else
this._startupAnimationSession();
},
_startupAnimationGreeter: function() {
// Don't animate the strut
this._freezeUpdateRegions();
if (this._background != null) {
this._background.destroy();
this._background = null;
}
Tweener.addTween(this.panelBox,
Tweener.addTween(this._panelBox,
{ translation_y: 0,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
onCompleteScope: this
});
onCompleteScope: this });
},
_startupAnimationSession: function() {
// Don't animate the strut
this._freezeUpdateRegions();
Tweener.addTween(this._rootTexture,
{ translation_y: -global.screen_height,
time: STARTUP_ANIMATION_TIME,
transition: 'linear' });
Tweener.addTween(this.uiGroup,
{ scale_x: 1,
scale_y: 1,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
onCompleteScope: this });
},
_startupAnimationComplete: function() {
// At this point, the UI group is covering everything, so
// we no longer need to clear the stage
global.stage.no_clear_hint = true;
global.stage_input_mode = Shell.StageInputMode.NORMAL;
this._rootTexture.destroy();
this._rootTexture = null;
this.emit('panel-box-changed');
this._thawUpdateRegions();
},
@ -506,7 +598,7 @@ const LayoutManager = new Lang.Class({
// monitor (it will be hidden whenever a fullscreen window is visible,
// and shown otherwise)
addChrome: function(actor, params) {
Main.uiGroup.add_actor(actor);
this.uiGroup.add_actor(actor);
this._trackActor(actor, params);
},
@ -557,7 +649,7 @@ const LayoutManager = new Lang.Class({
//
// Removes @actor from the chrome
removeChrome: function(actor) {
Main.uiGroup.remove_actor(actor);
this.uiGroup.remove_actor(actor);
this._untrackActor(actor);
},
@ -576,7 +668,7 @@ const LayoutManager = new Lang.Class({
let actorData = Params.parse(params, defaultParams);
actorData.actor = actor;
actorData.isToplevel = actor.get_parent() == Main.uiGroup;
actorData.isToplevel = actor.get_parent() == this.uiGroup;
actorData.visibleId = actor.connect('notify::visible',
Lang.bind(this, this._queueUpdateRegions));
actorData.allocationId = actor.connect('notify::allocation',
@ -612,7 +704,7 @@ const LayoutManager = new Lang.Class({
} else {
let i = this._findActor(actor);
let actorData = this._trackedActors[i];
actorData.isToplevel = (newParent == Main.uiGroup);
actorData.isToplevel = (newParent == this.uiGroup);
}
},
@ -812,7 +904,7 @@ const LayoutManager = new Lang.Class({
if (actorData.affectsInputRegion &&
actorData.actor.get_paint_visibility() &&
!Main.uiGroup.get_skip_paint(actorData.actor))
!this.uiGroup.get_skip_paint(actorData.actor))
rects.push(rect);
if (!actorData.affectsStruts)

View File

@ -38,7 +38,6 @@ const XdndHandler = imports.ui.xdndHandler;
const Util = imports.misc.util;
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
let componentManager = null;
let panel = null;
@ -63,6 +62,7 @@ let magnifier = null;
let xdndHandler = null;
let keyboard = null;
let layoutManager = null;
let background = null;
let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
@ -111,38 +111,17 @@ function start() {
tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
// The stage is always covered so Clutter doesn't need to clear it; however
// the color is used as the default contents for the Mutter root background
// actor so set it anyways.
global.stage.color = DEFAULT_BACKGROUND_COLOR;
global.stage.no_clear_hint = true;
// Setup the stage hierarchy early
layoutManager = new Layout.LayoutManager();
// For backward compatibility
uiGroup = layoutManager.uiGroup;
let backgroundActor = global.window_group.background;
background = backgroundActor.settings;
_defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
loadTheme();
// Set up stage hierarchy to group all UI actors under one container.
uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
uiGroup.connect('allocate',
function (actor, box, flags) {
let children = uiGroup.get_children();
for (let i = 0; i < children.length; i++)
children[i].allocate_preferred_size(flags);
});
uiGroup.connect('get-preferred-width',
function(actor, forHeight, alloc) {
let width = global.stage.width;
[alloc.min_size, alloc.natural_size] = [width, width];
});
uiGroup.connect('get-preferred-height',
function(actor, forWidth, alloc) {
let height = global.stage.height;
[alloc.min_size, alloc.natural_size] = [height, height];
});
global.window_group.reparent(uiGroup);
global.overlay_group.reparent(uiGroup);
global.stage.add_actor(uiGroup);
layoutManager = new Layout.LayoutManager();
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
overview = new Overview.Overview();
@ -196,6 +175,14 @@ function start() {
ExtensionDownloader.init();
ExtensionSystem.init();
// Run the startup animation as soon as the mainloop is idle enough
// This is necessary to have it smooth and without interruptions from
// completed IO tasks
GLib.idle_add(GLib.PRIORITY_LOW, function() {
layoutManager.startupAnimation();
return false;
});
}
let _workspaces = [];

View File

@ -122,7 +122,8 @@ const Overview = new Lang.Class({
// one. Instances of this class share a single CoglTexture behind the
// scenes which allows us to show the background with different
// rendering options without duplicating the texture data.
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
this._background = new Meta.BackgroundActor({ screen: global.screen,
settings: Main.background });
this._background.add_glsl_snippet(Meta.SnippetHook.FRAGMENT,
GLSL_DIM_EFFECT_DECLARATIONS,
GLSL_DIM_EFFECT_CODE,

View File

@ -644,7 +644,7 @@ const ActivitiesButton = new Lang.Class({
this.actor.label_actor = this._label;
this.hotCorner = new Layout.HotCorner();
this.hotCorner = new Layout.HotCorner(Main.layoutManager);
container.add_actor(this.hotCorner.actor);
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));

View File

@ -52,36 +52,16 @@ const SUMMARY_ICON_SIZE = 48;
const STANDARD_FADE_TIME = 10;
const SHORT_FADE_TIME = 0.3;
function sample(offx, offy) {
return 'texel += texture2D (sampler, tex_coord.st + pixel_step * ' +
'vec2 (' + offx + ',' + offy + '));\n'
}
const GLSL_BLUR_EFFECT_DECLARATIONS = ' \
uniform vec2 pixel_step;\n \
const GLSL_EFFECT_DECLARATIONS = ' \
uniform float desaturation; \n \
vec4 apply_blur(in sampler2D sampler, in vec2 tex_coord) {\n \
vec4 texel;\n \
texel = texture2D (sampler, tex_coord.st);\n'
+ sample(-1.0, -1.0)
+ sample( 0.0, -1.0)
+ sample(+1.0, -1.0)
+ sample(-1.0, 0.0)
+ sample(+1.0, 0.0)
+ sample(-1.0, +1.0)
+ sample( 0.0, +1.0)
+ sample(+1.0, +1.0) + ' \
texel /= 9.0;\n \
return texel;\n \
}\n \
vec3 desaturate (const vec3 color)\n \
{\n \
const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n \
vec3 gray = vec3 (dot (gray_conv, color));\n \
return vec3 (mix (color.rgb, gray, desaturation));\n \
}';
const GLSL_BLUR_EFFECT_CODE = ' \
cogl_texel = apply_blur(cogl_sampler, cogl_tex_coord.st);\n \
cogl_texel.rgb = desaturate(cogl_texel.rgb);\n';
const GLSL_EFFECT_CODE = ' \
cogl_color_out.rgb = desaturate(cogl_color_out.rgb);\n';
const Clock = new Lang.Class({
@ -467,16 +447,16 @@ const ScreenShield = new Lang.Class({
name: 'lockScreenContents' });
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
let backgroundActor = Meta.BackgroundActor.new_for_screen(global.screen);
backgroundActor.add_glsl_snippet(Meta.SnippetHook.TEXTURE_LOOKUP,
GLSL_BLUR_EFFECT_DECLARATIONS,
GLSL_BLUR_EFFECT_CODE,
true);
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
let backgroundActor = new Meta.BackgroundActor({ screen: global.screen,
settings: this._settings });
backgroundActor.add_glsl_snippet(Meta.SnippetHook.FRAGMENT,
GLSL_EFFECT_DECLARATIONS,
GLSL_EFFECT_CODE,
false);
backgroundActor.set_uniform_float('desaturation',
1, 1, [0.6]);
backgroundActor.connect('notify::size', function(actor) {
actor.set_uniform_float('pixel_step', 2, 1, [1/actor.width, 1/actor.height]);
});
this._background = new St.Bin({ style_class: 'screen-shield-background',
child: backgroundActor });
@ -531,8 +511,6 @@ const ScreenShield = new Lang.Class({
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); }));
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
this._isModal = false;
this._hasLockScreen = false;
this._isGreeter = false;

View File

@ -170,7 +170,8 @@ const WorkspaceThumbnail = new Lang.Class({
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
this._background = new Meta.BackgroundActor({ screen: global.screen,
settings: Main.background });
this._contents.add_actor(this._background);
let monitor = Main.layoutManager.primaryMonitor;

View File

@ -292,7 +292,7 @@ libgnome_shell_la_LIBADD = \
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
Shell-0.1.gir: libgnome-shell.la St-1.0.gir
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 TelepathyLogger-0.2 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 TelepathyLogger-0.2 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0 xlib-2.0
Shell_0_1_gir_CFLAGS = $(libgnome_shell_la_CPPFLAGS) -I $(srcdir)
Shell_0_1_gir_LIBS = libgnome-shell.la
Shell_0_1_gir_FILES = $(libgnome_shell_la_gir_sources)

View File

@ -9,6 +9,8 @@
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdkx.h>
#include <X11/Xatom.h>
#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
#include <langinfo.h>
@ -430,3 +432,56 @@ shell_util_create_pixbuf_from_data (const guchar *data,
bits_per_sample, width, height, rowstride,
(GdkPixbufDestroyNotify) g_free, NULL);
}
Pixmap
shell_util_get_root_background (void)
{
Display *display;
Pixmap pixmap;
Window rootwin;
Atom xrootpmap;
Atom actual_type;
int actual_format;
unsigned long n_items;
unsigned long bytes_after;
unsigned char *buffer;
display = gdk_x11_get_default_xdisplay ();
xrootpmap = gdk_x11_atom_to_xatom (gdk_atom_intern_static_string ("_XROOTPMAP_ID"));
rootwin = gdk_x11_get_default_root_xwindow ();
gdk_error_trap_push ();
actual_type = None;
buffer = NULL;
if (XGetWindowProperty (display, rootwin, xrootpmap,
0, G_MAXLONG,
False, XA_PIXMAP, &actual_type, &actual_format,
&n_items,
&bytes_after,
&buffer) != Success ||
actual_type == None)
{
if (buffer)
XFree (buffer);
gdk_error_trap_pop_ignored ();
return FALSE;
}
if (gdk_error_trap_pop () != Success ||
n_items == 0 ||
actual_type != XA_PIXMAP ||
actual_format != 32)
{
if (buffer)
XFree (buffer);
return FALSE;
}
pixmap = *((Pixmap*) buffer);
XFree (buffer);
return pixmap;
}

View File

@ -7,6 +7,7 @@
#include <clutter/clutter.h>
#include <libsoup/soup.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdkx.h>
G_BEGIN_DECLS
@ -46,6 +47,8 @@ GdkPixbuf *shell_util_create_pixbuf_from_data (const guchar *data,
int height,
int rowstride);
Pixmap shell_util_get_root_background (void);
G_END_DECLS
#endif /* __SHELL_UTIL_H__ */