Skip to content

Commit

Permalink
feat(config): Add recursive config option
Browse files Browse the repository at this point in the history
Fixes #112.
  • Loading branch information
danyspin97 committed Feb 2, 2025
1 parent b0b7e66 commit acc5652
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 33 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 1.1.2
## New features
- Add a new `recursive` config option, enabled by default (fixes #112).

# 1.1.1
## New features
- Make jemalloc feature optional, enabled by default
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ represents a different display and can contain the following keys:
- `queue-size`, decide how big the queue should be when `path` is set a directory and `sorting` is
set to `random`. (_Optional_, `10` by default)
- `initial-transition`, enable the initial transition at wpaperd startup. (_Optional_, true by default)
- `recursive`, recursively iterate the directory `path` when looking for available wallpapers;
it is only valid when `path` points to a directory. (_Optional_, true by default)

The section `default` will be used as base for the all the display configuration; the section
`any` will be used for all the displays that are not explictly listed. This allows to have a
Expand Down
25 changes: 22 additions & 3 deletions daemon/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use smithay_client_toolkit::reexports::calloop::ping::Ping;
use crate::{
image_picker::ImagePicker,
render::Transition,
wallpaper_info::{BackgroundMode, Sorting, WallpaperInfo},
wallpaper_info::{BackgroundMode, Recursive, Sorting, WallpaperInfo},
};

#[derive(Default, Deserialize, PartialEq, Debug, Clone)]
Expand Down Expand Up @@ -59,6 +59,10 @@ pub struct SerializedWallpaperInfo {

/// Assign these displays to a group that shows the same wallpaper
pub group: Option<u8>,

/// Recursively traverse the directory set as path
/// Set as true by default
pub recursive: Option<bool>,
}

impl SerializedWallpaperInfo {
Expand Down Expand Up @@ -222,6 +226,13 @@ impl SerializedWallpaperInfo {
(None, None) => None,
};

let recursive = match (&self.recursive, &default.recursive) {
(Some(recursive), _) | (None, Some(recursive)) => {
Some(std::convert::Into::<Recursive>::into(*recursive))
}
(None, None) => None,
};

Ok(WallpaperInfo {
path,
duration,
Expand All @@ -233,6 +244,7 @@ impl SerializedWallpaperInfo {
initial_transition,
transition,
offset,
recursive,
})
}
}
Expand Down Expand Up @@ -370,11 +382,18 @@ impl Config {
Ok(())
}

pub fn paths(&self) -> Vec<PathBuf> {
pub fn paths(&self) -> Vec<(PathBuf, Recursive)> {
let mut paths: Vec<_> = self
.data
.values()
.filter_map(|info| info.path.as_ref().map(|p| p.to_path_buf()))
.filter_map(|info| {
info.path.as_ref().map(|p| {
(
p.to_path_buf(),
info.recursive.map(Recursive::from).unwrap_or_default(),
)
})
})
.collect();
paths.sort_unstable();
paths.dedup();
Expand Down
30 changes: 21 additions & 9 deletions daemon/src/filelist_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,36 @@ use log::error;
use smithay_client_toolkit::reexports::calloop::{self, ping::Ping, LoopHandle};
use walkdir::WalkDir;

use crate::wpaperd::Wpaperd;
use crate::{wallpaper_info::Recursive, wpaperd::Wpaperd};

#[derive(Debug)]
struct Filelist {
path: PathBuf,
recursive: Recursive,
filelist: Arc<Vec<PathBuf>>,
outdated: Arc<AtomicBool>,
}

impl Filelist {
fn new(path: &Path) -> Self {
fn new(path: &Path, recursive: Recursive) -> Self {
let mut res = Self {
path: path.to_path_buf(),
recursive,
filelist: Arc::new(Vec::new()),
outdated: Arc::new(AtomicBool::new(true)),
};
res.populate();
res
}

fn populate(&mut self) {
self.filelist = Arc::new(
WalkDir::new(&self.path)
.max_depth(if self.recursive == Recursive::Off {
1
} else {
usize::MAX
})
.follow_links(true)
.sort_by_file_name()
.into_iter()
Expand All @@ -58,7 +66,7 @@ pub struct FilelistCache {

impl FilelistCache {
pub fn new(
paths: Vec<PathBuf>,
paths: Vec<(PathBuf, Recursive)>,
hotwatch: &mut Hotwatch,
event_loop_handle: LoopHandle<Wpaperd>,
) -> Result<(Ping, Self)> {
Expand All @@ -76,11 +84,11 @@ impl FilelistCache {
Ok((ping, filelist_cache))
}

pub fn get(&self, path: &Path) -> Arc<Vec<PathBuf>> {
pub fn get(&self, path: &Path, recursive: Recursive) -> Arc<Vec<PathBuf>> {
debug_assert!(path.is_dir());
self.cache
.iter()
.find(|filelist| filelist.path == path)
.find(|filelist| filelist.path == path && filelist.recursive == recursive)
.expect("path passed to Filelist::get has been cached")
.filelist
.clone()
Expand All @@ -89,13 +97,17 @@ impl FilelistCache {
/// paths must be sorted
pub fn update_paths(
&mut self,
paths: Vec<PathBuf>,
paths: Vec<(PathBuf, Recursive)>,
hotwatch: &mut Hotwatch,
event_loop_ping: Ping,
) {
self.cache.retain(|filelist| {
let path_exists = filelist.path.exists();
if paths.contains(&filelist.path) && path_exists {
if paths
.iter()
.any(|(path, recursive)| &filelist.path == path && filelist.recursive == *recursive)
&& path_exists
{
true
} else {
// Stop watching paths that have been removed
Expand All @@ -112,13 +124,13 @@ impl FilelistCache {
}
});

for path in paths {
for (path, recursive) in paths {
if !self.cache.iter().any(|filelist| filelist.path == path) {
// Skip paths that don't exists and files
if !path.exists() || !path.is_dir() {
continue;
}
let filelist = Filelist::new(&path);
let filelist = Filelist::new(&path, recursive);
let outdated = filelist.outdated.clone();
self.cache.push(filelist);
let ping_clone = event_loop_ping.clone();
Expand Down
28 changes: 21 additions & 7 deletions daemon/src/image_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use smithay_client_toolkit::reexports::client::{protocol::wl_surface::WlSurface,
use crate::{
filelist_cache::FilelistCache,
wallpaper_groups::{WallpaperGroup, WallpaperGroups},
wallpaper_info::{Sorting, WallpaperInfo},
wallpaper_info::{Recursive, Sorting, WallpaperInfo},
wpaperd::Wpaperd,
};

Expand Down Expand Up @@ -185,7 +185,10 @@ impl ImagePickerSorting {
let files_len = filelist_cache
.clone()
.borrow()
.get(&wallpaper_info.path)
.get(
&wallpaper_info.path,
*wallpaper_info.recursive.as_ref().unwrap(),
)
.len();
Self::new_ascending(files_len)
}
Expand Down Expand Up @@ -339,9 +342,16 @@ impl ImagePicker {
}
}

pub fn get_image_from_path(&mut self, path: &Path) -> Option<(PathBuf, usize)> {
pub fn get_image_from_path(
&mut self,
path: &Path,
recursive: &Option<Recursive>,
) -> Option<(PathBuf, usize)> {
if path.is_dir() {
let files = self.filelist_cache.borrow().get(path);
let files = self
.filelist_cache
.borrow()
.get(path, recursive.unwrap_or_default());

// There are no images, forcefully break out of the loop
if files.is_empty() {
Expand Down Expand Up @@ -405,9 +415,9 @@ impl ImagePicker {
}

/// Update wallpaper by going up 1 index through the cached image paths
pub fn next_image(&mut self, path: &Path) {
pub fn next_image(&mut self, path: &Path, recursive: &Option<Recursive>) {
self.action = Some(ImagePickerAction::Next);
self.get_image_from_path(path);
self.get_image_from_path(path, recursive);
}

pub fn current_image(&self) -> PathBuf {
Expand All @@ -419,6 +429,7 @@ impl ImagePicker {
&mut self,
new_sorting: Option<Sorting>,
path: &Path,
recursive: Option<Recursive>,
path_changed: bool,
wl_surface: &WlSurface,
drawn_images_queue_size: usize,
Expand All @@ -433,7 +444,10 @@ impl ImagePicker {
if !path_changed => {}
(_, Sorting::Ascending) if path_changed => {
self.sorting = ImagePickerSorting::new_ascending(
self.filelist_cache.borrow().get(path).len(),
self.filelist_cache
.borrow()
.get(path, recursive.unwrap())
.len(),
);
}
(_, Sorting::Descending) if path_changed => {
Expand Down
7 changes: 4 additions & 3 deletions daemon/src/ipc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,10 @@ pub fn handle_message(

IpcMessage::NextWallpaper { monitors } => check_monitors(wpaperd, &monitors).map(|_| {
for surface in collect_surfaces(wpaperd, monitors) {
surface
.image_picker
.next_image(&surface.wallpaper_info.path);
surface.image_picker.next_image(
&surface.wallpaper_info.path,
&surface.wallpaper_info.recursive,
);
surface.queue_draw(&qh);
}

Expand Down
30 changes: 19 additions & 11 deletions daemon/src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,10 @@ impl Surface {
pub fn load_wallpaper(&mut self, handle: Option<&LoopHandle<Wpaperd>>) -> Result<bool> {
// If we were not already trying to load an image
if self.loading_image.is_none() {
if let Some(item) = self
.image_picker
.get_image_from_path(&self.wallpaper_info.path)
{
if let Some(item) = self.image_picker.get_image_from_path(
&self.wallpaper_info.path,
&self.wallpaper_info.recursive.clone(),
) {
if self.image_picker.current_image() == item.0 && !self.image_picker.is_reloading()
{
return Ok(true);
Expand Down Expand Up @@ -451,19 +451,23 @@ impl Surface {
// if the two paths are different and the new path is a directory but doesn't contain the
// old image
let path_changed = self.wallpaper_info.path != wallpaper_info.path
&& (!self.wallpaper_info.path.is_dir()
|| !wallpaper_info.path.starts_with(&self.wallpaper_info.path));
&& self.wallpaper_info.path.is_dir()
&& !wallpaper_info.path.starts_with(&self.wallpaper_info.path)
// and the recursive mode is different
&& wallpaper_info.recursive.as_ref().zip(self.wallpaper_info.recursive.as_ref()).map(|(x, y)| x != y).unwrap_or(false);
self.image_picker.update_sorting(
self.wallpaper_info.sorting,
&self.wallpaper_info.path,
self.wallpaper_info.recursive,
path_changed,
&self.wl_surface,
wallpaper_info.drawn_images_queue_size,
&wallpaper_groups,
);
if path_changed {
// ask the image_picker to pick a new a image
self.image_picker.next_image(&self.wallpaper_info.path);
self.image_picker
.next_image(&self.wallpaper_info.path, &self.wallpaper_info.recursive);
}
// Always queue draw to load changes (needed for GroupedRandom)
self.queue_draw(qh);
Expand Down Expand Up @@ -547,7 +551,10 @@ impl Surface {
let saturating_sub = new_duration.saturating_sub(time_passed);
if saturating_sub.is_zero() {
// The image was on screen for the same time as the new duration
self.image_picker.next_image(&self.wallpaper_info.path);
self.image_picker.next_image(
&self.wallpaper_info.path,
&self.wallpaper_info.recursive,
);
if let Err(err) = self.load_wallpaper(None) {
warn!("{err:?}");
}
Expand Down Expand Up @@ -656,9 +663,10 @@ impl Surface {
surface.renderer.transition_finished();
surface.renderer.force_transition_end();
}
surface
.image_picker
.next_image(&surface.wallpaper_info.path);
surface.image_picker.next_image(
&surface.wallpaper_info.path,
&surface.wallpaper_info.recursive,
);
surface.queue_draw(&qh);
surface.wallpaper_info.duration.unwrap()
};
Expand Down
21 changes: 21 additions & 0 deletions daemon/src/wallpaper_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ use serde::Deserialize;

use crate::{image_picker::ImagePicker, render::Transition};

#[derive(Debug, PartialEq, Default, Ord, Eq, PartialOrd, Clone, Copy)]
pub enum Recursive {
#[default]
On,
Off,
}

impl From<bool> for Recursive {
fn from(b: bool) -> Self {
if b {
Recursive::On
} else {
Recursive::Off
}
}
}

#[derive(PartialEq, Debug)]
pub struct WallpaperInfo {
pub path: PathBuf,
Expand All @@ -23,6 +40,9 @@ pub struct WallpaperInfo {
/// Determine the offset for the wallpaper to be drawn into the screen
/// Must be from 0.0 to 1.0, by default is 0.0 in tile mode and 0.5 in all the others
pub offset: Option<f32>,

/// Recursively iterate the directory set as path
pub recursive: Option<Recursive>,
}

impl Default for WallpaperInfo {
Expand All @@ -38,6 +58,7 @@ impl Default for WallpaperInfo {
initial_transition: true,
transition: Transition::Fade {},
offset: None,
recursive: None,
}
}
}
Expand Down

0 comments on commit acc5652

Please sign in to comment.