Skip to content
Merged
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
12 changes: 11 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ fn send_command(cmd: &str) -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

fn parse_mode(args: &[String]) -> &str {
let i = args.iter().position(|a| a == "--mode" || a == "-m");
match i.and_then(|i| args.get(i + 1)).map(|s| s.as_str()) {
Some("fit") => "fit",
Some("original") => "original",
_ => "cover",
}
}

fn parse_anchor(args: &[String]) -> (f32, f32) {
let i = args.iter().position(|a| a == "--anchor" || a == "-a");
let num = i
Expand Down Expand Up @@ -109,8 +118,9 @@ fn main() {
return;
}
}
let mode = parse_mode(&args);
let (anchor_h, anchor_v) = parse_anchor(&args);
let cmd = format!("set {} {} {}", args[2], anchor_h, anchor_v);
let cmd = format!("set{}\x01{}\x01{}\x01{}", mode, anchor_h, anchor_v, args[2]);
if let Err(e) = send_command(&cmd) {
eprintln!("Failed to set wallpaper {}. Is the daemon running?", e);
}
Expand Down
95 changes: 73 additions & 22 deletions src/vulkan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,50 @@ pub fn vulkan_pipeline(
}


// --------------------------------------------------------------------- / set mode

fn mode_set(
img_w: u32,
img_h: u32,
scr_w: u32,
scr_h: u32,
anchor_x: f32,
anchor_y: f32,
mode: &str,
) -> (u32, u32, u32, u32, i32, i32, u32, u32, bool) {

if mode == "fit" {
let scale = (scr_w as f64 / img_w as f64).min(scr_h as f64 / img_h as f64);
let sw = (img_w as f64 * scale) as u32;
let sh = (img_h as f64 * scale) as u32;
let dx = ((scr_w - sw) as f32 * anchor_x) as i32;
let dy = ((scr_h - sh) as f32 * anchor_y) as i32;
return (0, 0, img_w, img_h, dx, dy, sw, sh, true);
}
if mode == "original" {
if img_w <= scr_w && img_h <= scr_h {
let dx = ((scr_w - img_w) as f32 * anchor_x) as i32;
let dy = ((scr_h - img_h) as f32 * anchor_y) as i32;
return (0, 0, img_w, img_h, dx, dy, img_w, img_h, true);
}
}
let src_aspect = img_w as f64 / img_h as f64;
let dst_aspect = scr_w as f64 / scr_h as f64;
let (sx, sy, sw, sh) = if src_aspect > dst_aspect {
let new_w = (img_h as f64 * dst_aspect) as u32;
let max_x = (img_w - new_w) as f32;
let x = (max_x * anchor_x) as u32;
(x, 0, new_w, img_h)
} else {
let new_h = (img_w as f64 / dst_aspect) as u32;
let max_y = (img_h - new_h) as f32;
let y = (max_y * anchor_y) as u32;
(0, y, img_w, new_h)
};
(sx, sy, sw, sh, 0, 0, scr_w, scr_h, false)
}


// --------------------------------------------------------------------- / draw wallpaper

pub fn draw_wallpaper(
Expand All @@ -525,6 +569,7 @@ pub fn draw_wallpaper(
swapchain_extent_height: u32,
anchor_x: f32,
anchor_y: f32,
mode: &str,
) -> Result<(), Box<dyn std::error::Error>> {

// acquire swapchain image
Expand Down Expand Up @@ -596,22 +641,32 @@ pub fn draw_wallpaper(
);
}

// preserve aspect ratios and fill screen (anchored crop)
let src_aspect = texture_width as f64 / texture_height as f64;
let dst_aspect = swapchain_extent_width as f64 / swapchain_extent_height as f64;
let (src_x, src_y, src_w, src_h) = if src_aspect > dst_aspect {
// Image is wider → crop left/right, horizontal anchor controls which side is kept
let new_width = (texture_height as f64 * dst_aspect) as u32;
let max_x = (texture_width - new_width) as f32;
let x = (max_x * anchor_x) as u32;
(x, 0, new_width, texture_height)
} else {
// Image is taller → crop top/bottom, vertical anchor controls which part is kept
let new_height = (texture_width as f64 / dst_aspect) as u32;
let max_y = (texture_height - new_height) as f32;
let y = (max_y * anchor_y) as u32;
(0, y, texture_width, new_height)
};
// compute source and destination rectangles based on mode
let (src_x, src_y, src_w, src_h, dst_x, dst_y, dst_w, dst_h, needs_clear) = mode_set(
texture_width, texture_height,
swapchain_extent_width, swapchain_extent_height,
anchor_x, anchor_y,
mode,
);

// if the mode requires black bars, clear the image first
if needs_clear {
let clear_color = vk::ClearColorValue { float32: [0.0, 0.0, 0.0, 1.0] };
let clear_range = vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: 0, level_count: 1,
base_array_layer: 0, layer_count: 1,
};
unsafe {
device.cmd_clear_color_image(
command_buffer,
target_image,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&clear_color,
&[clear_range],
);
}
}

