mirror of
https://github.com/lelgenio/wl-crosshair.git
synced 2025-01-18 22:36:26 -03:00
Compare commits
No commits in common. "a4a5c1f49bb8f70afdb587aff715ef3b6452708d" and "081f6bed695f9cf9f3947b44cfe37abad850f89e" have entirely different histories.
a4a5c1f49b
...
081f6bed69
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,2 @@
|
||||||
/target
|
/target
|
||||||
.direnv/
|
.direnv/
|
||||||
cursors/*~
|
|
||||||
|
|
940
Cargo.lock
generated
940
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -10,4 +10,3 @@ wayland-protocols-wlr = { version = "0.1.0", features = ["client"] }
|
||||||
|
|
||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
tempfile = "3.2"
|
tempfile = "3.2"
|
||||||
image = "0.25.1"
|
|
||||||
|
|
|
@ -3,11 +3,9 @@ A crosshair overlay for wlroots compositors.
|
||||||
|
|
||||||
A extremely stripped down version of [crossover](https://github.com/lacymorrow/crossover).
|
A extremely stripped down version of [crossover](https://github.com/lacymorrow/crossover).
|
||||||
|
|
||||||
```sh
|
Currently has no support for command line arguments or any customization.
|
||||||
wl-crosshair ./my-crosshair.png
|
|
||||||
```
|
|
||||||
|
|
||||||
### Preview (default cursor):
|
### Preview:
|
||||||
![image](https://github.com/lelgenio/wl-crosshair/assets/31388299/6e0aaa16-837b-40a8-9a13-ed808ea5db86)
|
![image](https://github.com/lelgenio/wl-crosshair/assets/31388299/6e0aaa16-837b-40a8-9a13-ed808ea5db86)
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
@ -15,4 +13,4 @@ wl-crosshair ./my-crosshair.png
|
||||||
- [ ] Option to control size of crosshair
|
- [ ] Option to control size of crosshair
|
||||||
- [ ] Option to offset crosshair
|
- [ ] Option to offset crosshair
|
||||||
- [ ] Configuratin file
|
- [ ] Configuratin file
|
||||||
- [x] Support for loading custom crosshair images
|
- [ ] Support for loading custom crosshair images
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 204 KiB |
|
@ -19,13 +19,6 @@
|
||||||
version = "0.1.0";
|
version = "0.1.0";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
cargoLock.lockFile = ./Cargo.lock;
|
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,10 +1,8 @@
|
||||||
use std::{fs::File, io::Write, os::unix::prelude::AsRawFd};
|
use std::{fs::File, io::Write, os::unix::prelude::AsRawFd};
|
||||||
|
|
||||||
use image::{GenericImageView, Pixel};
|
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
protocol::{
|
protocol::{
|
||||||
wl_buffer, wl_compositor, wl_keyboard, wl_region::WlRegion, wl_registry, wl_seat, wl_shm,
|
wl_buffer, wl_compositor, wl_keyboard, wl_region::WlRegion, wl_registry, wl_seat, wl_shm, wl_shm_pool, wl_surface
|
||||||
wl_shm_pool, wl_surface,
|
|
||||||
},
|
},
|
||||||
Connection, Dispatch, Proxy, QueueHandle,
|
Connection, Dispatch, Proxy, QueueHandle,
|
||||||
};
|
};
|
||||||
|
@ -19,9 +17,7 @@ use wayland_protocols::xdg::shell::client::xdg_wm_base;
|
||||||
struct State {
|
struct State {
|
||||||
running: bool,
|
running: bool,
|
||||||
|
|
||||||
cursor_width: u32,
|
cursor_size: u32,
|
||||||
cursor_height: u32,
|
|
||||||
image_path: String,
|
|
||||||
|
|
||||||
compositor: Option<wl_compositor::WlCompositor>,
|
compositor: Option<wl_compositor::WlCompositor>,
|
||||||
base_surface: Option<wl_surface::WlSurface>,
|
base_surface: Option<wl_surface::WlSurface>,
|
||||||
|
@ -31,30 +27,6 @@ struct State {
|
||||||
wm_base: Option<xdg_wm_base::XdgWmBase>,
|
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() {
|
fn main() {
|
||||||
let conn = Connection::connect_to_env().unwrap();
|
let conn = Connection::connect_to_env().unwrap();
|
||||||
|
|
||||||
|
@ -66,9 +38,7 @@ fn main() {
|
||||||
|
|
||||||
let mut state = State {
|
let mut state = State {
|
||||||
running: true,
|
running: true,
|
||||||
cursor_width: 10,
|
cursor_size: 10,
|
||||||
cursor_height: 10,
|
|
||||||
image_path: get_cursor_image_path(),
|
|
||||||
compositor: None,
|
compositor: None,
|
||||||
base_surface: None,
|
base_surface: None,
|
||||||
layer_shell: None,
|
layer_shell: None,
|
||||||
|
@ -121,11 +91,10 @@ impl Dispatch<wl_registry::WlRegistry, ()> for State {
|
||||||
} else if interface == wl_shm::WlShm::interface().name {
|
} else if interface == wl_shm::WlShm::interface().name {
|
||||||
let shm = registry.bind::<wl_shm::WlShm, _, _>(name, version, qh, ());
|
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();
|
let mut file = tempfile::tempfile().unwrap();
|
||||||
state.draw(&mut file);
|
draw(&mut file, (init_w, init_h));
|
||||||
|
|
||||||
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 pool = shm.create_pool(file.as_raw_fd(), (init_w * init_h * 4) as i32, qh, ());
|
||||||
let buffer = pool.create_buffer(
|
let buffer = pool.create_buffer(
|
||||||
0,
|
0,
|
||||||
|
@ -157,6 +126,38 @@ 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 {
|
impl State {
|
||||||
fn init_layer_surface(&mut self, qh: &QueueHandle<State>) {
|
fn init_layer_surface(&mut self, qh: &QueueHandle<State>) {
|
||||||
let layer = self.layer_shell.as_ref().unwrap().get_layer_surface(
|
let layer = self.layer_shell.as_ref().unwrap().get_layer_surface(
|
||||||
|
@ -170,44 +171,19 @@ impl State {
|
||||||
// Center the window
|
// Center the window
|
||||||
layer.set_anchor(Anchor::Top | Anchor::Right | Anchor::Bottom | Anchor::Left);
|
layer.set_anchor(Anchor::Top | Anchor::Right | Anchor::Bottom | Anchor::Left);
|
||||||
layer.set_keyboard_interactivity(zwlr_layer_surface_v1::KeyboardInteractivity::None);
|
layer.set_keyboard_interactivity(zwlr_layer_surface_v1::KeyboardInteractivity::None);
|
||||||
layer.set_size(self.cursor_width, self.cursor_height);
|
layer.set_size(self.cursor_size, self.cursor_size);
|
||||||
// A negative value means we will be centered on the screen
|
// A negative value means we will be centered on the screen
|
||||||
// independently of any other xdg_layer_shell
|
// independently of any other xdg_layer_shell
|
||||||
layer.set_exclusive_zone(-1);
|
layer.set_exclusive_zone(-1);
|
||||||
// Set empty input region to allow clicking through the window.
|
// Set empty input region to allow clicking through the window.
|
||||||
if let Some(compositor) = &self.compositor {
|
if let Some(compositor) = &self.compositor {
|
||||||
let region = compositor.create_region(qh, ());
|
let region = compositor.create_region(qh, ());
|
||||||
self.base_surface
|
self.base_surface.as_ref().unwrap().set_input_region(Some(®ion));
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.set_input_region(Some(®ion));
|
|
||||||
}
|
}
|
||||||
self.base_surface.as_ref().unwrap().commit();
|
self.base_surface.as_ref().unwrap().commit();
|
||||||
|
|
||||||
self.layer_surface = Some(layer);
|
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 {
|
impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for State {
|
||||||
|
|
Loading…
Reference in a new issue