aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2025-03-01 09:45:57 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-03-10 07:59:14 +0300
commit88614c08fe0a7833cbb749a6ecf3e703eb373c6e (patch)
treef8dfa7b6b1802a355eb42fb7abc0f46a224928c1 /src
parent4f5c8e745bec6395105138c83468bccb4ab27ea9 (diff)
downloadniri-88614c08fe0a7833cbb749a6ecf3e703eb373c6e.tar.gz
niri-88614c08fe0a7833cbb749a6ecf3e703eb373c6e.tar.bz2
niri-88614c08fe0a7833cbb749a6ecf3e703eb373c6e.zip
Make interactively moved window semitransparent
Diffstat (limited to 'src')
-rw-r--r--src/layout/mod.rs65
-rw-r--r--src/layout/tile.rs20
-rw-r--r--src/layout/workspace.rs5
3 files changed, 87 insertions, 3 deletions
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 43c1631d..ac83a0cf 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -93,6 +93,9 @@ pub const RESIZE_ANIMATION_THRESHOLD: f64 = 10.;
/// Pointer needs to move this far to pull a window from the layout.
const INTERACTIVE_MOVE_START_THRESHOLD: f64 = 256. * 256.;
+/// Opacity of interactively moved tiles targeting the scrolling layout.
+const INTERACTIVE_MOVE_ALPHA: f64 = 0.75;
+
/// Size-relative units.
pub struct SizeFrac;
@@ -2334,6 +2337,34 @@ impl<W: LayoutElement> Layout<W> {
// Tile position must be rounded to physical pixels.
assert_abs_diff_eq!(tile_pos.x, rounded_pos.x, epsilon = 1e-5);
assert_abs_diff_eq!(tile_pos.y, rounded_pos.y, epsilon = 1e-5);
+
+ if let Some(alpha) = &move_.tile.alpha_animation {
+ if move_.is_floating {
+ assert_eq!(
+ alpha.anim.to(),
+ 1.,
+ "interactively moved floating tile can animate alpha only to 1"
+ );
+
+ assert!(
+ !alpha.hold_after_done,
+ "interactively moved floating tile \
+ cannot have held alpha animation"
+ );
+ } else {
+ assert_ne!(
+ alpha.anim.to(),
+ 1.,
+ "interactively moved scrolling tile must animate alpha to not 1"
+ );
+
+ assert!(
+ alpha.hold_after_done,
+ "interactively moved scrolling tile \
+ must have held alpha animation"
+ );
+ }
+ }
}
}
}
@@ -3005,6 +3036,21 @@ impl<W: LayoutElement> Layout<W> {
size.h = ensure_min_max_size_maybe_zero(size.h, min_size.h, max_size.h);
win.request_size_once(size, true);
+
+ // Animate the tile back to opaque.
+ move_.tile.animate_alpha(
+ INTERACTIVE_MOVE_ALPHA,
+ 1.,
+ self.options.animations.window_movement.0,
+ );
+ } else {
+ // Animate the tile back to semitransparent.
+ move_.tile.animate_alpha(
+ 1.,
+ INTERACTIVE_MOVE_ALPHA,
+ self.options.animations.window_movement.0,
+ );
+ move_.tile.hold_alpha_animation_after_done();
}
return;
@@ -3773,6 +3819,16 @@ impl<W: LayoutElement> Layout<W> {
is_floating = unfullscreen_to_floating;
}
+ // Animate to semitransparent.
+ if !is_floating {
+ tile.animate_alpha(
+ 1.,
+ INTERACTIVE_MOVE_ALPHA,
+ self.options.animations.window_movement.0,
+ );
+ tile.hold_alpha_animation_after_done();
+ }
+
let mut data = InteractiveMoveData {
tile,
output,
@@ -3869,7 +3925,7 @@ impl<W: LayoutElement> Layout<W> {
return;
}
- let Some(InteractiveMoveState::Moving(move_)) = self.interactive_move.take() else {
+ let Some(InteractiveMoveState::Moving(mut move_)) = self.interactive_move.take() else {
unreachable!()
};
@@ -3878,6 +3934,13 @@ impl<W: LayoutElement> Layout<W> {
for ws in self.workspaces_mut() {
ws.dnd_scroll_gesture_end();
}
+
+ // Also animate the tile back to opaque.
+ move_.tile.animate_alpha(
+ INTERACTIVE_MOVE_ALPHA,
+ 1.,
+ self.options.animations.window_movement.0,
+ );
}
match &mut self.monitor_set {
diff --git a/src/layout/tile.rs b/src/layout/tile.rs
index 71aa33a1..a93e4a6f 100644
--- a/src/layout/tile.rs
+++ b/src/layout/tile.rs
@@ -148,6 +148,12 @@ struct MoveAnimation {
#[derive(Debug)]
pub(super) struct AlphaAnimation {
pub(super) anim: Animation,
+ /// Whether the animation should persist after it's done.
+ ///
+ /// This is used by things like interactive move which need to animate alpha to
+ /// semitransparent, then hold it at semitransparent for a while, until the operation
+ /// completes.
+ pub(super) hold_after_done: bool,
offscreen: OffscreenBuffer,
}
@@ -319,7 +325,7 @@ impl<W: LayoutElement> Tile<W> {
}
if let Some(alpha) = &mut self.alpha_animation {
- if alpha.anim.is_done() {
+ if !alpha.hold_after_done && alpha.anim.is_done() {
self.alpha_animation = None;
}
}
@@ -334,7 +340,10 @@ impl<W: LayoutElement> Tile<W> {
|| self.resize_animation.is_some()
|| self.move_x_animation.is_some()
|| self.move_y_animation.is_some()
- || self.alpha_animation.is_some()
+ || self
+ .alpha_animation
+ .as_ref()
+ .is_some_and(|alpha| !alpha.anim.is_done())
}
pub fn update_render_elements(&mut self, is_active: bool, view_rect: Rectangle<f64, Logical>) {
@@ -491,6 +500,7 @@ impl<W: LayoutElement> Tile<W> {
self.alpha_animation = Some(AlphaAnimation {
anim: Animation::new(self.clock.clone(), current, to, 0., config),
+ hold_after_done: false,
offscreen,
});
}
@@ -505,6 +515,12 @@ impl<W: LayoutElement> Tile<W> {
}
}
+ pub fn hold_alpha_animation_after_done(&mut self) {
+ if let Some(alpha) = &mut self.alpha_animation {
+ alpha.hold_after_done = true;
+ }
+ }
+
pub fn window(&self) -> &W {
&self.window
}
diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs
index 0e4c1af5..1cb55233 100644
--- a/src/layout/workspace.rs
+++ b/src/layout/workspace.rs
@@ -1757,6 +1757,11 @@ impl<W: LayoutElement> Workspace<W> {
if visible {
assert_eq!(anim.to(), 1., "visible tiles can animate alpha only to 1");
}
+
+ assert!(
+ !alpha.hold_after_done,
+ "tiles in the layout cannot have held alpha animation"
+ );
}
}
}