// record the blit command
let blit_region = vk::ImageBlit::default()
Expand Down Expand Up @@ -640,12 +695,8 @@ pub fn draw_wallpaper(
layer_count: 1,
})
.dst_offsets([
vk::Offset3D { x: 0, y: 0, z: 0 },
vk::Offset3D {
x: swapchain_extent_width as i32,
y: swapchain_extent_height as i32,
z: 1,
},
vk::Offset3D { x: dst_x, y: dst_y, z: 0 },
vk::Offset3D { x: dst_x + dst_w as i32, y: dst_y + dst_h as i32, z: 1 },
]);
unsafe {
device.cmd_blit_image(
Expand Down
17 changes: 11 additions & 6 deletions src/wallbashed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ fn set_wallpaper(
wallpaper: &mut Option<vulkan::VulkanTexture>,
anchor_x: f32,
anchor_y: f32,
mode: &str,
) -> Result<(), Box<dyn std::error::Error>> {

// load the wallpaper
Expand Down Expand Up @@ -109,6 +110,7 @@ fn set_wallpaper(
layer_height,
anchor_x,
anchor_y,
mode,
)?;

Ok(())
Expand Down Expand Up @@ -160,16 +162,17 @@ pub fn run(socket_path: &str) -> Result<(), Box<dyn std::error::Error>> {
if raw == "stop" {
println!("[wallbash] stopping daemon.");
running = false;
} else if raw.starts_with("set ") {
let args: Vec<&str> = raw[4..].trim().split_whitespace().collect();
let path = args[..args.len()-2].join(" ");
let anchor_x: f32 = args[args.len()-2].parse().unwrap_or(0.5);
let anchor_y: f32 = args[args.len()-1].parse().unwrap_or(0.5);
} else if raw.starts_with("set") {
let args: Vec<&str> = raw[3..].split('\x01').collect();
let mode = args[0].to_string();
let anchor_x: f32 = args[1].parse().unwrap_or(0.5);
let anchor_y: f32 = args[2].parse().unwrap_or(0.5);
let path = args[3..].join("\x01");
let resolved = std::fs::canonicalize(&path)
.map(|p| p.to_string_lossy().to_string())
.unwrap_or(path);

println!("[wallbash] loading {} (anchor {}/{})", resolved, anchor_x, anchor_y);
println!("[wallbash] loading '{}' ({}::{}x{})", resolved, mode, anchor_x, anchor_y);
match set_wallpaper(
&resolved,
&vk_core,
Expand All @@ -179,6 +182,7 @@ pub fn run(socket_path: &str) -> Result<(), Box<dyn std::error::Error>> {
&mut wallpaper,
anchor_x,
anchor_y,
&mode,
) {
Ok(()) => println!("[wallbash] wallpaper set."),
Err(e) if e.to_string().contains("out of date") => {
Expand Down Expand Up @@ -221,6 +225,7 @@ pub fn run(socket_path: &str) -> Result<(), Box<dyn std::error::Error>> {
&mut wallpaper,
anchor_x,
anchor_y,
&mode,
) {
eprintln!("[wallbash] error after swapchain recreation {}", e3);
}
Expand Down
Loading