mirror of
https://github.com/LinuxBeginnings/swww.git
synced 2026-01-12 07:21:01 -03:00
remote most static muts from globals
The only remaining `static mut` is the wayland file descriptor, because it would be incredibly incovenient to change it. The wayland `static mut` is also the least concerning one, since it always creates immutable references to it.
This commit is contained in:
@@ -8,11 +8,11 @@ use std::{
|
||||
|
||||
use common::{
|
||||
compression::Decompressor,
|
||||
ipc::{self, Animation, BgImg, ImgReq},
|
||||
ipc::{self, Animation, BgImg, ImgReq, PixelFormat},
|
||||
mmap::MmappedBytes,
|
||||
};
|
||||
|
||||
use crate::{wallpaper::Wallpaper, wayland::globals};
|
||||
use crate::{wallpaper::Wallpaper, wayland::ObjectManager};
|
||||
|
||||
mod transitions;
|
||||
use transitions::Effect;
|
||||
@@ -31,6 +31,7 @@ impl TransitionAnimator {
|
||||
pub fn new(
|
||||
mut wallpapers: Vec<Rc<RefCell<Wallpaper>>>,
|
||||
transition: &ipc::Transition,
|
||||
pixel_format: PixelFormat,
|
||||
img_req: ImgReq,
|
||||
animation: Option<Animation>,
|
||||
) -> Option<Self> {
|
||||
@@ -49,7 +50,7 @@ impl TransitionAnimator {
|
||||
return None;
|
||||
}
|
||||
let fps = Duration::from_nanos(1_000_000_000 / transition.fps as u64);
|
||||
let effect = Effect::new(transition, dim);
|
||||
let effect = Effect::new(transition, pixel_format, dim);
|
||||
Some(Self {
|
||||
wallpapers,
|
||||
effect,
|
||||
@@ -69,7 +70,7 @@ impl TransitionAnimator {
|
||||
self.now = Instant::now();
|
||||
}
|
||||
|
||||
pub fn frame(&mut self) -> bool {
|
||||
pub fn frame(&mut self, objman: &mut ObjectManager, pixel_format: PixelFormat) -> bool {
|
||||
let Self {
|
||||
wallpapers,
|
||||
effect,
|
||||
@@ -78,7 +79,7 @@ impl TransitionAnimator {
|
||||
..
|
||||
} = self;
|
||||
if !*over {
|
||||
*over = effect.execute(wallpapers, img.bytes());
|
||||
*over = effect.execute(objman, pixel_format, wallpapers, img.bytes());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
@@ -121,7 +122,7 @@ impl ImageAnimator {
|
||||
self.now = Instant::now();
|
||||
}
|
||||
|
||||
pub fn frame(&mut self) {
|
||||
pub fn frame(&mut self, objman: &mut ObjectManager, pixel_format: PixelFormat) {
|
||||
let Self {
|
||||
wallpapers,
|
||||
animation,
|
||||
@@ -134,9 +135,11 @@ impl ImageAnimator {
|
||||
|
||||
let mut j = 0;
|
||||
while j < wallpapers.len() {
|
||||
let result = wallpapers[j].borrow_mut().canvas_change(|canvas| {
|
||||
decompressor.decompress(frame, canvas, globals::pixel_format())
|
||||
});
|
||||
let result = wallpapers[j]
|
||||
.borrow_mut()
|
||||
.canvas_change(objman, pixel_format, |canvas| {
|
||||
decompressor.decompress(frame, canvas, pixel_format)
|
||||
});
|
||||
|
||||
if let Err(e) = result {
|
||||
error!("failed to unpack frame: {e}");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{cell::RefCell, rc::Rc, time::Instant};
|
||||
|
||||
use crate::{wallpaper::Wallpaper, wayland::globals};
|
||||
use common::ipc::{Transition, TransitionType};
|
||||
use crate::{wallpaper::Wallpaper, wayland::ObjectManager};
|
||||
use common::ipc::{PixelFormat, Transition, TransitionType};
|
||||
|
||||
use keyframe::{
|
||||
functions::BezierCurve, keyframes, mint::Vector2, num_traits::Pow, AnimationSequence,
|
||||
@@ -41,10 +41,17 @@ impl None {
|
||||
fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
fn run(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
|
||||
fn run(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
wallpapers.iter().for_each(|w| {
|
||||
w.borrow_mut()
|
||||
.canvas_change(|canvas| canvas.copy_from_slice(img))
|
||||
.canvas_change(objman, pixel_format, |canvas| canvas.copy_from_slice(img))
|
||||
});
|
||||
true
|
||||
}
|
||||
@@ -62,27 +69,33 @@ pub enum Effect {
|
||||
}
|
||||
|
||||
impl Effect {
|
||||
pub fn new(transition: &Transition, dimensions: (u32, u32)) -> Self {
|
||||
pub fn new(transition: &Transition, pixel_format: PixelFormat, dimensions: (u32, u32)) -> Self {
|
||||
match transition.transition_type {
|
||||
TransitionType::Simple => Self::Simple(Simple::new(transition.step.get())),
|
||||
TransitionType::Fade => Self::Fade(Fade::new(transition)),
|
||||
TransitionType::Outer => Self::Outer(Outer::new(transition, dimensions)),
|
||||
TransitionType::Wipe => Self::Wipe(Wipe::new(transition, dimensions)),
|
||||
TransitionType::Grow => Self::Grow(Grow::new(transition, dimensions)),
|
||||
TransitionType::Wave => Self::Wave(Wave::new(transition, dimensions)),
|
||||
TransitionType::Outer => Self::Outer(Outer::new(transition, pixel_format, dimensions)),
|
||||
TransitionType::Wipe => Self::Wipe(Wipe::new(transition, pixel_format, dimensions)),
|
||||
TransitionType::Grow => Self::Grow(Grow::new(transition, pixel_format, dimensions)),
|
||||
TransitionType::Wave => Self::Wave(Wave::new(transition, pixel_format, dimensions)),
|
||||
TransitionType::None => Self::None(None::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
pub fn execute(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
let done = match self {
|
||||
Effect::None(effect) => effect.run(wallpapers, img),
|
||||
Effect::Simple(effect) => effect.run(wallpapers, img),
|
||||
Effect::Fade(effect) => effect.run(wallpapers, img),
|
||||
Effect::Wave(effect) => effect.run(wallpapers, img),
|
||||
Effect::Wipe(effect) => effect.run(wallpapers, img),
|
||||
Effect::Grow(effect) => effect.run(wallpapers, img),
|
||||
Effect::Outer(effect) => effect.run(wallpapers, img),
|
||||
Effect::None(effect) => effect.run(objman, pixel_format, wallpapers, img),
|
||||
Effect::Simple(effect) => effect.run(objman, pixel_format, wallpapers, img),
|
||||
Effect::Fade(effect) => effect.run(objman, pixel_format, wallpapers, img),
|
||||
Effect::Wave(effect) => effect.run(objman, pixel_format, wallpapers, img),
|
||||
Effect::Wipe(effect) => effect.run(objman, pixel_format, wallpapers, img),
|
||||
Effect::Grow(effect) => effect.run(objman, pixel_format, wallpapers, img),
|
||||
Effect::Outer(effect) => effect.run(objman, pixel_format, wallpapers, img),
|
||||
};
|
||||
// we only finish for real if we are doing a None or a Simple transition
|
||||
if done {
|
||||
@@ -108,16 +121,24 @@ impl Simple {
|
||||
fn new(step: u8) -> Self {
|
||||
Self { step }
|
||||
}
|
||||
fn run(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
fn run(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
let step = self.step;
|
||||
let mut done = true;
|
||||
for wallpaper in wallpapers.iter() {
|
||||
wallpaper.borrow_mut().canvas_change(|canvas| {
|
||||
for (old, new) in canvas.iter_mut().zip(img) {
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
done = done && canvas == img;
|
||||
});
|
||||
wallpaper
|
||||
.borrow_mut()
|
||||
.canvas_change(objman, pixel_format, |canvas| {
|
||||
for (old, new) in canvas.iter_mut().zip(img) {
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
done = done && canvas == img;
|
||||
});
|
||||
}
|
||||
done
|
||||
}
|
||||
@@ -135,15 +156,23 @@ impl Fade {
|
||||
let step = 0;
|
||||
Self { start, seq, step }
|
||||
}
|
||||
fn run(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
fn run(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
for wallpaper in wallpapers.iter() {
|
||||
wallpaper.borrow_mut().canvas_change(|canvas| {
|
||||
for (old, new) in canvas.iter_mut().zip(img) {
|
||||
let x = *old as u16 * (256 - self.step);
|
||||
let y = *new as u16 * self.step;
|
||||
*old = ((x + y) >> 8) as u8;
|
||||
}
|
||||
});
|
||||
wallpaper
|
||||
.borrow_mut()
|
||||
.canvas_change(objman, pixel_format, |canvas| {
|
||||
for (old, new) in canvas.iter_mut().zip(img) {
|
||||
let x = *old as u16 * (256 - self.step);
|
||||
let y = *new as u16 * self.step;
|
||||
*old = ((x + y) >> 8) as u8;
|
||||
}
|
||||
});
|
||||
}
|
||||
self.step = (256.0 * self.seq.now() as f64).trunc() as u16;
|
||||
self.seq.advance_to(self.start.elapsed().as_secs_f64());
|
||||
@@ -169,7 +198,7 @@ struct Wave {
|
||||
}
|
||||
|
||||
impl Wave {
|
||||
fn new(transition: &Transition, dimensions: (u32, u32)) -> Self {
|
||||
fn new(transition: &Transition, pixel_format: PixelFormat, dimensions: (u32, u32)) -> Self {
|
||||
let width = dimensions.0;
|
||||
let height = dimensions.1;
|
||||
let center = (width / 2, height / 2);
|
||||
@@ -190,7 +219,7 @@ impl Wave {
|
||||
let (seq, start) = bezier_seq(transition, offset as f32, max_offset as f32);
|
||||
|
||||
let step = transition.step.get();
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
let stride = width * channels;
|
||||
Self {
|
||||
start,
|
||||
@@ -209,7 +238,13 @@ impl Wave {
|
||||
step,
|
||||
}
|
||||
}
|
||||
fn run(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
fn run(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
let Self {
|
||||
width,
|
||||
height,
|
||||
@@ -239,54 +274,57 @@ impl Wave {
|
||||
lhs <= rhs
|
||||
};
|
||||
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
let offset = self.seq.now() as f64;
|
||||
self.seq.advance_to(self.start.elapsed().as_secs_f64());
|
||||
|
||||
for wallpaper in wallpapers.iter() {
|
||||
wallpaper.borrow_mut().canvas_change(|canvas| {
|
||||
// divide in 3 sections: the one we know will not be drawn to, the one we know
|
||||
// WILL be drawn to, and the one we need to do a more expensive check on.
|
||||
// We do this by creating 2 lines: the first tangential to the wave's peaks,
|
||||
// the second to its valeys. In-between is where we have to do the more
|
||||
// expensive checks
|
||||
for line in 0..height {
|
||||
let y = ((height - line) as f64 - center.1 as f64 - scale_y * sin) * b;
|
||||
let x =
|
||||
(circle_radius.powi(2) - y - offset) / a + center.0 as f64 + scale_y * cos;
|
||||
let x = x.min(width as f64);
|
||||
let (col_begin, col_end) = if a.is_sign_negative() {
|
||||
(0usize, x as usize * channels)
|
||||
} else {
|
||||
(x as usize * channels, stride)
|
||||
};
|
||||
for col in col_begin..col_end {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
let old_x = x;
|
||||
let y = ((height - line) as f64 - center.1 as f64 + scale_y * sin) * b;
|
||||
let x =
|
||||
(circle_radius.powi(2) - y - offset) / a + center.0 as f64 - scale_y * cos;
|
||||
let x = x.min(width as f64);
|
||||
let (col_begin, col_end) = if old_x < x {
|
||||
(old_x as usize, x as usize)
|
||||
} else {
|
||||
(x as usize, old_x as usize)
|
||||
};
|
||||
for col in col_begin..col_end {
|
||||
if is_low(col as f64, line as f64, offset) {
|
||||
let i = line * stride + col * channels;
|
||||
for j in 0..channels {
|
||||
let old = unsafe { canvas.get_unchecked_mut(i + j) };
|
||||
let new = unsafe { img.get_unchecked(i + j) };
|
||||
change_byte(step, old, new);
|
||||
wallpaper
|
||||
.borrow_mut()
|
||||
.canvas_change(objman, pixel_format, |canvas| {
|
||||
// divide in 3 sections: the one we know will not be drawn to, the one we know
|
||||
// WILL be drawn to, and the one we need to do a more expensive check on.
|
||||
// We do this by creating 2 lines: the first tangential to the wave's peaks,
|
||||
// the second to its valeys. In-between is where we have to do the more
|
||||
// expensive checks
|
||||
for line in 0..height {
|
||||
let y = ((height - line) as f64 - center.1 as f64 - scale_y * sin) * b;
|
||||
let x = (circle_radius.powi(2) - y - offset) / a
|
||||
+ center.0 as f64
|
||||
+ scale_y * cos;
|
||||
let x = x.min(width as f64);
|
||||
let (col_begin, col_end) = if a.is_sign_negative() {
|
||||
(0usize, x as usize * channels)
|
||||
} else {
|
||||
(x as usize * channels, stride)
|
||||
};
|
||||
for col in col_begin..col_end {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
let old_x = x;
|
||||
let y = ((height - line) as f64 - center.1 as f64 + scale_y * sin) * b;
|
||||
let x = (circle_radius.powi(2) - y - offset) / a + center.0 as f64
|
||||
- scale_y * cos;
|
||||
let x = x.min(width as f64);
|
||||
let (col_begin, col_end) = if old_x < x {
|
||||
(old_x as usize, x as usize)
|
||||
} else {
|
||||
(x as usize, old_x as usize)
|
||||
};
|
||||
for col in col_begin..col_end {
|
||||
if is_low(col as f64, line as f64, offset) {
|
||||
let i = line * stride + col * channels;
|
||||
for j in 0..channels {
|
||||
let old = unsafe { canvas.get_unchecked_mut(i + j) };
|
||||
let new = unsafe { img.get_unchecked(i + j) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
self.start.elapsed().as_secs_f64() > self.seq.duration()
|
||||
@@ -307,7 +345,7 @@ struct Wipe {
|
||||
}
|
||||
|
||||
impl Wipe {
|
||||
fn new(transition: &Transition, dimensions: (u32, u32)) -> Self {
|
||||
fn new(transition: &Transition, pixel_format: PixelFormat, dimensions: (u32, u32)) -> Self {
|
||||
let width = dimensions.0;
|
||||
let height = dimensions.1;
|
||||
let center = (width / 2, height / 2);
|
||||
@@ -330,7 +368,7 @@ impl Wipe {
|
||||
let (seq, start) = bezier_seq(transition, offset as f32, max_offset as f32);
|
||||
|
||||
let step = transition.step.get();
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
let stride = width * channels;
|
||||
Self {
|
||||
start,
|
||||
@@ -345,7 +383,13 @@ impl Wipe {
|
||||
step,
|
||||
}
|
||||
}
|
||||
fn run(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
fn run(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
let Self {
|
||||
width,
|
||||
height,
|
||||
@@ -357,29 +401,31 @@ impl Wipe {
|
||||
step,
|
||||
..
|
||||
} = *self;
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
let offset = self.seq.now() as f64;
|
||||
self.seq.advance_to(self.start.elapsed().as_secs_f64());
|
||||
for wallpaper in wallpapers.iter() {
|
||||
wallpaper.borrow_mut().canvas_change(|canvas| {
|
||||
// line formula: (x-h)*a + (y-k)*b + C = r^2
|
||||
// https://www.desmos.com/calculator/vpvzk12yar
|
||||
for line in 0..height {
|
||||
let y = ((height - line) as f64 - center.1 as f64) * b;
|
||||
let x = (circle_radius.powi(2) - y - offset) / a + center.0 as f64;
|
||||
let x = x.min(width as f64);
|
||||
let (col_begin, col_end) = if a.is_sign_negative() {
|
||||
(0usize, x as usize * channels)
|
||||
} else {
|
||||
(x as usize * channels, stride)
|
||||
};
|
||||
for col in col_begin..col_end {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
wallpaper
|
||||
.borrow_mut()
|
||||
.canvas_change(objman, pixel_format, |canvas| {
|
||||
// line formula: (x-h)*a + (y-k)*b + C = r^2
|
||||
// https://www.desmos.com/calculator/vpvzk12yar
|
||||
for line in 0..height {
|
||||
let y = ((height - line) as f64 - center.1 as f64) * b;
|
||||
let x = (circle_radius.powi(2) - y - offset) / a + center.0 as f64;
|
||||
let x = x.min(width as f64);
|
||||
let (col_begin, col_end) = if a.is_sign_negative() {
|
||||
(0usize, x as usize * channels)
|
||||
} else {
|
||||
(x as usize * channels, stride)
|
||||
};
|
||||
for col in col_begin..col_end {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
self.start.elapsed().as_secs_f64() > self.seq.duration()
|
||||
}
|
||||
@@ -398,7 +444,7 @@ struct Grow {
|
||||
}
|
||||
|
||||
impl Grow {
|
||||
fn new(transition: &Transition, dimensions: (u32, u32)) -> Self {
|
||||
fn new(transition: &Transition, pixel_format: PixelFormat, dimensions: (u32, u32)) -> Self {
|
||||
let (width, height) = (dimensions.0 as f32, dimensions.1 as f32);
|
||||
let (center_x, center_y) = transition.pos.to_pixel(dimensions, transition.invert_y);
|
||||
let dist_center: f32 = 0.0;
|
||||
@@ -418,7 +464,7 @@ impl Grow {
|
||||
let (center_x, center_y) = (center_x as usize, center_y as usize);
|
||||
|
||||
let step = transition.step.get();
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
let stride = width * channels;
|
||||
let (seq, start) = bezier_seq(transition, 0.0, dist_end);
|
||||
Self {
|
||||
@@ -433,7 +479,13 @@ impl Grow {
|
||||
step,
|
||||
}
|
||||
}
|
||||
fn run(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
fn run(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
let Self {
|
||||
width,
|
||||
height,
|
||||
@@ -444,26 +496,28 @@ impl Grow {
|
||||
step,
|
||||
..
|
||||
} = *self;
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
|
||||
for wallpaper in wallpapers.iter() {
|
||||
wallpaper.borrow_mut().canvas_change(|canvas| {
|
||||
let line_begin = center_y.saturating_sub(dist_center as usize);
|
||||
let line_end = height.min(center_y + dist_center as usize);
|
||||
wallpaper
|
||||
.borrow_mut()
|
||||
.canvas_change(objman, pixel_format, |canvas| {
|
||||
let line_begin = center_y.saturating_sub(dist_center as usize);
|
||||
let line_end = height.min(center_y + dist_center as usize);
|
||||
|
||||
// to plot half a circle with radius r, we do sqrt(r^2 - x^2)
|
||||
for line in line_begin..line_end {
|
||||
let offset = (dist_center.powi(2) - (center_y as f32 - line as f32).powi(2))
|
||||
.sqrt() as usize;
|
||||
let col_begin = center_x.saturating_sub(offset) * channels;
|
||||
let col_end = width.min(center_x + offset) * channels;
|
||||
for col in col_begin..col_end {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
// to plot half a circle with radius r, we do sqrt(r^2 - x^2)
|
||||
for line in line_begin..line_end {
|
||||
let offset = (dist_center.powi(2) - (center_y as f32 - line as f32).powi(2))
|
||||
.sqrt() as usize;
|
||||
let col_begin = center_x.saturating_sub(offset) * channels;
|
||||
let col_end = width.min(center_x + offset) * channels;
|
||||
for col in col_begin..col_end {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
self.dist_center = self.seq.now();
|
||||
@@ -485,7 +539,7 @@ struct Outer {
|
||||
}
|
||||
|
||||
impl Outer {
|
||||
fn new(transition: &Transition, dimensions: (u32, u32)) -> Self {
|
||||
fn new(transition: &Transition, pixel_format: PixelFormat, dimensions: (u32, u32)) -> Self {
|
||||
let (width, height) = (dimensions.0 as f32, dimensions.1 as f32);
|
||||
let (center_x, center_y) = transition.pos.to_pixel(dimensions, transition.invert_y);
|
||||
let dist_center = {
|
||||
@@ -503,7 +557,7 @@ impl Outer {
|
||||
let (center_x, center_y) = (center_x as usize, center_y as usize);
|
||||
|
||||
let step = transition.step.get();
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
let stride = width * channels;
|
||||
let (seq, start) = bezier_seq(transition, dist_center, 0.0);
|
||||
Self {
|
||||
@@ -518,7 +572,13 @@ impl Outer {
|
||||
dist_center,
|
||||
}
|
||||
}
|
||||
fn run(&mut self, wallpapers: &mut [Rc<RefCell<Wallpaper>>], img: &[u8]) -> bool {
|
||||
fn run(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: &mut [Rc<RefCell<Wallpaper>>],
|
||||
img: &[u8],
|
||||
) -> bool {
|
||||
let Self {
|
||||
width,
|
||||
height,
|
||||
@@ -529,27 +589,29 @@ impl Outer {
|
||||
step,
|
||||
..
|
||||
} = *self;
|
||||
let channels = globals::pixel_format().channels() as usize;
|
||||
let channels = pixel_format.channels() as usize;
|
||||
for wallpaper in wallpapers.iter() {
|
||||
wallpaper.borrow_mut().canvas_change(|canvas| {
|
||||
// to plot half a circle with radius r, we do sqrt(r^2 - x^2)
|
||||
for line in 0..height {
|
||||
let offset = (dist_center.powi(2) - (center_y as f32 - line as f32).powi(2))
|
||||
.sqrt() as usize;
|
||||
let col_begin = center_x.saturating_sub(offset) * channels;
|
||||
let col_end = width.min(center_x + offset) * channels;
|
||||
for col in 0..col_begin {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
wallpaper
|
||||
.borrow_mut()
|
||||
.canvas_change(objman, pixel_format, |canvas| {
|
||||
// to plot half a circle with radius r, we do sqrt(r^2 - x^2)
|
||||
for line in 0..height {
|
||||
let offset = (dist_center.powi(2) - (center_y as f32 - line as f32).powi(2))
|
||||
.sqrt() as usize;
|
||||
let col_begin = center_x.saturating_sub(offset) * channels;
|
||||
let col_end = width.min(center_x + offset) * channels;
|
||||
for col in 0..col_begin {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
for col in col_end..stride {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
}
|
||||
for col in col_end..stride {
|
||||
let old = unsafe { canvas.get_unchecked_mut(line * stride + col) };
|
||||
let new = unsafe { img.get_unchecked(line * stride + col) };
|
||||
change_byte(step, old, new);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
self.dist_center = self.seq.now();
|
||||
self.seq.advance_to(self.start.elapsed().as_secs_f64());
|
||||
|
||||
@@ -15,8 +15,8 @@ use rustix::{
|
||||
|
||||
use wallpaper::Wallpaper;
|
||||
use wayland::{
|
||||
globals::{self, FractionalScaleManager, Initializer},
|
||||
ObjectId,
|
||||
globals::{self, InitState},
|
||||
ObjectId, ObjectManager,
|
||||
};
|
||||
|
||||
use std::{
|
||||
@@ -31,7 +31,9 @@ use std::{
|
||||
};
|
||||
|
||||
use animations::{ImageAnimator, TransitionAnimator};
|
||||
use common::ipc::{Answer, BgInfo, ImageReq, IpcSocket, RequestRecv, RequestSend, Scale, Server};
|
||||
use common::ipc::{
|
||||
Answer, BgInfo, ImageReq, IpcSocket, PixelFormat, RequestRecv, RequestSend, Scale, Server,
|
||||
};
|
||||
use common::mmap::MmappedStr;
|
||||
|
||||
// We need this because this might be set by signals, so we can't keep it in the daemon
|
||||
@@ -50,83 +52,58 @@ extern "C" fn signal_handler(_s: libc::c_int) {
|
||||
}
|
||||
|
||||
struct Daemon {
|
||||
objman: ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
wallpapers: Vec<Rc<RefCell<Wallpaper>>>,
|
||||
transition_animators: Vec<TransitionAnimator>,
|
||||
image_animators: Vec<ImageAnimator>,
|
||||
use_cache: bool,
|
||||
fractional_scale_manager: Option<FractionalScaleManager>,
|
||||
fractional_scale_manager: Option<ObjectId>,
|
||||
poll_time: PollTime,
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
fn new(initializer: &Initializer, no_cache: bool) -> Self {
|
||||
log::info!(
|
||||
"Selected wl_shm format: {:?}",
|
||||
wayland::globals::pixel_format()
|
||||
fn new(init_state: InitState, no_cache: bool) -> Self {
|
||||
let InitState {
|
||||
output_names,
|
||||
fractional_scale,
|
||||
objman,
|
||||
pixel_format,
|
||||
} = init_state;
|
||||
|
||||
assert_eq!(
|
||||
fractional_scale.is_some(),
|
||||
objman.fractional_scale_support()
|
||||
);
|
||||
let fractional_scale_manager = initializer.fractional_scale().cloned();
|
||||
|
||||
let wallpapers = Vec::new();
|
||||
log::info!("Selected wl_shm format: {pixel_format:?}");
|
||||
|
||||
Self {
|
||||
wallpapers,
|
||||
let mut daemon = Self {
|
||||
objman,
|
||||
pixel_format,
|
||||
wallpapers: Vec::new(),
|
||||
transition_animators: Vec::new(),
|
||||
image_animators: Vec::new(),
|
||||
use_cache: !no_cache,
|
||||
fractional_scale_manager,
|
||||
fractional_scale_manager: fractional_scale.map(|x| x.id()),
|
||||
poll_time: PollTime::Never,
|
||||
};
|
||||
|
||||
for output_name in output_names {
|
||||
daemon.new_output(output_name);
|
||||
}
|
||||
|
||||
daemon
|
||||
}
|
||||
|
||||
fn new_output(&mut self, output_name: u32) {
|
||||
use wayland::interfaces::*;
|
||||
let output = globals::object_create(wayland::WlDynObj::Output);
|
||||
wl_registry::req::bind(output_name, output, "wl_output", 4).unwrap();
|
||||
|
||||
let surface = globals::object_create(wayland::WlDynObj::Surface);
|
||||
wl_compositor::req::create_surface(surface).unwrap();
|
||||
|
||||
let region = globals::object_create(wayland::WlDynObj::Region);
|
||||
wl_compositor::req::create_region(region).unwrap();
|
||||
|
||||
wl_surface::req::set_input_region(surface, Some(region)).unwrap();
|
||||
wl_region::req::destroy(region).unwrap();
|
||||
|
||||
let layer_surface = globals::object_create(wayland::WlDynObj::LayerSurface);
|
||||
zwlr_layer_shell_v1::req::get_layer_surface(
|
||||
layer_surface,
|
||||
surface,
|
||||
Some(output),
|
||||
zwlr_layer_shell_v1::layer::BACKGROUND,
|
||||
"swww-daemon",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let viewport = globals::object_create(wayland::WlDynObj::Viewport);
|
||||
wp_viewporter::req::get_viewport(viewport, surface).unwrap();
|
||||
|
||||
let wp_fractional = if let Some(fract_man) = self.fractional_scale_manager.as_ref() {
|
||||
let fractional = globals::object_create(wayland::WlDynObj::FractionalScale);
|
||||
wp_fractional_scale_manager_v1::req::get_fractional_scale(
|
||||
fract_man.id(),
|
||||
fractional,
|
||||
surface,
|
||||
)
|
||||
.unwrap();
|
||||
Some(fractional)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
debug!("New output: {output_name}");
|
||||
self.wallpapers.push(Rc::new(RefCell::new(Wallpaper::new(
|
||||
output,
|
||||
let wallpaper = Rc::new(RefCell::new(Wallpaper::new(
|
||||
&mut self.objman,
|
||||
self.pixel_format,
|
||||
self.fractional_scale_manager,
|
||||
output_name,
|
||||
surface,
|
||||
viewport,
|
||||
wp_fractional,
|
||||
layer_surface,
|
||||
))));
|
||||
)));
|
||||
self.wallpapers.push(wallpaper);
|
||||
}
|
||||
|
||||
fn recv_socket_msg(&mut self, stream: IpcSocket<Server>) {
|
||||
@@ -146,9 +123,9 @@ impl Daemon {
|
||||
for wallpaper in &wallpapers {
|
||||
let mut wallpaper = wallpaper.borrow_mut();
|
||||
wallpaper.set_img_info(common::ipc::BgImg::Color(clear.color));
|
||||
wallpaper.clear(clear.color);
|
||||
wallpaper.clear(&mut self.objman, self.pixel_format, clear.color);
|
||||
}
|
||||
crate::wallpaper::attach_buffers_and_damage_surfaces(&wallpapers);
|
||||
crate::wallpaper::attach_buffers_and_damage_surfaces(&mut self.objman, &wallpapers);
|
||||
crate::wallpaper::commit_wallpapers(&wallpapers);
|
||||
Answer::Ok
|
||||
}
|
||||
@@ -178,10 +155,14 @@ impl Daemon {
|
||||
};
|
||||
let wallpapers = self.find_wallpapers_by_names(&names);
|
||||
self.stop_animations(&wallpapers);
|
||||
if let Some(mut transition) =
|
||||
TransitionAnimator::new(wallpapers, &transition, img, animation)
|
||||
{
|
||||
transition.frame();
|
||||
if let Some(mut transition) = TransitionAnimator::new(
|
||||
wallpapers,
|
||||
&transition,
|
||||
self.pixel_format,
|
||||
img,
|
||||
animation,
|
||||
) {
|
||||
transition.frame(&mut self.objman, self.pixel_format);
|
||||
self.transition_animators.push(transition);
|
||||
}
|
||||
}
|
||||
@@ -197,7 +178,7 @@ impl Daemon {
|
||||
fn wallpapers_info(&self) -> Box<[BgInfo]> {
|
||||
self.wallpapers
|
||||
.iter()
|
||||
.map(|wallpaper| wallpaper.borrow().get_bg_info())
|
||||
.map(|wallpaper| wallpaper.borrow().get_bg_info(self.pixel_format))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -235,10 +216,13 @@ impl Daemon {
|
||||
spin_sleep(time);
|
||||
}
|
||||
|
||||
wallpaper::attach_buffers_and_damage_surfaces(&animator.wallpapers);
|
||||
wallpaper::attach_buffers_and_damage_surfaces(
|
||||
&mut self.objman,
|
||||
&animator.wallpapers,
|
||||
);
|
||||
wallpaper::commit_wallpapers(&animator.wallpapers);
|
||||
animator.updt_time();
|
||||
if animator.frame() {
|
||||
if animator.frame(&mut self.objman, self.pixel_format) {
|
||||
let animator = self.transition_animators.swap_remove(i);
|
||||
if let Some(anim) = animator.into_image_animator() {
|
||||
self.image_animators.push(anim);
|
||||
@@ -266,10 +250,13 @@ impl Daemon {
|
||||
spin_sleep(time);
|
||||
}
|
||||
|
||||
wallpaper::attach_buffers_and_damage_surfaces(&animator.wallpapers);
|
||||
wallpaper::attach_buffers_and_damage_surfaces(
|
||||
&mut self.objman,
|
||||
&animator.wallpapers,
|
||||
);
|
||||
wallpaper::commit_wallpapers(&animator.wallpapers);
|
||||
animator.updt_time();
|
||||
animator.frame();
|
||||
animator.frame(&mut self.objman, self.pixel_format);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,10 +281,16 @@ impl Daemon {
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland::interfaces::wl_display::HasObjman for Daemon {
|
||||
fn objman(&mut self) -> &mut ObjectManager {
|
||||
&mut self.objman
|
||||
}
|
||||
}
|
||||
|
||||
impl wayland::interfaces::wl_display::EvHandler for Daemon {
|
||||
fn delete_id(&mut self, id: u32) {
|
||||
if let Some(id) = NonZeroU32::new(id) {
|
||||
globals::object_remove(ObjectId::new(id));
|
||||
self.objman.remove(ObjectId::new(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,7 +367,7 @@ impl wayland::interfaces::wl_output::EvHandler for Daemon {
|
||||
if wallpaper.borrow().has_output(sender_id) {
|
||||
if wallpaper
|
||||
.borrow_mut()
|
||||
.commit_surface_changes(self.use_cache)
|
||||
.commit_surface_changes(&mut self.objman, self.use_cache)
|
||||
{
|
||||
self.stop_animations(&[wallpaper.clone()]);
|
||||
}
|
||||
@@ -502,7 +495,7 @@ impl wayland::interfaces::wp_fractional_scale_v1::EvHandler for Daemon {
|
||||
wallpaper.borrow_mut().set_scale(Scale::Fractional(factor));
|
||||
if wallpaper
|
||||
.borrow_mut()
|
||||
.commit_surface_changes(self.use_cache)
|
||||
.commit_surface_changes(&mut self.objman, self.use_cache)
|
||||
{
|
||||
self.stop_animations(&[wallpaper.clone()]);
|
||||
}
|
||||
@@ -521,7 +514,7 @@ fn main() -> Result<(), String> {
|
||||
make_logger(cli.quiet);
|
||||
|
||||
// initialize the wayland connection, getting all the necessary globals
|
||||
let initializer = wayland::globals::init(cli.format);
|
||||
let init_state = wayland::globals::init(cli.format);
|
||||
|
||||
// create the socket listener and setup the signal handlers
|
||||
// this will also return an error if there is an `swww-daemon` instance already
|
||||
@@ -530,11 +523,7 @@ fn main() -> Result<(), String> {
|
||||
setup_signals();
|
||||
|
||||
// use the initializer to create the Daemon, then drop it to free up the memory
|
||||
let mut daemon = Daemon::new(&initializer, cli.no_cache);
|
||||
for &output_name in initializer.output_names() {
|
||||
daemon.new_output(output_name);
|
||||
}
|
||||
drop(initializer);
|
||||
let mut daemon = Daemon::new(init_state, cli.no_cache);
|
||||
|
||||
if let Ok(true) = sd_notify::booted() {
|
||||
if let Err(e) = sd_notify::notify(true, &[sd_notify::NotifyState::Ready]) {
|
||||
@@ -574,7 +563,7 @@ fn main() -> Result<(), String> {
|
||||
globals::WP_VIEWPORTER => error!("wp_viewporter has no events"),
|
||||
globals::ZWLR_LAYER_SHELL_V1 => error!("zwlr_layer_shell_v1 has no events"),
|
||||
other => {
|
||||
let obj_id = globals::object_type_get(other);
|
||||
let obj_id = daemon.objman.get(other);
|
||||
match obj_id {
|
||||
Some(WlDynObj::Output) => wl_output::event(&mut daemon, msg, payload),
|
||||
Some(WlDynObj::Surface) => wl_surface::event(&mut daemon, msg, payload),
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
use common::ipc::{BgImg, BgInfo, Scale};
|
||||
use common::ipc::{BgImg, BgInfo, PixelFormat, Scale};
|
||||
use log::{debug, error, warn};
|
||||
|
||||
use std::{cell::RefCell, num::NonZeroI32, rc::Rc, sync::atomic::AtomicBool};
|
||||
|
||||
use crate::wayland::{
|
||||
bump_pool::BumpPool,
|
||||
globals,
|
||||
interfaces::{
|
||||
wl_output, wl_surface, wp_fractional_scale_v1, wp_viewport, zwlr_layer_surface_v1,
|
||||
},
|
||||
ObjectId, WlDynObj,
|
||||
ObjectId, ObjectManager, WlDynObj,
|
||||
};
|
||||
|
||||
struct FrameCallbackHandler {
|
||||
@@ -18,8 +17,8 @@ struct FrameCallbackHandler {
|
||||
}
|
||||
|
||||
impl FrameCallbackHandler {
|
||||
fn new(surface: ObjectId) -> Self {
|
||||
let callback = globals::object_create(WlDynObj::Callback);
|
||||
fn new(objman: &mut ObjectManager, surface: ObjectId) -> Self {
|
||||
let callback = objman.create(WlDynObj::Callback);
|
||||
wl_surface::req::frame(surface, callback).unwrap();
|
||||
FrameCallbackHandler {
|
||||
done: true, // we do not have to wait for the first frame
|
||||
@@ -27,8 +26,8 @@ impl FrameCallbackHandler {
|
||||
}
|
||||
}
|
||||
|
||||
fn request_frame_callback(&mut self, surface: ObjectId) {
|
||||
let callback = globals::object_create(WlDynObj::Callback);
|
||||
fn request_frame_callback(&mut self, objman: &mut ObjectManager, surface: ObjectId) {
|
||||
let callback = objman.create(WlDynObj::Callback);
|
||||
wl_surface::req::frame(surface, callback).unwrap();
|
||||
self.callback = callback;
|
||||
}
|
||||
@@ -85,13 +84,48 @@ impl std::cmp::PartialEq for Wallpaper {
|
||||
|
||||
impl Wallpaper {
|
||||
pub(crate) fn new(
|
||||
output: ObjectId,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
fractional_scale_manager: Option<ObjectId>,
|
||||
output_name: u32,
|
||||
wl_surface: ObjectId,
|
||||
wp_viewport: ObjectId,
|
||||
wp_fractional: Option<ObjectId>,
|
||||
layer_surface: ObjectId,
|
||||
) -> Self {
|
||||
use crate::wayland::{self, interfaces::*};
|
||||
let output = objman.create(wayland::WlDynObj::Output);
|
||||
wl_registry::req::bind(output_name, output, "wl_output", 4).unwrap();
|
||||
|
||||
let wl_surface = objman.create(wayland::WlDynObj::Surface);
|
||||
wl_compositor::req::create_surface(wl_surface).unwrap();
|
||||
|
||||
let region = objman.create(wayland::WlDynObj::Region);
|
||||
wl_compositor::req::create_region(region).unwrap();
|
||||
|
||||
wl_surface::req::set_input_region(wl_surface, Some(region)).unwrap();
|
||||
wl_region::req::destroy(region).unwrap();
|
||||
|
||||
let layer_surface = objman.create(wayland::WlDynObj::LayerSurface);
|
||||
zwlr_layer_shell_v1::req::get_layer_surface(
|
||||
layer_surface,
|
||||
wl_surface,
|
||||
Some(output),
|
||||
zwlr_layer_shell_v1::layer::BACKGROUND,
|
||||
"swww-daemon",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let wp_viewport = objman.create(wayland::WlDynObj::Viewport);
|
||||
wp_viewporter::req::get_viewport(wp_viewport, wl_surface).unwrap();
|
||||
|
||||
let wp_fractional = if let Some(fract_man) = fractional_scale_manager {
|
||||
let fractional = objman.create(wayland::WlDynObj::FractionalScale);
|
||||
wp_fractional_scale_manager_v1::req::get_fractional_scale(
|
||||
fract_man, fractional, wl_surface,
|
||||
)
|
||||
.unwrap();
|
||||
Some(fractional)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let inner = WallpaperInner::default();
|
||||
let inner_staging = WallpaperInner::default();
|
||||
|
||||
@@ -106,12 +140,13 @@ impl Wallpaper {
|
||||
.unwrap();
|
||||
wl_surface::req::set_buffer_scale(wl_surface, 1).unwrap();
|
||||
|
||||
let frame_callback_handler = FrameCallbackHandler::new(wl_surface);
|
||||
let frame_callback_handler = FrameCallbackHandler::new(objman, wl_surface);
|
||||
// commit so that the compositor send the initial configuration
|
||||
wl_surface::req::commit(wl_surface).unwrap();
|
||||
|
||||
let pool = BumpPool::new(256, 256);
|
||||
let pool = BumpPool::new(256, 256, objman, pixel_format);
|
||||
|
||||
debug!("New output: {output_name}");
|
||||
Self {
|
||||
output,
|
||||
output_name,
|
||||
@@ -128,7 +163,7 @@ impl Wallpaper {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_bg_info(&self) -> BgInfo {
|
||||
pub fn get_bg_info(&self, pixel_format: PixelFormat) -> BgInfo {
|
||||
BgInfo {
|
||||
name: self.inner.name.clone().unwrap_or("?".to_string()),
|
||||
dim: (
|
||||
@@ -137,7 +172,7 @@ impl Wallpaper {
|
||||
),
|
||||
scale_factor: self.inner.scale_factor,
|
||||
img: self.img.clone(),
|
||||
pixel_format: globals::pixel_format(),
|
||||
pixel_format,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +248,7 @@ impl Wallpaper {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit_surface_changes(&mut self, use_cache: bool) -> bool {
|
||||
pub fn commit_surface_changes(&mut self, objman: &mut ObjectManager, use_cache: bool) -> bool {
|
||||
use wl_output::transform;
|
||||
let inner = &mut self.inner;
|
||||
let staging = &self.inner_staging;
|
||||
@@ -283,7 +318,7 @@ impl Wallpaper {
|
||||
self.pool.resize(w, h);
|
||||
|
||||
self.frame_callback_handler
|
||||
.request_frame_callback(self.wl_surface);
|
||||
.request_frame_callback(objman, self.wl_surface);
|
||||
wl_surface::req::commit(self.wl_surface).unwrap();
|
||||
self.configured
|
||||
.store(true, std::sync::atomic::Ordering::Release);
|
||||
@@ -342,20 +377,30 @@ impl Wallpaper {
|
||||
(dim.0 as u32, dim.1 as u32)
|
||||
}
|
||||
|
||||
pub(super) fn canvas_change<F, T>(&mut self, f: F) -> T
|
||||
pub(super) fn canvas_change<F, T>(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
f: F,
|
||||
) -> T
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> T,
|
||||
{
|
||||
f(self.pool.get_drawable())
|
||||
f(self.pool.get_drawable(objman, pixel_format))
|
||||
}
|
||||
|
||||
pub(super) fn frame_callback_completed(&mut self) {
|
||||
self.frame_callback_handler.done = true;
|
||||
}
|
||||
|
||||
pub(super) fn clear(&mut self, color: [u8; 3]) {
|
||||
self.canvas_change(|canvas| {
|
||||
for pixel in canvas.chunks_exact_mut(globals::pixel_format().channels().into()) {
|
||||
pub(super) fn clear(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
color: [u8; 3],
|
||||
) {
|
||||
self.canvas_change(objman, pixel_format, |canvas| {
|
||||
for pixel in canvas.chunks_exact_mut(pixel_format.channels().into()) {
|
||||
pixel[0..3].copy_from_slice(&color);
|
||||
}
|
||||
})
|
||||
@@ -368,7 +413,10 @@ impl Wallpaper {
|
||||
}
|
||||
|
||||
/// attaches all pending buffers and damages all surfaces with one single request
|
||||
pub(crate) fn attach_buffers_and_damage_surfaces(wallpapers: &[Rc<RefCell<Wallpaper>>]) {
|
||||
pub(crate) fn attach_buffers_and_damage_surfaces(
|
||||
objman: &mut ObjectManager,
|
||||
wallpapers: &[Rc<RefCell<Wallpaper>>],
|
||||
) {
|
||||
#[rustfmt::skip]
|
||||
// Note this is little-endian specific
|
||||
const MSG: [u8; 56] = [
|
||||
@@ -409,7 +457,7 @@ pub(crate) fn attach_buffers_and_damage_surfaces(wallpapers: &[Rc<RefCell<Wallpa
|
||||
msg[40..44].copy_from_slice(&height.to_ne_bytes());
|
||||
|
||||
// frame callback
|
||||
let callback = globals::object_create(WlDynObj::Callback);
|
||||
let callback = objman.create(WlDynObj::Callback);
|
||||
wallpaper.frame_callback_handler.callback = callback;
|
||||
msg[44..48].copy_from_slice(&wallpaper.wl_surface.get().to_ne_bytes());
|
||||
msg[52..56].copy_from_slice(&callback.get().to_ne_bytes());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use common::mmap::Mmap;
|
||||
use common::{ipc::PixelFormat, mmap::Mmap};
|
||||
|
||||
use super::{globals, ObjectId};
|
||||
use super::{ObjectId, ObjectManager};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Buffer {
|
||||
@@ -10,6 +10,7 @@ struct Buffer {
|
||||
|
||||
impl Buffer {
|
||||
fn new(
|
||||
objman: &mut ObjectManager,
|
||||
pool_id: ObjectId,
|
||||
offset: i32,
|
||||
width: i32,
|
||||
@@ -18,7 +19,7 @@ impl Buffer {
|
||||
format: u32,
|
||||
) -> Self {
|
||||
let released = true;
|
||||
let object_id = globals::object_create(super::WlDynObj::Buffer);
|
||||
let object_id = objman.create(super::WlDynObj::Buffer);
|
||||
super::interfaces::wl_shm_pool::req::create_buffer(
|
||||
pool_id, object_id, offset, width, height, stride, format,
|
||||
)
|
||||
@@ -66,11 +67,15 @@ pub(crate) struct BumpPool {
|
||||
|
||||
impl BumpPool {
|
||||
/// We assume `width` and `height` have already been multiplied by their scale factor
|
||||
pub(crate) fn new(width: i32, height: i32) -> Self {
|
||||
let len =
|
||||
width as usize * height as usize * super::globals::pixel_format().channels() as usize;
|
||||
pub(crate) fn new(
|
||||
width: i32,
|
||||
height: i32,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
) -> Self {
|
||||
let len = width as usize * height as usize * pixel_format.channels() as usize;
|
||||
let mmap = Mmap::create(len);
|
||||
let pool_id = globals::object_create(super::WlDynObj::ShmPool);
|
||||
let pool_id = objman.create(super::WlDynObj::ShmPool);
|
||||
super::interfaces::wl_shm::req::create_pool(pool_id, &mmap.fd(), len as i32)
|
||||
.expect("failed to create WlShmPool object");
|
||||
let buffers = Vec::with_capacity(2);
|
||||
@@ -108,24 +113,22 @@ impl BumpPool {
|
||||
}
|
||||
}
|
||||
|
||||
fn buffer_len(&self) -> usize {
|
||||
self.width as usize
|
||||
* self.height as usize
|
||||
* super::globals::pixel_format().channels() as usize
|
||||
const fn buffer_len(&self, pixel_format: PixelFormat) -> usize {
|
||||
self.width as usize * self.height as usize * pixel_format.channels() as usize
|
||||
}
|
||||
|
||||
fn buffer_offset(&self, buffer_index: usize) -> usize {
|
||||
self.buffer_len() * buffer_index
|
||||
const fn buffer_offset(&self, buffer_index: usize, pixel_format: PixelFormat) -> usize {
|
||||
self.buffer_len(pixel_format) * buffer_index
|
||||
}
|
||||
|
||||
fn occupied_bytes(&self) -> usize {
|
||||
self.buffer_offset(self.buffers.len())
|
||||
fn occupied_bytes(&self, pixel_format: PixelFormat) -> usize {
|
||||
self.buffer_offset(self.buffers.len(), pixel_format)
|
||||
}
|
||||
|
||||
/// resizes the pool and creates a new WlBuffer at the next free offset
|
||||
fn grow(&mut self) {
|
||||
let len = self.buffer_len();
|
||||
let new_len = self.occupied_bytes() + len;
|
||||
fn grow(&mut self, objman: &mut ObjectManager, pixel_format: PixelFormat) {
|
||||
let len = self.buffer_len(pixel_format);
|
||||
let new_len = self.occupied_bytes(pixel_format) + len;
|
||||
|
||||
// we unmap the shared memory file descriptor when animations are done, so here we must
|
||||
// ensure the bytes are actually mmaped
|
||||
@@ -141,12 +144,13 @@ impl BumpPool {
|
||||
|
||||
let new_buffer_index = self.buffers.len();
|
||||
self.buffers.push(Buffer::new(
|
||||
objman,
|
||||
self.pool_id,
|
||||
self.buffer_offset(new_buffer_index) as i32,
|
||||
self.buffer_offset(new_buffer_index, pixel_format) as i32,
|
||||
self.width,
|
||||
self.height,
|
||||
self.width * super::globals::pixel_format().channels() as i32,
|
||||
super::globals::wl_shm_format(),
|
||||
self.width * pixel_format.channels() as i32,
|
||||
super::globals::wl_shm_format(pixel_format),
|
||||
));
|
||||
|
||||
log::info!(
|
||||
@@ -159,7 +163,11 @@ impl BumpPool {
|
||||
/// Returns a drawable surface. If we can't find a free buffer, we request more memory
|
||||
///
|
||||
/// This function automatically handles copying the previous buffer over onto the new one
|
||||
pub(crate) fn get_drawable(&mut self) -> &mut [u8] {
|
||||
pub(crate) fn get_drawable(
|
||||
&mut self,
|
||||
objman: &mut ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
) -> &mut [u8] {
|
||||
let (i, buf) = match self
|
||||
.buffers
|
||||
.iter_mut()
|
||||
@@ -168,17 +176,17 @@ impl BumpPool {
|
||||
{
|
||||
Some((i, buf)) => (i, buf),
|
||||
None => {
|
||||
self.grow();
|
||||
self.grow(objman, pixel_format);
|
||||
(self.buffers.len() - 1, self.buffers.last_mut().unwrap())
|
||||
}
|
||||
};
|
||||
buf.unset_released();
|
||||
|
||||
let len = self.buffer_len();
|
||||
let offset = self.buffer_offset(i);
|
||||
let len = self.buffer_len(pixel_format);
|
||||
let offset = self.buffer_offset(i, pixel_format);
|
||||
|
||||
if self.last_used_buffer != i {
|
||||
let last_offset = self.buffer_offset(self.last_used_buffer);
|
||||
let last_offset = self.buffer_offset(self.last_used_buffer, pixel_format);
|
||||
self.mmap
|
||||
.slice_mut()
|
||||
.copy_within(last_offset..last_offset + len, offset);
|
||||
|
||||
@@ -18,9 +18,9 @@ use rustix::{
|
||||
};
|
||||
|
||||
use common::ipc::PixelFormat;
|
||||
use log::{debug, error, info};
|
||||
use log::{debug, error};
|
||||
|
||||
use super::{ObjectId, ObjectManager, WlDynObj};
|
||||
use super::{ObjectId, ObjectManager};
|
||||
use std::{num::NonZeroU32, path::PathBuf, sync::atomic::AtomicBool};
|
||||
|
||||
// all of these objects must always exist for `swww-daemon` to work correctly, so we turn them into
|
||||
@@ -42,13 +42,14 @@ const REQUIRED_GLOBALS: [&str; 4] = [
|
||||
"wp_viewporter",
|
||||
"zwlr_layer_shell_v1",
|
||||
];
|
||||
|
||||
/// Minimal version necessary for `REQUIRED_GLOBALS`
|
||||
const VERSIONS: [u32; 4] = [4, 1, 1, 3];
|
||||
|
||||
/// This is an unsafe static mut that we only ever write to once, during the `init` function call.
|
||||
/// Any other function in this program can only access this variable through the `wayland_fd`
|
||||
/// function, which always creates an immutable reference, which should be safe.
|
||||
static mut WAYLAND_FD: OwnedFd = unsafe { std::mem::zeroed() };
|
||||
static mut FRACTIONAL_SCALE_SUPPORT: bool = false;
|
||||
static mut PIXEL_FORMAT: PixelFormat = PixelFormat::Xrgb;
|
||||
static mut OBJECT_MANAGER: ObjectManager = ObjectManager::new();
|
||||
|
||||
static INITIALIZED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
@@ -60,43 +61,8 @@ pub fn wayland_fd() -> BorrowedFd<'static> {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn fractional_scale_support() -> bool {
|
||||
unsafe { FRACTIONAL_SCALE_SUPPORT }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Safe because this is a single threaded application, so no race conditions can occur
|
||||
pub fn object_type_get(object_id: ObjectId) -> Option<WlDynObj> {
|
||||
debug_assert!(INITIALIZED.load(std::sync::atomic::Ordering::Relaxed));
|
||||
let ptr = &raw const OBJECT_MANAGER;
|
||||
unsafe { &*ptr }.get(object_id)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// Safe because this is a single threaded application, so no race conditions can occur
|
||||
pub fn object_create(object_type: WlDynObj) -> ObjectId {
|
||||
debug_assert!(INITIALIZED.load(std::sync::atomic::Ordering::Relaxed));
|
||||
let ptr = &raw mut OBJECT_MANAGER;
|
||||
unsafe { &mut *ptr }.create(object_type)
|
||||
}
|
||||
|
||||
/// Safe because this is a single threaded application, so no race conditions can occur
|
||||
pub fn object_remove(object_id: ObjectId) {
|
||||
debug_assert!(INITIALIZED.load(std::sync::atomic::Ordering::Relaxed));
|
||||
let ptr = &raw mut OBJECT_MANAGER;
|
||||
unsafe { &mut *ptr }.remove(object_id)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn pixel_format() -> PixelFormat {
|
||||
debug_assert!(INITIALIZED.load(std::sync::atomic::Ordering::Relaxed));
|
||||
unsafe { PIXEL_FORMAT }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn wl_shm_format() -> u32 {
|
||||
debug_assert!(INITIALIZED.load(std::sync::atomic::Ordering::Relaxed));
|
||||
match unsafe { PIXEL_FORMAT } {
|
||||
pub fn wl_shm_format(pixel_format: PixelFormat) -> u32 {
|
||||
match pixel_format {
|
||||
PixelFormat::Xrgb => super::interfaces::wl_shm::format::XRGB8888,
|
||||
PixelFormat::Xbgr => super::interfaces::wl_shm::format::XBGR8888,
|
||||
PixelFormat::Rgb => super::interfaces::wl_shm::format::RGB888,
|
||||
@@ -105,24 +71,16 @@ pub fn wl_shm_format() -> u32 {
|
||||
}
|
||||
|
||||
/// Note that this function assumes the logger has already been set up
|
||||
pub fn init(pixel_format: Option<PixelFormat>) -> Initializer {
|
||||
pub fn init(pixel_format: Option<PixelFormat>) -> InitState {
|
||||
if INITIALIZED.load(std::sync::atomic::Ordering::Relaxed) {
|
||||
panic!("trying to run initialization code twice");
|
||||
}
|
||||
|
||||
let mut initializer = Initializer::new(pixel_format);
|
||||
|
||||
// initialize the two most important globals:
|
||||
// * the wayland file descriptor; and
|
||||
// * the object manager
|
||||
// we optionally initialize the pixel_format, if necessary
|
||||
unsafe {
|
||||
WAYLAND_FD = connect();
|
||||
if let Some(format) = pixel_format {
|
||||
info!("Forced usage of wl_shm format: {:?}", format);
|
||||
PIXEL_FORMAT = format;
|
||||
}
|
||||
}
|
||||
let mut initializer = Initializer::new(pixel_format);
|
||||
|
||||
// the only globals that can break catastrophically are WAYLAND_FD and OBJECT_MANAGER, that we
|
||||
// have just initialized above. So this is safe
|
||||
INITIALIZED.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||
@@ -169,7 +127,6 @@ pub fn init(pixel_format: Option<PixelFormat>) -> Initializer {
|
||||
|
||||
// bind fractional scale, if it is supported
|
||||
if let Some(fractional_scale_manager) = initializer.fractional_scale.as_ref() {
|
||||
unsafe { FRACTIONAL_SCALE_SUPPORT = true };
|
||||
super::interfaces::wl_registry::req::bind(
|
||||
fractional_scale_manager.name.get(),
|
||||
fractional_scale_manager.id,
|
||||
@@ -201,7 +158,7 @@ pub fn init(pixel_format: Option<PixelFormat>) -> Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
initializer
|
||||
initializer.into_init_state()
|
||||
}
|
||||
|
||||
/// mostly copy-pasted from `wayland-client.rs`
|
||||
@@ -263,7 +220,9 @@ impl FractionalScaleManager {
|
||||
}
|
||||
|
||||
/// Helper struct to do all the initialization in this file
|
||||
pub struct Initializer {
|
||||
struct Initializer {
|
||||
objman: ObjectManager,
|
||||
pixel_format: PixelFormat,
|
||||
global_names: [u32; REQUIRED_GLOBALS.len()],
|
||||
output_names: Vec<u32>,
|
||||
fractional_scale: Option<FractionalScaleManager>,
|
||||
@@ -271,14 +230,24 @@ pub struct Initializer {
|
||||
should_exit: bool,
|
||||
}
|
||||
|
||||
/// Helper struct to expose all of the initialized state
|
||||
pub struct InitState {
|
||||
pub output_names: Vec<u32>,
|
||||
pub fractional_scale: Option<FractionalScaleManager>,
|
||||
pub objman: ObjectManager,
|
||||
pub pixel_format: PixelFormat,
|
||||
}
|
||||
|
||||
impl Initializer {
|
||||
fn new(cli_format: Option<PixelFormat>) -> Self {
|
||||
Self {
|
||||
objman: ObjectManager::new(),
|
||||
global_names: [0; REQUIRED_GLOBALS.len()],
|
||||
output_names: Vec::new(),
|
||||
fractional_scale: None,
|
||||
forced_shm_format: cli_format.is_some(),
|
||||
should_exit: false,
|
||||
pixel_format: cli_format.unwrap_or(PixelFormat::Xrgb),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,6 +259,16 @@ impl Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
fn into_init_state(self) -> InitState {
|
||||
debug!("Initialization Over");
|
||||
InitState {
|
||||
output_names: self.output_names,
|
||||
fractional_scale: self.fractional_scale,
|
||||
objman: self.objman,
|
||||
pixel_format: self.pixel_format,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output_names(&self) -> &[u32] {
|
||||
&self.output_names
|
||||
}
|
||||
@@ -299,6 +278,12 @@ impl Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
impl super::interfaces::wl_display::HasObjman for Initializer {
|
||||
fn objman(&mut self) -> &mut ObjectManager {
|
||||
&mut self.objman
|
||||
}
|
||||
}
|
||||
|
||||
impl super::interfaces::wl_display::EvHandler for Initializer {
|
||||
fn delete_id(&mut self, id: u32) {
|
||||
if id == 3 // initial callback for the roundtrip
|
||||
@@ -333,6 +318,7 @@ impl super::interfaces::wl_registry::EvHandler for Initializer {
|
||||
id: ObjectId(unsafe { NonZeroU32::new_unchecked(7) }),
|
||||
name: name.try_into().unwrap(),
|
||||
});
|
||||
self.objman.set_fractional_scale_support(true);
|
||||
}
|
||||
"wl_output" => {
|
||||
if version < 4 {
|
||||
@@ -371,29 +357,23 @@ impl super::interfaces::wl_shm::EvHandler for Initializer {
|
||||
}
|
||||
super::interfaces::wl_shm::format::XBGR8888 => {
|
||||
debug!("available shm format: Xbgr");
|
||||
if !self.forced_shm_format && pixel_format() == PixelFormat::Xrgb {
|
||||
unsafe { PIXEL_FORMAT = PixelFormat::Xbgr }
|
||||
if !self.forced_shm_format && self.pixel_format == PixelFormat::Xrgb {
|
||||
self.pixel_format = PixelFormat::Xbgr;
|
||||
}
|
||||
}
|
||||
super::interfaces::wl_shm::format::RGB888 => {
|
||||
debug!("available shm format: Rbg");
|
||||
if !self.forced_shm_format && pixel_format() != PixelFormat::Bgr {
|
||||
unsafe { PIXEL_FORMAT = PixelFormat::Rgb }
|
||||
if !self.forced_shm_format && self.pixel_format != PixelFormat::Bgr {
|
||||
self.pixel_format = PixelFormat::Rgb
|
||||
}
|
||||
}
|
||||
super::interfaces::wl_shm::format::BGR888 => {
|
||||
debug!("available shm format: Bgr");
|
||||
if !self.forced_shm_format {
|
||||
unsafe { PIXEL_FORMAT = PixelFormat::Bgr }
|
||||
self.pixel_format = PixelFormat::Bgr
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Initializer {
|
||||
fn drop(&mut self) {
|
||||
debug!("Initialization Over");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
use super::{
|
||||
globals,
|
||||
wire::{WaylandPayload, WireMsg, WireMsgBuilder, WlFixed},
|
||||
ObjectId,
|
||||
ObjectId, ObjectManager,
|
||||
};
|
||||
|
||||
///core global object
|
||||
@@ -18,7 +18,13 @@ use super::{
|
||||
pub mod wl_display {
|
||||
use super::*;
|
||||
|
||||
pub trait EvHandler {
|
||||
/// This is a special interface to make it possible to have a generic implementation for this
|
||||
/// interface
|
||||
pub trait HasObjman {
|
||||
fn objman(&mut self) -> &mut ObjectManager;
|
||||
}
|
||||
|
||||
pub trait EvHandler: HasObjman {
|
||||
///fatal error event
|
||||
///
|
||||
///The error event is sent out when a fatal (non-recoverable)
|
||||
@@ -36,7 +42,7 @@ pub mod wl_display {
|
||||
globals::WL_SHM => "wl_shm",
|
||||
globals::WP_VIEWPORTER => "wp_viewporter",
|
||||
globals::ZWLR_LAYER_SHELL_V1 => "zwlr_layer_shell_v1",
|
||||
other => match super::super::globals::object_type_get(other) {
|
||||
other => match self.objman().get(other) {
|
||||
Some(super::super::WlDynObj::Output) => "wl_output",
|
||||
Some(super::super::WlDynObj::Surface) => "wl_surface",
|
||||
Some(super::super::WlDynObj::Region) => "wl_region",
|
||||
|
||||
@@ -67,6 +67,7 @@ pub struct ObjectManager {
|
||||
objects: Vec<Option<WlDynObj>>,
|
||||
/// the next id we ought to generate
|
||||
next: u32,
|
||||
fractional_scale_support: bool,
|
||||
}
|
||||
|
||||
impl ObjectManager {
|
||||
@@ -77,6 +78,7 @@ impl ObjectManager {
|
||||
Self {
|
||||
objects: Vec::new(),
|
||||
next: 0,
|
||||
fractional_scale_support: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ impl ObjectManager {
|
||||
/// * 'None' if the object was already deleted
|
||||
#[must_use]
|
||||
pub fn get(&self, object_id: ObjectId) -> Option<WlDynObj> {
|
||||
let offset = Self::BASE_OFFSET + globals::fractional_scale_support() as u32;
|
||||
let offset = Self::BASE_OFFSET + self.fractional_scale_support as u32;
|
||||
let pos = object_id.get() - offset;
|
||||
self.objects[pos as usize]
|
||||
}
|
||||
@@ -95,7 +97,7 @@ impl ObjectManager {
|
||||
/// creates a new Id to use in requests
|
||||
#[must_use]
|
||||
pub fn create(&mut self, object: WlDynObj) -> ObjectId {
|
||||
let offset = Self::BASE_OFFSET + globals::fractional_scale_support() as u32;
|
||||
let offset = Self::BASE_OFFSET + self.fractional_scale_support as u32;
|
||||
if self.next as usize == self.objects.len() {
|
||||
self.next += 1;
|
||||
self.objects.push(Some(object));
|
||||
@@ -122,13 +124,21 @@ impl ObjectManager {
|
||||
/// Removing the same element twice currently works just fine and does not panic,
|
||||
/// but that may change in the future
|
||||
pub fn remove(&mut self, object_id: ObjectId) {
|
||||
let offset = Self::BASE_OFFSET + globals::fractional_scale_support() as u32;
|
||||
let offset = Self::BASE_OFFSET + self.fractional_scale_support as u32;
|
||||
let pos = object_id.get() - offset;
|
||||
self.objects[pos as usize] = None;
|
||||
if pos < self.next {
|
||||
self.next = pos;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_fractional_scale_support(&mut self, fractional_scale_support: bool) {
|
||||
self.fractional_scale_support = fractional_scale_support;
|
||||
}
|
||||
|
||||
pub fn fractional_scale_support(&self) -> bool {
|
||||
self.fractional_scale_support
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -263,7 +263,7 @@ pub unsafe fn send_unchecked(msg: &[u8], fds: &[BorrowedFd]) -> rustix::io::Resu
|
||||
net::sendmsg(wayland_fd(), &[iov], &mut control, net::SendFlags::NOSIGNAL).map(|_| ())
|
||||
}
|
||||
|
||||
impl<'a> WlSlice<'a> {
|
||||
impl WlSlice<'_> {
|
||||
#[must_use]
|
||||
pub const fn get(&self) -> &[u8] {
|
||||
self.0
|
||||
@@ -302,7 +302,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> WlStr<'a> {
|
||||
impl WlStr<'_> {
|
||||
#[must_use]
|
||||
pub const fn get(&self) -> &str {
|
||||
self.0
|
||||
@@ -381,7 +381,7 @@ impl From<&WlFixed> for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NewId<'a> {
|
||||
impl NewId<'_> {
|
||||
#[must_use]
|
||||
pub const fn id(&self) -> &ObjectId {
|
||||
&self.id
|
||||
|
||||
Reference in New Issue
Block a user