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
70 changes: 58 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ image = "0.25"
wayland-client = "0.31.14"
wayland-protocols-wlr = { version = "0.3", features = ["client"] }
wayland-backend = { version = "0.3", features = ["client_system"] }

[build-dependencies]
shaderc = "0.8"
18 changes: 18 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::env;
use std::fs;
use std::path::Path;

fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
let path = Path::new("shaders").join("blur.comp");
let source = fs::read_to_string(&path).expect("Failed to read blur.comp");
let compiler = shaderc::Compiler::new().unwrap();
let mut options = shaderc::CompileOptions::new().unwrap();
options.set_optimization_level(shaderc::OptimizationLevel::Performance);
let result = compiler
.compile_into_spirv(&source, shaderc::ShaderKind::Compute, "blur.comp", "main", Some(&options))
.unwrap();
let out_name = Path::new(&out_dir).join("blur.comp.spv");
fs::write(out_name, result.as_binary_u8()).unwrap();
}

25 changes: 25 additions & 0 deletions shaders/blur.comp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#version 450
layout(local_size_x = 16, local_size_y = 16) in;
layout(binding = 0) uniform sampler2D srcImage;
layout(rgba8, binding = 1) uniform image2D dstImage;

void main() {
ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(dstImage);
if (gid.x >= size.x || gid.y >= size.y) return;

vec2 texelSize = 1.0 / vec2(size);
vec4 color = vec4(0.0);
int radius = 5;
int samples = 0;

for (int dx = -radius; dx <= radius; dx++) {
for (int dy = -radius; dy <= radius; dy++) {
vec2 offset = vec2(dx, dy) * texelSize;
color += texture(srcImage, (vec2(gid) + 0.5) / vec2(size) + offset);
samples++;
}
}
imageStore(dstImage, gid, color / float(samples));
}

99 changes: 52 additions & 47 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ fn print_usage() {
eprintln!(" wallbash status | Show daemon status");
}

fn send_command(cmd: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut stream = UnixStream::connect(SOCKET_PATH)?;
writeln!(stream, "{}", cmd)?;
Ok(())
}

fn check_daemon() -> bool {
UnixStream::connect(SOCKET_PATH).is_ok()
}
Expand All @@ -44,52 +50,56 @@ fn wait_loop() -> Result<(), Box<dyn std::error::Error>> {
Err("Waiting for daemon...".into())
}

fn send_command(cmd: &str) -> Result<(), Box<dyn std::error::Error>> {
let mut stream = UnixStream::connect(SOCKET_PATH)?;
writeln!(stream, "{}", cmd)?;
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_args(args: &[String]) -> (String, String, f32, f32) {

// wallpaper – mandatory
let wall = args.iter().position(|a| a == "--wall" || a == "-w")
.and_then(|i| args.get(i + 1).cloned())
.or_else(|| {
args.iter().skip(2).find(|a| !a.starts_with('-')).cloned()
})
.unwrap_or_else(|| {
eprintln!("Missing wallpaper (use --wall <path> or bare path)");
print_usage();
std::process::exit(1);
});

// mode – default "cover"
let mode = args.iter().position(|a| a == "--mode" || a == "-m")
.and_then(|i| args.get(i + 1))
.filter(|s| matches!(s.as_str(), "cover" | "fit" | "original"))
.map(|s| s.clone())
.unwrap_or_else(|| "cover".into());

fn parse_anchor(args: &[String]) -> (f32, f32) {
let i = args.iter().position(|a| a == "--anchor" || a == "-a");
let num = i
// anchor – default "center"
let anchor_num = args.iter().position(|a| a == "--anchor" || a == "-a")
.and_then(|i| args.get(i + 1))
.and_then(|val| val.parse::<u8>().ok());
match num {
Some(1) => (0.0, 0.0),
Some(2) => (0.5, 0.0),
Some(3) => (1.0, 0.0),
Some(4) => (0.0, 0.5),
Some(5) => (0.5, 0.5),
Some(6) => (1.0, 0.5),
Some(7) => (0.0, 1.0),
Some(8) => (0.5, 1.0),
Some(9) => (1.0, 1.0),
.and_then(|s| s.parse::<u8>().ok())
.filter(|&n| (1..10).contains(&n))
.unwrap_or(5);
let (ax, ay) = match anchor_num {
1 => (0.0, 0.0),
2 => (0.5, 0.0),
3 => (1.0, 0.0),
4 => (0.0, 0.5),
5 => (0.5, 0.5),
6 => (1.0, 0.5),
7 => (0.0, 1.0),
8 => (0.5, 1.0),
9 => (1.0, 1.0),
_ => (0.5, 0.5),
}
};

(wall, mode, ax, ay)
}


// --------------------------------------------------------------------- / main

fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
print_usage();
return;
}

match args[1].as_str() {
"start" => {
match args.get(1).map(|s| s.as_str()) {
Some("start") => {
if check_daemon() {
eprintln!("Daemon is already running.");
return;
Expand All @@ -98,11 +108,9 @@ fn main() {
eprintln!("Failed to start daemon {}", e);
}
}
"set" => {
if args.len() < 3 {
eprintln!("Missing image path.");
return;
}
Some("set") => {
let (wall, mode, ax, ay) = parse_args(&args);
let cmd = format!("set{}\x01{}\x01{}\x01{}", mode, ax, ay, wall);
if !check_daemon() {
println!("Starting daemon");
let log_file = std::fs::File::create(LOG_FILE).expect("Cannot create log");
Expand All @@ -118,26 +126,23 @@ fn main() {
return;
}
}
let mode = parse_mode(&args);
let (anchor_h, anchor_v) = parse_anchor(&args);
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);
}
}
"stop" => {
Some("stop") => {
if let Err(e) = send_command("stop") {
eprintln!("Failed to stop daemon {}. Is it running?", e);
}
}
"status" => {
Some("status") => {
if check_daemon() {
println!("Daemon is running.");
} else {
println!("Daemon is not running.");
}
}
_ => print_usage(),
_ => print_usage()
}
}

Loading
Loading