Skip to content

Commit

Permalink
Implement transitions between wallpapers
Browse files Browse the repository at this point in the history
  • Loading branch information
danyspin97 committed Feb 16, 2024
1 parent 3ff3051 commit ce4337e
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 77 deletions.
2 changes: 1 addition & 1 deletion daemon/src/image_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub struct ImagePicker {
impl ImagePicker {
pub fn new(wallpaper_info: Arc<WallpaperInfo>) -> Self {
Self {
current_img: PathBuf::new(),
current_img: PathBuf::from("/tmp/new.png"),
image_changed_instant: Instant::now(),
action: Some(ImagePickerAction::Next),
sorting: match wallpaper_info.sorting {
Expand Down
46 changes: 17 additions & 29 deletions daemon/src/ipc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,19 @@ use color_eyre::eyre::Context;
use color_eyre::Result;
use log::error;
use smithay_client_toolkit::reexports::calloop::LoopHandle;
use smithay_client_toolkit::reexports::client::QueueHandle;
use wpaperd_ipc::{IpcError, IpcMessage, IpcResponse};

use crate::socket::SocketSource;
use crate::surface::Surface;
use crate::Wpaperd;

/// Create an IPC socket.
pub fn spawn_ipc_socket(event_loop: &LoopHandle<Wpaperd>, socket_path: &Path) -> Result<()> {
pub fn spawn_ipc_socket(
socket_path: &Path,
event_loop: &LoopHandle<Wpaperd>,
qh: QueueHandle<Wpaperd>,
) -> Result<()> {
// Try to delete the socket if it exists already.
if socket_path.exists() {
fs::remove_file(socket_path)?;
Expand All @@ -31,7 +36,7 @@ pub fn spawn_ipc_socket(event_loop: &LoopHandle<Wpaperd>, socket_path: &Path) ->
// Add source to calloop loop.
let mut message_buffer = String::new();
event_loop.insert_source(socket, move |stream, _, wpaperd| {
if let Err(err) = handle_message(&mut message_buffer, stream, wpaperd) {
if let Err(err) = handle_message(&mut message_buffer, stream, qh.clone(), wpaperd) {
error!("{}", err);
}
})?;
Expand Down Expand Up @@ -69,7 +74,12 @@ fn collect_surfaces(wpaperd: &mut Wpaperd, monitors: Vec<String>) -> Vec<&mut Su
}

/// Handle IPC socket messages.
fn handle_message(buffer: &mut String, ustream: UnixStream, wpaperd: &mut Wpaperd) -> Result<()> {
fn handle_message(
buffer: &mut String,
ustream: UnixStream,
qh: QueueHandle<Wpaperd>,
wpaperd: &mut Wpaperd,
) -> Result<()> {
buffer.clear();

// Read new content to buffer.
Expand Down Expand Up @@ -110,45 +120,23 @@ fn handle_message(buffer: &mut String, ustream: UnixStream, wpaperd: &mut Wpaper

IpcMessage::PreviousWallpaper { monitors } => {
check_monitors(wpaperd, &monitors).and_then(|_| {
let mut errors = Vec::new();
for surface in collect_surfaces(wpaperd, monitors) {
surface.image_picker.previous_image();
match surface.draw() {
Ok(_) => {}
Err(err) => {
log::error!("Error drawing surface: {}", err);
errors.push((surface.name().to_string(), err.to_string()))
}
}
surface.queue_draw(&qh);
}

if errors.is_empty() {
Ok(IpcResponse::Ok)
} else {
Err(IpcError::DrawErrors(errors))
}
Ok(IpcResponse::Ok)
})
}

IpcMessage::NextWallpaper { monitors } => {
check_monitors(wpaperd, &monitors).and_then(|_| {
let mut errors = Vec::new();
for surface in collect_surfaces(wpaperd, monitors) {
surface.image_picker.next_image();
match surface.draw() {
Ok(_) => {}
Err(err) => {
log::error!("Error drawing surface: {}", err);
errors.push((surface.name().to_string(), err.to_string()))
}
}
surface.queue_draw(&qh);
}

if errors.is_empty() {
Ok(IpcResponse::Ok)
} else {
Err(IpcError::DrawErrors(errors))
}
Ok(IpcResponse::Ok)
})
}

Expand Down
11 changes: 6 additions & 5 deletions daemon/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ fn run(config: Config, xdg_dirs: BaseDirectories) -> Result<()> {
// loop we will always receive timeout events and create
// them when that happens
if surface.is_configured() {
surface.add_timer(event_loop.handle(), None);
surface.add_timer(None, event_loop.handle(), qh.clone());
surface.draw(&qh, 0);
true
} else {
false
Expand All @@ -117,7 +118,7 @@ fn run(config: Config, xdg_dirs: BaseDirectories) -> Result<()> {
.context("dispatching the event loop")?;
}

ipc_server::spawn_ipc_socket(&event_loop.handle(), &socket_path()?).unwrap();
ipc_server::spawn_ipc_socket(&socket_path()?, &event_loop.handle(), qh.clone()).unwrap();
if let Some(notify) = config.notify {
let mut f = unsafe { File::from_raw_fd(notify as i32) };
if let Err(err) = writeln!(f) {
Expand All @@ -128,10 +129,10 @@ fn run(config: Config, xdg_dirs: BaseDirectories) -> Result<()> {
loop {
let mut wallpaper_config = wallpaper_config.lock().unwrap();
if wallpaper_config.reloaded {
wpaperd.surfaces.iter_mut().for_each(|surface| {
for surface in &mut wpaperd.surfaces {
let wallpaper_info = wallpaper_config.get_output_by_name(surface.name());
surface.update_wallpaper_info(event_loop.handle(), wallpaper_info);
});
surface.update_wallpaper_info(event_loop.handle(), &qh, wallpaper_info);
}
wallpaper_config.reloaded = false;
}
drop(wallpaper_config);
Expand Down
97 changes: 75 additions & 22 deletions daemon/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ pub struct Renderer {
vao: gl::types::GLuint,
vbo: gl::types::GLuint,
gl: gl::Gl,
// reverse: false
// old gl texture0
// new gl texture1
// reverse: true
// new gl texture0
// old texture1
reverse: bool,
// milliseconds time for the animation
animation_time: u32,
pub time_started: u32,
}

// Macro that check the error code of the last OpenGL call and returns a Result.
Expand All @@ -32,14 +42,17 @@ macro_rules! gl_check {
let error = $gl.GetError();
if error != gl::NO_ERROR {
let error_string = $gl.GetString(error);
if error_string.is_null() {
bail!("OpenGL error when {}: {}", $desc, error);
} else {
let error_string = CStr::from_ptr(error_string as _)
.to_string_lossy()
.into_owned();
bail!("OpenGL error when {}: {} ({})", $desc, error, error_string);
}
ensure!(
!error_string.is_null(),
"OpenGL error when {}: {}",
$desc,
error
);

let error_string = CStr::from_ptr(error_string as _)
.to_string_lossy()
.into_owned();
bail!("OpenGL error when {}: {} ({})", $desc, error, error_string);
}
}};
}
Expand Down Expand Up @@ -143,7 +156,7 @@ impl EglContext {
}

impl Renderer {
pub unsafe fn new() -> Result<Self> {
pub unsafe fn new(image: DynamicImage) -> Result<Self> {
let gl = gl::Gl::load_with(|name| {
egl.get_proc_address(name).unwrap() as *const std::ffi::c_void
});
Expand Down Expand Up @@ -221,12 +234,19 @@ impl Renderer {
gl.BindBuffer(gl::ARRAY_BUFFER, vbo);
gl_check!(gl, "binding the buffer");

Ok(Self {
let mut renderer = Self {
program,
vao,
vbo,
gl,
})
reverse: true,
time_started: 0,
animation_time: 3000,
};

renderer.load_texture(image)?;

Ok(renderer)
}

pub fn check_error(&self, msg: &str) -> Result<()> {
Expand All @@ -236,19 +256,35 @@ impl Renderer {
Ok(())
}

pub unsafe fn draw(&self) -> Result<()> {
pub unsafe fn draw(&self, time: u32) -> Result<()> {
let elapsed = time - self.time_started;
let mut progress = (elapsed as f32 / self.animation_time as f32).min(1.0);
if self.reverse {
progress = 1.0 - progress;
}

let loc = self
.gl
.GetUniformLocation(self.program, b"u_progress\0".as_ptr() as *const _);
self.check_error("getting the uniform location")?;
self.gl.Uniform1f(loc, progress);
self.check_error("calling Uniform1i")?;
self.gl.DrawArrays(gl::TRIANGLES, 0, 6);
self.check_error("drawing the triangles")?;

Ok(())
}

pub fn load_texture(&self, image: DynamicImage) -> Result<()> {
pub fn load_texture(&mut self, image: DynamicImage) -> Result<()> {
let mut texture = 0;
Ok(unsafe {
self.gl.GenTextures(1, &mut texture);
self.check_error("generating textures")?;
self.gl.ActiveTexture(gl::TEXTURE0);
self.gl.ActiveTexture(if self.reverse {
gl::TEXTURE0
} else {
gl::TEXTURE1
});
self.check_error("activating textures")?;
self.gl.BindTexture(gl::TEXTURE_2D, texture);
self.check_error("binding textures")?;
Expand All @@ -266,21 +302,30 @@ impl Renderer {
self.check_error("defining the texture")?;
self.gl.GenerateMipmap(gl::TEXTURE_2D);
self.check_error("generating the mipmap")?;
let loc = self
.gl
.GetUniformLocation(self.program, b"u_texture\0".as_ptr() as *const _);
self.check_error("getting the uniform location")?;
self.gl.Uniform1i(loc, 0);
self.check_error("calling Uniform1i")?;
self.gl
.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
self.check_error("defining the texture min filter")?;
self.gl
.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
self.check_error("defining the texture mag filter")?;
// We assume that the we still have an active texture
if self.reverse {
self.gl.Uniform1i(0, 0);
} else {
self.gl.Uniform1i(1, 1);
}
self.reverse = !self.reverse;
})
}

pub fn start_animation(&mut self, time: u32) {
self.time_started = time;
}

pub fn assign_textures(&mut self) -> Result<()> {
Ok(())
}

pub fn clear_after_draw(&self) -> Result<()> {
unsafe {
// Unbind the framebuffer and renderbuffer before deleting.
Expand All @@ -301,6 +346,10 @@ impl Renderer {
self.check_error("resizing the viewport")
}
}

pub(crate) fn is_drawing_animation(&self, time: u32) -> bool {
time < (self.time_started + self.animation_time)
}
}

impl Deref for Renderer {
Expand Down Expand Up @@ -393,9 +442,13 @@ out vec4 FragColor;
in vec2 v_texcoord;
uniform sampler2D u_texture;
layout(location = 0) uniform sampler2D u_texture0;
layout(location = 1) uniform sampler2D u_texture1;
layout(location = 2) uniform float u_progress;
void main() {
FragColor = texture(u_texture, v_texcoord);
FragColor = mix(texture(u_texture1, v_texcoord), texture(u_texture0, v_texcoord), u_progress);
}
\0";
Loading

0 comments on commit ce4337e

Please sign in to comment.