mirror of
				https://github.com/lelgenio/wl-crosshair.git
				synced 2025-10-31 00:00:16 -03:00 
			
		
		
		
	Add support for loading any image, add some default cursors
This commit is contained in:
		
							parent
							
								
									081f6bed69
								
							
						
					
					
						commit
						d642e72c48
					
				
					 8 changed files with 1009 additions and 48 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,2 +1,3 @@ | |||
| /target | ||||
| .direnv/ | ||||
| cursors/*~ | ||||
|  |  | |||
							
								
								
									
										944
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										944
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -10,3 +10,4 @@ wayland-protocols-wlr = { version = "0.1.0", features = ["client"] } | |||
| 
 | ||||
| log = { version = "0.4", optional = true } | ||||
| tempfile = "3.2" | ||||
| image = "0.25.1" | ||||
|  |  | |||
							
								
								
									
										
											BIN
										
									
								
								cursors/inverse-v.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cursors/inverse-v.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 8.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								cursors/test-colors.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cursors/test-colors.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 5.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								cursors/wojak-cursor.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cursors/wojak-cursor.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 204 KiB | 
|  | @ -19,6 +19,13 @@ | |||
|             version = "0.1.0"; | ||||
|             src = ./.; | ||||
|             cargoLock.lockFile = ./Cargo.lock; | ||||
|             nativeBuildInputs = with pkgs; [ makeWrapper ]; | ||||
|             postInstall = '' | ||||
|               mkdir -p $out/share | ||||
|               cp -rv ${./cursors} $out/share/cursors | ||||
|               wrapProgram $out/bin/* \ | ||||
|                 --set WL_CROSSHAIR_IMAGE_PATH $out/share/cursors/inverse-v.png | ||||
|             ''; | ||||
|           }; | ||||
|         }; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										104
									
								
								src/main.rs
									
										
									
									
									
								
							
							
						
						
									
										104
									
								
								src/main.rs
									
										
									
									
									
								
							|  | @ -1,8 +1,10 @@ | |||
| use std::{fs::File, io::Write, os::unix::prelude::AsRawFd}; | ||||
| 
 | ||||
| use image::{GenericImageView, Pixel}; | ||||
| use wayland_client::{ | ||||
|     protocol::{ | ||||
|         wl_buffer, wl_compositor, wl_keyboard, wl_region::WlRegion, wl_registry, wl_seat, wl_shm, wl_shm_pool, wl_surface | ||||
|         wl_buffer, wl_compositor, wl_keyboard, wl_region::WlRegion, wl_registry, wl_seat, wl_shm, | ||||
|         wl_shm_pool, wl_surface, | ||||
|     }, | ||||
|     Connection, Dispatch, Proxy, QueueHandle, | ||||
| }; | ||||
|  | @ -17,7 +19,9 @@ use wayland_protocols::xdg::shell::client::xdg_wm_base; | |||
| struct State { | ||||
|     running: bool, | ||||
| 
 | ||||
|     cursor_size: u32, | ||||
|     cursor_width: u32, | ||||
|     cursor_height: u32, | ||||
|     image_path: String, | ||||
| 
 | ||||
|     compositor: Option<wl_compositor::WlCompositor>, | ||||
|     base_surface: Option<wl_surface::WlSurface>, | ||||
|  | @ -27,6 +31,30 @@ struct State { | |||
|     wm_base: Option<xdg_wm_base::XdgWmBase>, | ||||
| } | ||||
| 
 | ||||
| fn get_cursor_image_path() -> String { | ||||
|     if let Some(p) = std::env::args().skip(1).next() { | ||||
|         return p; | ||||
|     } | ||||
| 
 | ||||
|     if let Ok(p) = std::env::var("WL_CROSSHAIR_IMAGE_PATH") { | ||||
|         return p; | ||||
|     } | ||||
| 
 | ||||
|     [ | ||||
|         std::option_env!("WL_CROSSHAIR_IMAGE_PATH").map(String::from), | ||||
|         Some("cursors/inverse-v.png".to_string()), | ||||
|     ] | ||||
|       .into_iter() | ||||
|       .flatten() | ||||
|       .filter(|p| | ||||
|           std::fs::metadata(p) | ||||
|               .map(|m| m.is_file()) | ||||
|               .unwrap_or(false) | ||||
|       ) | ||||
|       .next() | ||||
|       .expect("Could not find a crosshair image, pass it as a cli argument or set WL_CROSSHAIR_IMAGE_PATH environment variable") | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|     let conn = Connection::connect_to_env().unwrap(); | ||||
| 
 | ||||
|  | @ -38,7 +66,9 @@ fn main() { | |||
| 
 | ||||
|     let mut state = State { | ||||
|         running: true, | ||||
|         cursor_size: 10, | ||||
|         cursor_width: 10, | ||||
|         cursor_height: 10, | ||||
|         image_path: get_cursor_image_path(), | ||||
|         compositor: None, | ||||
|         base_surface: None, | ||||
|         layer_shell: None, | ||||
|  | @ -91,10 +121,11 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State { | |||
|             } else if interface == wl_shm::WlShm::interface().name { | ||||
|                 let shm = registry.bind::<wl_shm::WlShm, _, _>(name, version, qh, ()); | ||||
| 
 | ||||
|                 let (init_w, init_h) = (state.cursor_size, state.cursor_size); | ||||
| 
 | ||||
|                 let mut file = tempfile::tempfile().unwrap(); | ||||
|                 draw(&mut file, (init_w, init_h)); | ||||
|                 state.draw(&mut file); | ||||
| 
 | ||||
|                 let (init_w, init_h) = (state.cursor_width, state.cursor_height); | ||||
| 
 | ||||
|                 let pool = shm.create_pool(file.as_raw_fd(), (init_w * init_h * 4) as i32, qh, ()); | ||||
|                 let buffer = pool.create_buffer( | ||||
|                     0, | ||||
|  | @ -126,38 +157,6 @@ impl Dispatch<WlRegion, ()> for State { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| fn draw(tmp: &mut File, (buf_x, buf_y): (u32, u32)) { | ||||
|     let mut buf = std::io::BufWriter::new(tmp); | ||||
|     for y in 0..buf_y { | ||||
|         for x in 0..buf_x { | ||||
|             let ix = x as i32; | ||||
|             let iy = y as i32; | ||||
| 
 | ||||
|             let dist = if x <= (buf_x / 2) { | ||||
|                 ix + iy - (buf_y as i32) | ||||
|             } else { | ||||
|                 iy - ix | ||||
|             }; | ||||
| 
 | ||||
|             let a: u32 = match dist.abs() { | ||||
|                 0 => 0xFF, | ||||
|                 1 => 0x88, | ||||
|                 _ => 0x00, | ||||
|             }; | ||||
| 
 | ||||
|             let c: u32 = match dist.abs() { | ||||
|                 0 => 0xFF, | ||||
|                 1 => 0x88, | ||||
|                 _ => 0x00, | ||||
|             }; | ||||
| 
 | ||||
|             let color = (a << 24) + (c << 16) + (c << 8) + c; | ||||
|             buf.write_all(&color.to_ne_bytes()).unwrap(); | ||||
|         } | ||||
|     } | ||||
|     buf.flush().unwrap(); | ||||
| } | ||||
| 
 | ||||
| impl State { | ||||
|     fn init_layer_surface(&mut self, qh: &QueueHandle<State>) { | ||||
|         let layer = self.layer_shell.as_ref().unwrap().get_layer_surface( | ||||
|  | @ -171,19 +170,44 @@ impl State { | |||
|         // Center the window
 | ||||
|         layer.set_anchor(Anchor::Top | Anchor::Right | Anchor::Bottom | Anchor::Left); | ||||
|         layer.set_keyboard_interactivity(zwlr_layer_surface_v1::KeyboardInteractivity::None); | ||||
|         layer.set_size(self.cursor_size, self.cursor_size); | ||||
|         layer.set_size(self.cursor_width, self.cursor_height); | ||||
|         // A negative value means we will be centered on the screen
 | ||||
|         // independently of any other xdg_layer_shell
 | ||||
|         layer.set_exclusive_zone(-1); | ||||
|         // Set empty input region to allow clicking through the window.
 | ||||
|         if let Some(compositor) = &self.compositor { | ||||
|             let region = compositor.create_region(qh, ()); | ||||
|             self.base_surface.as_ref().unwrap().set_input_region(Some(®ion)); | ||||
|             self.base_surface | ||||
|                 .as_ref() | ||||
|                 .unwrap() | ||||
|                 .set_input_region(Some(®ion)); | ||||
|         } | ||||
|         self.base_surface.as_ref().unwrap().commit(); | ||||
| 
 | ||||
|         self.layer_surface = Some(layer); | ||||
|     } | ||||
| 
 | ||||
|     fn draw(&mut self, tmp: &mut File) { | ||||
|         let mut buf = std::io::BufWriter::new(tmp); | ||||
| 
 | ||||
|         let i = image::open(&self.image_path).unwrap(); | ||||
| 
 | ||||
|         self.cursor_width = i.width(); | ||||
|         self.cursor_height = i.height(); | ||||
| 
 | ||||
|         for y in 0..self.cursor_height { | ||||
|             for x in 0..self.cursor_width { | ||||
|                 let px = i.get_pixel(x, y).to_rgba(); | ||||
| 
 | ||||
|                 let [r, g, b, a] = px.channels().try_into().unwrap(); | ||||
| 
 | ||||
|                 let color = u32::from_be_bytes([a, r, g, b]); | ||||
| 
 | ||||
|                 buf.write_all(&color.to_le_bytes()).unwrap(); | ||||
|             } | ||||
|         } | ||||
|         buf.flush().unwrap(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue