diff options
| author | Petri Hienonen <petri.hienonen@gmail.com> | 2025-10-18 19:32:34 +0300 |
|---|---|---|
| committer | Petri Hienonen <petri.hienonen@gmail.com> | 2025-10-18 19:32:34 +0300 |
| commit | 2fb4913277734dccab54479e5b65c6031de6e9ab (patch) | |
| tree | 1b497f1156f7a2d568f60723e0e22d979f07ef72 /src/main.rs | |
| parent | 60505314d8bc86b33ba84bdfccdb87bf5dd7f9af (diff) | |
| download | wallpaper-2fb4913277734dccab54479e5b65c6031de6e9ab.tar.zst | |
Use tabs
Diffstat (limited to '')
| -rw-r--r-- | src/main.rs | 710 |
1 files changed, 355 insertions, 355 deletions
diff --git a/src/main.rs b/src/main.rs index 64dfdba..5509e47 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,373 +6,373 @@ use std::mem; use std::time::Instant; use wgpu::util::DeviceExt; use winit::{ - application::ApplicationHandler, - event::WindowEvent, - event_loop::{ActiveEventLoop, EventLoop}, - window::{Window, WindowAttributes, WindowId}, + application::ApplicationHandler, + event::WindowEvent, + event_loop::{ActiveEventLoop, EventLoop}, + window::{Window, WindowAttributes, WindowId}, }; #[repr(C)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] struct Uniforms { - i_resolution: [f32; 3], - i_time: f32, - i_mouse: [f32; 4], + i_resolution: [f32; 3], + i_time: f32, + i_mouse: [f32; 4], } struct WallpaperApp { - window: Option<Window>, - surface: Option<wgpu::Surface<'static>>, - device: Option<wgpu::Device>, - queue: Option<wgpu::Queue>, - config: Option<wgpu::SurfaceConfiguration>, - render_pipeline: Option<wgpu::RenderPipeline>, - uniform_buffer: Option<wgpu::Buffer>, - bind_group: Option<wgpu::BindGroup>, - start_time: Instant, - shader_path: String, - hyprland_config: wayland::HyprlandConfig, - wayland_configured: bool, + window: Option<Window>, + surface: Option<wgpu::Surface<'static>>, + device: Option<wgpu::Device>, + queue: Option<wgpu::Queue>, + config: Option<wgpu::SurfaceConfiguration>, + render_pipeline: Option<wgpu::RenderPipeline>, + uniform_buffer: Option<wgpu::Buffer>, + bind_group: Option<wgpu::BindGroup>, + start_time: Instant, + shader_path: String, + hyprland_config: wayland::HyprlandConfig, + wayland_configured: bool, } impl WallpaperApp { - fn new(shader_path: String) -> Self { - Self { - window: None, - surface: None, - device: None, - queue: None, - config: None, - render_pipeline: None, - uniform_buffer: None, - bind_group: None, - start_time: Instant::now(), - shader_path, - hyprland_config: wayland::HyprlandConfig::default(), - wayland_configured: false, - } - } - fn init_graphics(&mut self) -> Result<()> { - let window = self - .window - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Window not initialized"))?; - let size = window.inner_size(); - let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor { - memory_budget_thresholds: wgpu::MemoryBudgetThresholds { - for_resource_creation: Some(200), - for_device_loss: Some(100), - }, - backends: wgpu::Backends::VULKAN, - backend_options: wgpu::BackendOptions { - gl: wgpu::GlBackendOptions::default(), - dx12: wgpu::Dx12BackendOptions::default(), - noop: wgpu::NoopBackendOptions::default(), - }, - flags: wgpu::InstanceFlags::empty(), - }); - // Create surface - let surface = instance - .create_surface(window) - .map_err(|e| anyhow::anyhow!("Failed to create surface: {}", e))?; - let surface = - unsafe { mem::transmute::<wgpu::Surface<'_>, wgpu::Surface<'static>>(surface) }; - let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::HighPerformance, - compatible_surface: Some(&surface), - force_fallback_adapter: false, - })) - .unwrap(); - let (device, queue) = - pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor { - required_features: wgpu::Features::empty(), - required_limits: wgpu::Limits::default(), - memory_hints: wgpu::MemoryHints::Performance, - label: None, - experimental_features: wgpu::ExperimentalFeatures::disabled(), - trace: wgpu::Trace::Off, - }))?; - let surface_caps = surface.get_capabilities(&adapter); - let surface_format = surface_caps - .formats - .iter() - .copied() - .find(|f| f.is_srgb()) - .unwrap_or(surface_caps.formats[0]); - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: surface_format, - width: size.width, - height: size.height, - present_mode: surface_caps.present_modes[0], - alpha_mode: surface_caps.alpha_modes[0], - view_formats: vec![], - desired_maximum_frame_latency: 2, - }; - surface.configure(&device, &config); - // Load and compile shader - let shader_source = std::fs::read_to_string(&self.shader_path).map_err(|e| { - anyhow::anyhow!("Failed to read shader file {}: {}", &self.shader_path, e) - })?; - let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some("Wallpaper Shader"), - source: wgpu::ShaderSource::Wgsl(shader_source.as_str().into()), - }); - // Create uniform buffer - let uniforms = Uniforms { - i_resolution: [size.width as f32, size.height as f32, 0.0], - i_time: 0.0, - i_mouse: [0.0, 0.0, 0.0, 0.0], - }; - let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Uniform Buffer"), - contents: bytemuck::cast_slice(&[uniforms]), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - }); - let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - label: Some("uniform_bind_group_layout"), - }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: uniform_buffer.as_entire_binding(), - }], - label: Some("uniform_bind_group"), - }); - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Render Pipeline Layout"), - bind_group_layouts: &[&bind_group_layout], - push_constant_ranges: &[], - }); - let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Render Pipeline"), - layout: Some(&pipeline_layout), - vertex: wgpu::VertexState { - module: &shader_module, - entry_point: Some("vs_main"), - compilation_options: wgpu::PipelineCompilationOptions::default(), - buffers: &[], - }, - fragment: Some(wgpu::FragmentState { - module: &shader_module, - entry_point: Some("fs_main"), - compilation_options: wgpu::PipelineCompilationOptions::default(), - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState::REPLACE), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: Some(wgpu::Face::Back), - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - cache: None, - }); - self.surface = Some(surface); - self.device = Some(device); - self.queue = Some(queue); - self.config = Some(config); - self.render_pipeline = Some(render_pipeline); - self.uniform_buffer = Some(uniform_buffer); - self.bind_group = Some(bind_group); - Ok(()) - } - fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { - if new_size.width > 0 - && new_size.height > 0 - && let (Some(surface), Some(device), Some(config)) = - (&self.surface, &self.device, &mut self.config) - { - config.width = new_size.width; - config.height = new_size.height; - surface.configure(device, config); - } - } - fn render(&mut self) -> Result<()> { - let surface = self - .surface - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Surface not initialized"))?; - let device = self - .device - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Device not initialized"))?; - let queue = self - .queue - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Queue not initialized"))?; - let render_pipeline = self - .render_pipeline - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Render pipeline not initialized"))?; - let uniform_buffer = self - .uniform_buffer - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Uniform buffer not initialized"))?; - let bind_group = self - .bind_group - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Bind group not initialized"))?; - let config = self - .config - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Config not initialized"))?; - let frame = surface.get_current_texture()?; - let view = frame - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - // Update uniforms - let uniforms = Uniforms { - i_resolution: [config.width as f32, config.height as f32, 0.0], - i_time: self.start_time.elapsed().as_secs_f32(), - i_mouse: [0.0, 0.0, 0.0, 0.0], - }; - queue.write_buffer(uniform_buffer, 0, bytemuck::cast_slice(&[uniforms])); - let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Render Encoder"), - }); - { - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - depth_slice: None, - view: &view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: None, - occlusion_query_set: None, - timestamp_writes: None, - }); - render_pass.set_pipeline(render_pipeline); - render_pass.set_bind_group(0, bind_group, &[]); - render_pass.draw(0..3, 0..1); - } - queue.submit(std::iter::once(encoder.finish())); - frame.present(); - Ok(()) - } + fn new(shader_path: String) -> Self { + Self { + window: None, + surface: None, + device: None, + queue: None, + config: None, + render_pipeline: None, + uniform_buffer: None, + bind_group: None, + start_time: Instant::now(), + shader_path, + hyprland_config: wayland::HyprlandConfig::default(), + wayland_configured: false, + } + } + fn init_graphics(&mut self) -> Result<()> { + let window = self + .window + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Window not initialized"))?; + let size = window.inner_size(); + let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor { + memory_budget_thresholds: wgpu::MemoryBudgetThresholds { + for_resource_creation: Some(200), + for_device_loss: Some(100), + }, + backends: wgpu::Backends::VULKAN, + backend_options: wgpu::BackendOptions { + gl: wgpu::GlBackendOptions::default(), + dx12: wgpu::Dx12BackendOptions::default(), + noop: wgpu::NoopBackendOptions::default(), + }, + flags: wgpu::InstanceFlags::empty(), + }); + // Create surface + let surface = instance + .create_surface(window) + .map_err(|e| anyhow::anyhow!("Failed to create surface: {}", e))?; + let surface = + unsafe { mem::transmute::<wgpu::Surface<'_>, wgpu::Surface<'static>>(surface) }; + let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(&surface), + force_fallback_adapter: false, + })) + .unwrap(); + let (device, queue) = + pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor { + required_features: wgpu::Features::empty(), + required_limits: wgpu::Limits::default(), + memory_hints: wgpu::MemoryHints::Performance, + label: None, + experimental_features: wgpu::ExperimentalFeatures::disabled(), + trace: wgpu::Trace::Off, + }))?; + let surface_caps = surface.get_capabilities(&adapter); + let surface_format = surface_caps + .formats + .iter() + .copied() + .find(|f| f.is_srgb()) + .unwrap_or(surface_caps.formats[0]); + let config = wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: surface_format, + width: size.width, + height: size.height, + present_mode: surface_caps.present_modes[0], + alpha_mode: surface_caps.alpha_modes[0], + view_formats: vec![], + desired_maximum_frame_latency: 2, + }; + surface.configure(&device, &config); + // Load and compile shader + let shader_source = std::fs::read_to_string(&self.shader_path).map_err(|e| { + anyhow::anyhow!("Failed to read shader file {}: {}", &self.shader_path, e) + })?; + let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some("Wallpaper Shader"), + source: wgpu::ShaderSource::Wgsl(shader_source.as_str().into()), + }); + // Create uniform buffer + let uniforms = Uniforms { + i_resolution: [size.width as f32, size.height as f32, 0.0], + i_time: 0.0, + i_mouse: [0.0, 0.0, 0.0, 0.0], + }; + let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Uniform Buffer"), + contents: bytemuck::cast_slice(&[uniforms]), + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + }); + let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: Some("uniform_bind_group_layout"), + }); + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: uniform_buffer.as_entire_binding(), + }], + label: Some("uniform_bind_group"), + }); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("Render Pipeline Layout"), + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }); + let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: &shader_module, + entry_point: Some("vs_main"), + compilation_options: wgpu::PipelineCompilationOptions::default(), + buffers: &[], + }, + fragment: Some(wgpu::FragmentState { + module: &shader_module, + entry_point: Some("fs_main"), + compilation_options: wgpu::PipelineCompilationOptions::default(), + targets: &[Some(wgpu::ColorTargetState { + format: config.format, + blend: Some(wgpu::BlendState::REPLACE), + write_mask: wgpu::ColorWrites::ALL, + })], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: None, + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + cache: None, + }); + self.surface = Some(surface); + self.device = Some(device); + self.queue = Some(queue); + self.config = Some(config); + self.render_pipeline = Some(render_pipeline); + self.uniform_buffer = Some(uniform_buffer); + self.bind_group = Some(bind_group); + Ok(()) + } + fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) { + if new_size.width > 0 + && new_size.height > 0 + && let (Some(surface), Some(device), Some(config)) = + (&self.surface, &self.device, &mut self.config) + { + config.width = new_size.width; + config.height = new_size.height; + surface.configure(device, config); + } + } + fn render(&mut self) -> Result<()> { + let surface = self + .surface + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Surface not initialized"))?; + let device = self + .device + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Device not initialized"))?; + let queue = self + .queue + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Queue not initialized"))?; + let render_pipeline = self + .render_pipeline + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Render pipeline not initialized"))?; + let uniform_buffer = self + .uniform_buffer + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Uniform buffer not initialized"))?; + let bind_group = self + .bind_group + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Bind group not initialized"))?; + let config = self + .config + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Config not initialized"))?; + let frame = surface.get_current_texture()?; + let view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + // Update uniforms + let uniforms = Uniforms { + i_resolution: [config.width as f32, config.height as f32, 0.0], + i_time: self.start_time.elapsed().as_secs_f32(), + i_mouse: [0.0, 0.0, 0.0, 0.0], + }; + queue.write_buffer(uniform_buffer, 0, bytemuck::cast_slice(&[uniforms])); + let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encoder"), + }); + { + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + depth_slice: None, + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + occlusion_query_set: None, + timestamp_writes: None, + }); + render_pass.set_pipeline(render_pipeline); + render_pass.set_bind_group(0, bind_group, &[]); + render_pass.draw(0..3, 0..1); + } + queue.submit(std::iter::once(encoder.finish())); + frame.present(); + Ok(()) + } } impl ApplicationHandler for WallpaperApp { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { - if self.window.is_none() { - let window_attributes = WindowAttributes::default() - .with_title("Hyprland Live Wallpaper") - .with_transparent(true) - .with_decorations(false) - .with_fullscreen(Some(winit::window::Fullscreen::Borderless(None))); - let window = match event_loop.create_window(window_attributes) { - Ok(window) => window, - Err(e) => { - error!("Failed to create window: {}", e); - return; - } - }; - // Configure window for Hyprland - if let Err(e) = wayland::configure_hyprland_window(&window, &self.hyprland_config) { - warn!("Failed to configure Hyprland window: {}", e); - } - // Store window first, then initialize graphics - self.window = Some(window); - match self.init_graphics() { - Ok(()) => { - info!("Wallpaper service running"); - } - Err(e) => { - error!("Failed to initialize graphics: {}", e); - } - } - } - } - fn window_event( - &mut self, - event_loop: &ActiveEventLoop, - _window_id: WindowId, - event: WindowEvent, - ) { - match event { - WindowEvent::CloseRequested => { - event_loop.exit(); - } - WindowEvent::Resized(size) => { - self.resize(size); - } - WindowEvent::RedrawRequested => { - // Apply Hyprland rules on first redraw (after window is mapped) - if !self.wayland_configured - && let Some(window) = &self.window - { - // Convert window ID to u64 for hyprctl - let window_id: u64 = window.id().into(); - if let Err(e) = wayland::apply_hyprland_rules(window_id, &self.hyprland_config) - { - warn!("Failed to apply Hyprland rules: {}", e); - } - self.wayland_configured = true; - } - if let Err(e) = self.render() { - error!("Render error: {}", e); - event_loop.exit(); - } - } - _ => {} - } - } - fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { - if let Some(window) = &self.window { - window.request_redraw(); - } - } + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + if self.window.is_none() { + let window_attributes = WindowAttributes::default() + .with_title("Hyprland Live Wallpaper") + .with_transparent(true) + .with_decorations(false) + .with_fullscreen(Some(winit::window::Fullscreen::Borderless(None))); + let window = match event_loop.create_window(window_attributes) { + Ok(window) => window, + Err(e) => { + error!("Failed to create window: {}", e); + return; + } + }; + // Configure window for Hyprland + if let Err(e) = wayland::configure_hyprland_window(&window, &self.hyprland_config) { + warn!("Failed to configure Hyprland window: {}", e); + } + // Store window first, then initialize graphics + self.window = Some(window); + match self.init_graphics() { + Ok(()) => { + info!("Wallpaper service running"); + } + Err(e) => { + error!("Failed to initialize graphics: {}", e); + } + } + } + } + fn window_event( + &mut self, + event_loop: &ActiveEventLoop, + _window_id: WindowId, + event: WindowEvent, + ) { + match event { + WindowEvent::CloseRequested => { + event_loop.exit(); + } + WindowEvent::Resized(size) => { + self.resize(size); + } + WindowEvent::RedrawRequested => { + // Apply Hyprland rules on first redraw (after window is mapped) + if !self.wayland_configured + && let Some(window) = &self.window + { + // Convert window ID to u64 for hyprctl + let window_id: u64 = window.id().into(); + if let Err(e) = wayland::apply_hyprland_rules(window_id, &self.hyprland_config) + { + warn!("Failed to apply Hyprland rules: {}", e); + } + self.wayland_configured = true; + } + if let Err(e) = self.render() { + error!("Render error: {}", e); + event_loop.exit(); + } + } + _ => {} + } + } + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { + if let Some(window) = &self.window { + window.request_redraw(); + } + } } fn main() -> Result<()> { - env_logger::init(); - let matches = Command::new("hyprland-live-wallpaper") - .version("0.1.0") - .about("Live wallpaper service for Hyprland using wgpu") - .arg( - Arg::new("shader") - .short('s') - .long("shader") - .value_name("FILE") - .help("Path to WGSL shader file"), - ) - .get_matches(); - info!("Starting Hyprland Live Wallpaper"); - let shader_path = matches - .get_one::<String>("shader") - .map(|s| s.as_str()) - .unwrap_or("shaders/red.wgsl") - .to_string(); - run_wallpaper(shader_path)?; - Ok(()) + env_logger::init(); + let matches = Command::new("hyprland-live-wallpaper") + .version("0.1.0") + .about("Live wallpaper service for Hyprland using wgpu") + .arg( + Arg::new("shader") + .short('s') + .long("shader") + .value_name("FILE") + .help("Path to WGSL shader file"), + ) + .get_matches(); + info!("Starting Hyprland Live Wallpaper"); + let shader_path = matches + .get_one::<String>("shader") + .map(|s| s.as_str()) + .unwrap_or("shaders/red.wgsl") + .to_string(); + run_wallpaper(shader_path)?; + Ok(()) } fn run_wallpaper(shader_path: String) -> Result<()> { - let event_loop = EventLoop::new()?; - let mut app = WallpaperApp::new(shader_path); - event_loop.run_app(&mut app)?; - Ok(()) + let event_loop = EventLoop::new()?; + let mut app = WallpaperApp::new(shader_path); + event_loop.run_app(&mut app)?; + Ok(()) } |
