diff options
| author | 2026-02-23 17:27:20 -0500 | |
|---|---|---|
| committer | 2026-02-23 17:27:20 -0500 | |
| commit | befa1cbd0709ff629c0a0e70b048369506bf7bb6 (patch) | |
| tree | 6d19902044db59e2e491089aae67b32410dab234 | |
| parent | get keymap from server instead of building a new one (diff) | |
add simple cairo visual
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/main.rs | 73 |
3 files changed, 75 insertions, 0 deletions
@@ -298,6 +298,7 @@ version = "0.1.0" dependencies = [ "as-raw-xcb-connection", "cairo-rs", + "cairo-sys-rs", "pam", "xcb", "xkbcommon", @@ -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()?; + } _ => {} } } |
