Skip to content

Commit ec69b49

Browse files
committed
Add desktop style transition animation
Display a fade animation when the desktop style changes from default to dark or vice versa. Notice that, because the theme changes at the GTK level, we need to wait an arbitrary time showing current theme window before we can perform the animation.
1 parent e2b86b2 commit ec69b49

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed

lib/Constants.vala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ namespace Gala {
3333
WORKSPACE_SWITCH = 400,
3434
// Duration of the nudge animation when trying to switch to at the end of the workspace list
3535
NUDGE = 360,
36+
// Duration of the default/dark style animation
37+
STYLE = 300,
3638
}
3739
}

src/StyleAnimationManager.vala

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2021 elementary, Inc (https://elementary.io)
3+
* 2021 José Expósito <[email protected]>
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
/**
20+
* Utility class to draw a Cairo.Surface in a Clutter.Actor.
21+
*/
22+
private class Gala.CairoImageActor : Clutter.Actor {
23+
public Cairo.Surface? image { get; construct; }
24+
25+
public CairoImageActor (Cairo.Surface image, int x, int y, int width, int height) {
26+
Object (image: image);
27+
this.x = x;
28+
this.y = y;
29+
this.width = width;
30+
this.height = height;
31+
32+
var canvas = new Clutter.Canvas ();
33+
canvas.set_size (width, height);
34+
canvas.draw.connect (draw_image);
35+
set_content (canvas);
36+
37+
canvas.invalidate ();
38+
}
39+
40+
private bool draw_image (Cairo.Context ctx) {
41+
Clutter.cairo_clear (ctx);
42+
43+
ctx.set_source_surface (image, 0.0, 0.0);
44+
ctx.rectangle (0.0, 0.0, width, height);
45+
ctx.paint ();
46+
47+
return true;
48+
}
49+
}
50+
51+
/**
52+
* Watch for style transitions (default to dark or or vice versa) and performs
53+
* an animation.
54+
*/
55+
public class Gala.StyleAnimationManager : Object {
56+
public WindowManager wm { get; construct; }
57+
58+
/**
59+
* Time to wait displaying the CairoImageActor before starting
60+
* the fade animation.
61+
*/
62+
private const int WAIT_BEFORE_ANIMATE = 700;
63+
64+
public StyleAnimationManager (WindowManager wm) {
65+
Object (wm: wm);
66+
}
67+
68+
public void watch_style_transitions () {
69+
var granite_settings = Granite.Settings.get_default ();
70+
granite_settings.notify["prefers-color-scheme"].connect (() => {
71+
if (wm.enable_animations) {
72+
animate ();
73+
}
74+
});
75+
}
76+
77+
private void animate () {
78+
unowned var workspace_manager = wm.get_display ().get_workspace_manager ();
79+
unowned var workspace = workspace_manager.get_active_workspace ();
80+
81+
foreach (unowned Meta.Window window in workspace.list_windows ()) {
82+
unowned var window_actor = window.get_compositor_private () as Meta.WindowActor;
83+
var rect = window.get_frame_rect ();
84+
int x = rect.x - (int) window_actor.x;
85+
int y = rect.y - (int) window_actor.y;
86+
int width = rect.width;
87+
int height = rect.height;
88+
89+
var image = window_actor.get_image ({ x, y, width, height });
90+
var image_actor = new CairoImageActor (image, x, y, width, height);
91+
window_actor.add_child (image_actor);
92+
93+
Timeout.add (WAIT_BEFORE_ANIMATE, () => {
94+
image_actor.set_easing_duration (AnimationDuration.STYLE);
95+
image_actor.set_easing_mode (Clutter.AnimationMode.LINEAR);
96+
image_actor.opacity = 0;
97+
98+
ulong signal_id = 0U;
99+
signal_id = image_actor.transitions_completed.connect (() => {
100+
image_actor.disconnect (signal_id);
101+
window_actor.remove_child (image_actor);
102+
image_actor.destroy ();
103+
});
104+
105+
return Source.REMOVE;
106+
});
107+
}
108+
}
109+
}

src/WindowManager.vala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ namespace Gala {
7575
public ScreenSaverManager? screensaver { get; private set; }
7676

7777
HotCornerManager? hot_corner_manager = null;
78+
StyleAnimationManager? style_animation_manager = null;
7879

7980
/**
8081
* Allow to zoom in/out the entire desktop.
@@ -290,6 +291,9 @@ namespace Gala {
290291
hot_corner_manager.on_configured.connect (update_input_area);
291292
hot_corner_manager.configure ();
292293

294+
style_animation_manager = new StyleAnimationManager (this);
295+
style_animation_manager.watch_style_transitions ();
296+
293297
zoom = new Zoom (this);
294298

295299
accent_color_manager = new AccentColorManager ();

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ gala_bin_sources = files(
1313
'ScreenshotManager.vala',
1414
'SessionManager.vala',
1515
'ShadowEffect.vala',
16+
'StyleAnimationManager.vala',
1617
'WindowListener.vala',
1718
'WindowManager.vala',
1819
'WorkspaceManager.vala',

0 commit comments

Comments
 (0)