Rust · 2284 bytes Raw Blame History
1 //! Cairo rendering for the greeter
2 //!
3 //! Provides a Cairo surface that can be rendered to X11.
4
5 use anyhow::{Context, Result};
6 use cairo::{Context as CairoContext, Format, ImageSurface};
7
8 /// Cairo-based renderer
9 pub struct Renderer {
10 surface: ImageSurface,
11 width: i32,
12 height: i32,
13 }
14
15 impl Renderer {
16 /// Create a new renderer with the given dimensions
17 pub fn new(width: u16, height: u16) -> Result<Self> {
18 let surface = ImageSurface::create(Format::ARgb32, width as i32, height as i32)
19 .context("Failed to create Cairo surface")?;
20
21 Ok(Self {
22 surface,
23 width: width as i32,
24 height: height as i32,
25 })
26 }
27
28 /// Get a Cairo context for drawing
29 pub fn context(&self) -> Result<CairoContext> {
30 CairoContext::new(&self.surface).context("Failed to create Cairo context")
31 }
32
33 /// Get the raw pixel data for X11 (BGRA format on little-endian)
34 pub fn data(&mut self) -> Result<Vec<u8>> {
35 self.surface.flush();
36
37 let stride = self.surface.stride() as usize;
38 let height = self.height as usize;
39
40 let data = self
41 .surface
42 .data()
43 .context("Failed to get surface data")?;
44
45 // Cairo uses ARGB, which on little-endian is BGRA in memory
46 // X11 with depth 24/32 typically expects the same
47 Ok(data[..stride * height].to_vec())
48 }
49
50 /// Get the width
51 pub fn width(&self) -> i32 {
52 self.width
53 }
54
55 /// Get the height
56 pub fn height(&self) -> i32 {
57 self.height
58 }
59
60 /// Clear the surface with a solid color
61 pub fn clear(&self, r: f64, g: f64, b: f64) -> Result<()> {
62 let ctx = self.context()?;
63 ctx.set_source_rgb(r, g, b);
64 ctx.paint()?;
65 Ok(())
66 }
67 }
68
69 /// Draw a rounded rectangle path
70 pub fn rounded_rectangle(ctx: &CairoContext, x: f64, y: f64, w: f64, h: f64, r: f64) {
71 let degrees = std::f64::consts::PI / 180.0;
72 ctx.new_sub_path();
73 ctx.arc(x + w - r, y + r, r, -90.0 * degrees, 0.0);
74 ctx.arc(x + w - r, y + h - r, r, 0.0, 90.0 * degrees);
75 ctx.arc(x + r, y + h - r, r, 90.0 * degrees, 180.0 * degrees);
76 ctx.arc(x + r, y + r, r, 180.0 * degrees, 270.0 * degrees);
77 ctx.close_path();
78 }
79