Skip to content
This repository was archived by the owner on Oct 31, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions daemon/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ workspace = true

[dependencies]
common = { workspace = true }

waybackend = { version = "0.7" }
log = { version = "0.4", default-features = false, features = [
log = { version = "0.4", default-features = false, features = [
"max_level_trace",
"release_max_level_info",
"std",
] }
rustix = { version = "1.1", default-features = false, features = ["event"] }
libc = "0.2"
keyframe = "1.1"
sd-notify = { version = "0.4" }

waybackend = { version = "0.7" }
rustix = { version = "1.1", default-features = false, features = ["event"] }
libc = { version = "0.2" }
keyframe = { version = "1.1" }
sd-notify = { version = "0.4" }

[build-dependencies]
waybackend-scanner = { version = "0.7", features = ["build-script"] }
185 changes: 103 additions & 82 deletions daemon/src/animations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ use log::error;
use waybackend::{Waybackend, objman::ObjectManager};

use std::{
cell::RefCell,
rc::Rc,
num::NonZeroU8,
time::{Duration, Instant},
};

use common::{
compression::Decompressor,
ipc::{self, Animation, BgImg, ImgReq, PixelFormat},
ipc::{self, BgImg, ImgReq, PixelFormat},
mmap::MmappedBytes,
};

Expand All @@ -18,71 +17,127 @@ use crate::{WaylandObject, wallpaper::Wallpaper};
mod transitions;
use transitions::Effect;

pub struct TransitionAnimator {
pub wallpapers: Vec<Rc<RefCell<Wallpaper>>>,
fps: Duration,
effect: Effect,
img: MmappedBytes,
animation: Option<Animation>,
pub struct Animator {
now: Instant,
over: bool,
animator: AnimatorKind,
}

impl TransitionAnimator {
enum AnimatorKind {
Transition(Transition),
Animation(Animation),
}

impl Animator {
pub fn new(
mut wallpapers: Vec<Rc<RefCell<Wallpaper>>>,
wallpapers: &mut [Wallpaper],
group: NonZeroU8,
transition: &ipc::Transition,
pixel_format: PixelFormat,
img_req: ImgReq,
animation: Option<Animation>,
animation: Option<ipc::Animation>,
) -> Option<Self> {
let ImgReq { img, path, dim, .. } = img_req;
if wallpapers.is_empty() {
return None;
}
for w in wallpapers.iter_mut() {
w.borrow_mut()
.set_img_info(BgImg::Img(path.str().to_string()));
}

let expect = wallpapers[0].borrow().get_dimensions();
let expect = wallpapers
.iter()
.find(|w| Some(group) == w.animation_group)
.unwrap()
.get_dimensions();

if dim != expect {
error!("image has wrong dimensions! Expect {expect:?}, actual {dim:?}");
return None;
}

for w in wallpapers
.iter_mut()
.filter(|w| Some(group) == w.animation_group)
{
w.set_img_info(BgImg::Img(path.str().to_string()));
}

let fps = Duration::from_nanos(1_000_000_000 / transition.fps as u64);
let effect = Effect::new(transition, pixel_format, dim);
Some(Self {
wallpapers,
effect,
fps,
img,
animation,
now: Instant::now(),
over: false,
animator: AnimatorKind::Transition(Transition {
effect,
fps,
img,
animation,
over: false,
}),
})
}

pub fn time_to_draw(&self) -> std::time::Duration {
self.fps.saturating_sub(self.now.elapsed())
match &self.animator {
AnimatorKind::Transition(transition) => transition.time_to_draw(&self.now),
AnimatorKind::Animation(animation) => animation.time_to_draw(&self.now),
}
}

pub fn updt_time(&mut self) {
self.now = Instant::now();
}

pub fn frame(
pub fn frame<'a, W: Iterator<Item = &'a mut Wallpaper>>(
&mut self,
backend: &mut Waybackend,
objman: &mut ObjectManager<WaylandObject>,
wallpapers: W,
pixel_format: PixelFormat,
) -> bool {
let Self { animator, .. } = self;
match animator {
AnimatorKind::Transition(transition) => {
if !transition.frame(backend, objman, wallpapers, pixel_format) {
return false;
}
// Note: it needs to have more than a single frame, otherwise there is no point in
// animating it
if let Some(animation) = transition.animation.take()
&& animation.animation.len() > 1
{
*animator = AnimatorKind::Animation(Animation {
animation,
decompressor: Decompressor::new(),
i: 0,
});
return false;
}
true
}
AnimatorKind::Animation(animation) => {
animation.frame(backend, objman, wallpapers, pixel_format);
false
}
}
}
}

struct Transition {
fps: Duration,
effect: Effect,
img: MmappedBytes,
animation: Option<ipc::Animation>,
over: bool,
}

impl Transition {
fn time_to_draw(&self, now: &Instant) -> std::time::Duration {
self.fps.saturating_sub(now.elapsed())
}

fn frame<'a, W: Iterator<Item = &'a mut Wallpaper>>(
&mut self,
backend: &mut Waybackend,
objman: &mut ObjectManager<WaylandObject>,
wallpapers: W,
pixel_format: PixelFormat,
) -> bool {
let Self {
wallpapers,
effect,
img,
over,
..
effect, img, over, ..
} = self;
if !*over {
*over = effect.execute(backend, objman, pixel_format, wallpapers, img.bytes());
Expand All @@ -91,58 +146,29 @@ impl TransitionAnimator {
true
}
}

pub fn into_image_animator(self) -> Option<ImageAnimator> {
let Self {
wallpapers,
animation,
..
} = self;

if let Some(animation) = animation {
// it needs to have more than a single frame, otherwise there is no point in animating
// it
if animation.animation.len() > 1 {
return Some(ImageAnimator {
now: Instant::now(),
wallpapers,
animation,
decompressor: Decompressor::new(),
i: 0,
});
}
}
None
}
}

pub struct ImageAnimator {
now: Instant,
pub wallpapers: Vec<Rc<RefCell<Wallpaper>>>,
animation: Animation,
struct Animation {
animation: ipc::Animation,
decompressor: Decompressor,
i: usize,
}

impl ImageAnimator {
pub fn time_to_draw(&self) -> std::time::Duration {
impl Animation {
fn time_to_draw(&self, now: &Instant) -> std::time::Duration {
self.animation.animation[self.i % self.animation.animation.len()]
.1
.saturating_sub(self.now.elapsed())
.saturating_sub(now.elapsed())
}

pub fn updt_time(&mut self) {
self.now = Instant::now();
}

pub fn frame(
fn frame<'a, W: Iterator<Item = &'a mut Wallpaper>>(
&mut self,
backend: &mut Waybackend,
objman: &mut ObjectManager<WaylandObject>,
wallpapers: W,
pixel_format: PixelFormat,
) {
let Self {
wallpapers,
animation,
decompressor,
i,
Expand All @@ -152,28 +178,23 @@ impl ImageAnimator {
let frame = &animation.animation[*i % animation.animation.len()].0;

if *i < animation.animation.len() {
wallpapers.retain(|w| {
let mut borrow = w.borrow_mut();
let result = borrow.canvas_change(backend, objman, pixel_format, |canvas| {
for w in wallpapers {
let result = w.canvas_change(backend, objman, pixel_format, |canvas| {
decompressor.decompress(frame, canvas, pixel_format)
});
match result {
Ok(()) => true,
Err(e) => {
error!("failed to unpack frame: {e}");
false
}
if let Err(e) = result {
error!("failed to unpack frame: {e}");
w.animation_group = None;
}
});
}
} else {
// if we already went through one loop, we can use the unsafe version, because
// everything was already validated
for w in wallpapers {
let mut borrow = w.borrow_mut();
// SAFETY: we have already validated every frame and removed the ones that have
// errors in the previous loops. The only ones left should be those that can be
// decompressed correctly
borrow.canvas_change(backend, objman, pixel_format, |canvas| unsafe {
w.canvas_change(backend, objman, pixel_format, |canvas| unsafe {
decompressor.decompress_unchecked(frame, canvas, pixel_format)
});
}
Expand Down
Loading
Loading