aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar BanceDev 2026-02-23 17:27:20 -0500
committerGravatar BanceDev 2026-02-23 17:27:20 -0500
commitbefa1cbd0709ff629c0a0e70b048369506bf7bb6 (patch)
tree6d19902044db59e2e491089aae67b32410dab234
parentget keymap from server instead of building a new one (diff)
add simple cairo visual
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/main.rs73
3 files changed, 75 insertions, 0 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b05975c..9610685 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -298,6 +298,7 @@ version = "0.1.0"
dependencies = [
"as-raw-xcb-connection",
"cairo-rs",
+ "cairo-sys-rs",
"pam",
"xcb",
"xkbcommon",
diff --git a/Cargo.toml b/Cargo.toml
index 3be8b0c..79977b0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,4 +8,5 @@ as-raw-xcb-connection = "1.0.1"
pam = "0.8.0"
xcb = { version = "1.7.0", features = ["xkb"] }
xkbcommon = { version = "0.9.0", features = ["x11"] }
+cairo-sys-rs = "0.20"
cairo-rs = { version = "0.20", features = ["xcb"] }
diff --git a/src/main.rs b/src/main.rs
index d0dbf8f..ef3176b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
use as_raw_xcb_connection::ValidConnection;
+use cairo::{Context, XCBConnection, XCBDrawable, XCBSurface, XCBVisualType};
use pam::Client;
use xcb::Xid;
use xcb::x;
@@ -22,6 +23,35 @@ fn authenticate(username: &str, password: &str) -> bool {
client.authenticate().is_ok() && client.open_session().is_ok()
}
+fn find_visual(screen: &x::Screen) -> Option<x::Visualtype> {
+ for depth in screen.allowed_depths() {
+ for visual in depth.visuals() {
+ if visual.visual_id() == screen.root_visual() {
+ return Some(*visual);
+ }
+ }
+ }
+ None
+}
+
+fn draw(ctx: &Context, width: i32, height: i32, count: usize) {
+ ctx.set_source_rgb(0.06, 0.06, 0.06);
+ ctx.paint().unwrap();
+
+ let dot_radius = 8.0;
+ let dot_spacing = 24.0;
+ let total_width = count as f64 * dot_spacing;
+ let start_x = (width as f64 - total_width) / 2.0 + dot_spacing / 2.0;
+ let center_y = height as f64 / 2.0;
+
+ ctx.set_source_rgb(0.106, 0.992, 0.612);
+ for i in 0..count {
+ let x = start_x + i as f64 * dot_spacing;
+ ctx.arc(x, center_y, dot_radius, 0.0, std::f64::consts::TAU);
+ ctx.fill().unwrap();
+ }
+}
+
fn main() -> xcb::Result<()> {
let username = get_username();
let mut password_buf = String::new();
@@ -115,6 +145,30 @@ fn main() -> xcb::Result<()> {
return Ok(());
}
+ let mut visual = find_visual(&screen).expect("Failed to find visual");
+
+ let cairo_conn = unsafe { XCBConnection::from_raw_none(conn.get_raw_conn() as *mut _) };
+ let cairo_drawable = XCBDrawable(window.resource_id());
+ let visual_ptr = unsafe {
+ XCBVisualType::from_raw_none(
+ &mut visual as *mut x::Visualtype as *mut cairo_sys::xcb_visualtype_t,
+ )
+ };
+ let surface = XCBSurface::create(
+ &cairo_conn,
+ &cairo_drawable,
+ &visual_ptr,
+ screen.width_in_pixels() as i32,
+ screen.height_in_pixels() as i32,
+ )
+ .expect("Failed to create cairo surface");
+
+ let ctx = Context::new(&surface).expect("Failed to create cairo context");
+ let (w, h) = (
+ screen.width_in_pixels() as i32,
+ screen.height_in_pixels() as i32,
+ );
+
// We enter the main event loop
loop {
match conn.wait_for_event()? {
@@ -138,28 +192,47 @@ fn main() -> xcb::Result<()> {
} else {
eprintln!("Authentication failed");
password_buf.clear();
+ draw(&ctx, w, h, 0);
+ surface.flush();
+ conn.flush()?;
}
}
keysyms::KEY_BackSpace => {
password_buf.pop();
+ draw(&ctx, w, h, password_buf.len());
+ surface.flush();
+ conn.flush()?;
}
keysyms::KEY_Escape => {
password_buf.clear();
+ draw(&ctx, w, h, 0);
+ surface.flush();
+ conn.flush()?;
}
_ => {
if !c.is_empty() {
password_buf.push_str(&c);
+ draw(&ctx, w, h, password_buf.len());
+ surface.flush();
+ conn.flush()?;
}
}
}
}
+
xcb::Event::X(x::Event::KeyRelease(ev)) => {
let keycode = ev.detail();
state.update_key(keycode.into(), xkb::KeyDirection::Up);
}
+
+ xcb::Event::X(x::Event::Expose(_)) => {
+ draw(&ctx, w, h, password_buf.len());
+ surface.flush();
+ conn.flush()?;
+ }
_ => {}
}
}