diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-11-12 00:36:19 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-11-12 14:23:50 -0700 |
| commit | 7c457902864fd3e54832dd22bf33f324b6ec3cdb (patch) | |
| tree | 6991a0dc8f0eb832e8b60f094789e15a2b59f737 | |
| parent | 6480f84e8ee9839fb486916d708712daf34a0aff (diff) | |
draw text
this uses Xft, which unfortunately has a lot of parallel tooling it needs some refactoring into its own files, but it works :) Change-Id: I0e78ea69167b1d91af2e9f494d757564d8cb7cdb Force-Push: yes
| -rw-r--r-- | Cargo.lock | 18 | ||||
| -rw-r--r-- | Cargo.toml | 6 | ||||
| -rw-r--r-- | src/main.rs | 169 | ||||
| -rw-r--r-- | src/x/connection.rs | 10 | ||||
| -rw-r--r-- | src/x/display.rs | 2 |
5 files changed, 151 insertions, 54 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9d8267d..6e41252 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] name = "quick-xml" version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -33,10 +39,21 @@ dependencies = [ name = "sandbar" version = "1.0.0" dependencies = [ + "x11", "xcb", ] [[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] name = "xcb" version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -45,4 +62,5 @@ dependencies = [ "bitflags", "libc", "quick-xml", + "x11", ] diff --git a/Cargo.toml b/Cargo.toml index bdc2891..1bb85d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,9 @@ edition = "2024" [dependencies.xcb] version = "1.7.1" -features = [ "libxcb_v1_14" ] +features = [ "libxcb_v1_14", "xlib_xcb" ] + +[dependencies.x11] +version = "2.21.0" +features = [ "xft", "xlib_xcb" ] diff --git a/src/main.rs b/src/main.rs index 5b2f853..523ec45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,15 @@ use crate::geometry::*; use crate::x::*; -use std::ops::Sub; use std::sync::Arc; +use x11::xrender::XRenderColor; +use x11::xft::{ + XftFontOpenName, + XftDrawCreate, XftDrawDestroy, + XftColor, + XftDrawStringUtf8 +}; use xcb::{ Xid }; use xcb::x::{ ClientMessageData, @@ -24,6 +30,8 @@ struct DockConfiguration { thickness: u16, side: Side, background_pixel: u32, + foreground_pixel: u32, + foreground_render_color: XRenderColor, use_rounded_inside_corners: bool, use_rounded_outside_corners: bool, } @@ -32,6 +40,7 @@ struct Dock { configuration: DockConfiguration, window: Window, bounds: Arc<Rectangle<u16>>, + font: *mut x11::xft::XftFont, } impl HasWindow for Dock { @@ -45,10 +54,17 @@ fn main() -> xcb::Result<()> { // #d4ffcc let background_pixel = display.allocate_color(54484, 65535, 52428)?; + // #5c01be + let foreground_pixel = display.allocate_color(23644, 257, 48830)?; + let foreground_render_color = XRenderColor { + red: 23644, green: 257, blue: 48830, alpha: 65535, + }; + let dock = Dock::new(Arc::clone(&display), DockConfiguration { - thickness: 50, + thickness: 34, side: Side::Bottom, background_pixel, + foreground_pixel, foreground_render_color, use_rounded_inside_corners: false, use_rounded_outside_corners: true, })?; @@ -103,7 +119,21 @@ impl Dock { Cw::EventMask(EventMask::EXPOSURE | EventMask::BUTTON_PRESS), ], })?; - let dock = Dock { window, configuration, bounds: Arc::new(dock_bounds) }; + + let xlib_display = display.connection().get_xlib_display(); + let screen_index = display.screen_index(); + + let font = unsafe { + XftFontOpenName(xlib_display, screen_index, + c"FantasqueSansM Nerd Font Mono:style=Regular:size=18" + .as_ptr().cast()) + }; + + let dock = Dock { + window, configuration, + bounds: Arc::new(dock_bounds), + font + }; dock.set_string_property(&xcb::x::ATOM_WM_NAME, b"sandbar")?; @@ -205,61 +235,73 @@ impl Dock { if self.configuration.use_rounded_inside_corners || self.configuration.use_rounded_outside_corners { - let black_pixel = self.screen().black_pixel(); + self.draw_corners(drawable, &context)?; + } - let mut corner_squares = Vec::new(); - let mut corner_arcs = Vec::new(); - if self.configuration.use_rounded_outside_corners { - for corner in self.configuration.side.corners_on_side() { - let (corner_square, corner_arc) = self.compute_corner_regions(*corner); + self.draw_text()?; - corner_squares.push(corner_square); - corner_arcs.push(corner_arc); - } - } - if self.configuration.use_rounded_inside_corners { - for corner in self.configuration.side.opposite().corners_on_side() { - let (corner_square, corner_arc) = self.compute_corner_regions(*corner); + Ok(()) + } - corner_squares.push(corner_square); - corner_arcs.push(corner_arc); - } + + fn draw_corners(&self, drawable: Drawable, context: &GraphicContext) + -> xcb::Result<()> + { + let black_pixel = self.screen().black_pixel(); + + let mut corner_squares = Vec::new(); + let mut corner_arcs = Vec::new(); + if self.configuration.use_rounded_outside_corners { + for corner in self.configuration.side.corners_on_side() { + let (corner_square, corner_arc) = self.compute_corner_regions(*corner); + + corner_squares.push(corner_square); + corner_arcs.push(corner_arc); } + } + if self.configuration.use_rounded_inside_corners { + for corner in self.configuration.side.opposite().corners_on_side() { + let (corner_square, corner_arc) = self.compute_corner_regions(*corner); - let cookie = self.send_request_checked(&ChangeGc { - gc: context.graphic_context_id(), - value_list: &[ - Gc::Foreground(black_pixel), - ], - }); - self.check_request(cookie)?; - - let cookie = self.send_request_checked(&PolyFillRectangle { - drawable: drawable, - gc: context.graphic_context_id(), - rectangles: &corner_squares, - }); - self.check_request(cookie)?; - - let cookie = self.send_request_checked(&ChangeGc { - gc: context.graphic_context_id(), - value_list: &[ - Gc::Foreground(self.configuration.background_pixel), - ], - }); - self.check_request(cookie)?; - - let cookie = self.send_request_checked(&PolyFillArc { - drawable: drawable, - gc: context.graphic_context_id(), - arcs: &corner_arcs, - }); - self.check_request(cookie)?; + corner_squares.push(corner_square); + corner_arcs.push(corner_arc); + } } + let cookie = self.send_request_checked(&ChangeGc { + gc: context.graphic_context_id(), + value_list: &[ + Gc::Foreground(black_pixel), + ], + }); + self.check_request(cookie)?; + + let cookie = self.send_request_checked(&PolyFillRectangle { + drawable: drawable, + gc: context.graphic_context_id(), + rectangles: &corner_squares, + }); + self.check_request(cookie)?; + + let cookie = self.send_request_checked(&ChangeGc { + gc: context.graphic_context_id(), + value_list: &[ + Gc::Foreground(self.configuration.background_pixel), + ], + }); + self.check_request(cookie)?; + + let cookie = self.send_request_checked(&PolyFillArc { + drawable: drawable, + gc: context.graphic_context_id(), + arcs: &corner_arcs, + }); + self.check_request(cookie)?; + Ok(()) } + fn compute_corner_regions(&self, corner: Corner) -> (xcb::x::Rectangle, xcb::x::Arc) { @@ -277,6 +319,37 @@ impl Dock { (corner_square, corner_arc) } + + + fn draw_text(&self) -> xcb::Result<()> { + let xlib_display = self.connection().get_xlib_display(); + let x_visual = unsafe { + x11::xlib::XDefaultVisual(xlib_display, + self.display().screen_index()) + }; + + let xft_context = unsafe { + XftDrawCreate(xlib_display, + self.window().window_id().resource_id() as u64, + x_visual, + self.screen().default_colormap().resource_id() as u64) + }; + + let xft_color = XftColor { + pixel: self.configuration.foreground_pixel as u64, + color: self.configuration.foreground_render_color, + }; + let text = c"amazing cool fiction technically reads playful unknown telephonic works from-post"; + unsafe { + XftDrawStringUtf8(xft_context, &xft_color, self.font, 12, 25, + text.as_ptr().cast(), + text.count_bytes() as i32) + }; + + unsafe { XftDrawDestroy(xft_context) }; + + Ok(()) + } } impl HasDisplay for Dock { diff --git a/src/x/connection.rs b/src/x/connection.rs index d9ed9ca..78e721d 100644 --- a/src/x/connection.rs +++ b/src/x/connection.rs @@ -7,11 +7,9 @@ use xcb::x::{ Atom, InternAtom }; pub struct Connection(xcb::Connection); impl Connection { - pub fn connect(display_name: Option<&str>) - -> xcb::ConnResult<(Connection, i32)> - { + pub fn connect() -> xcb::ConnResult<(Connection, i32)> { let (connection, screen_index) - = xcb::Connection::connect(display_name)?; + = xcb::Connection::connect_with_xlib_display()?; Ok((Connection(connection), screen_index)) } @@ -91,6 +89,10 @@ pub trait ConnectionExt: HasConnection { wm_strut, wm_strut_partial, }) } + + fn get_xlib_display(&self) -> *mut x11::xlib::Display { + self.connection().0.get_raw_dpy() + } } impl<T: HasConnection> ConnectionExt for T { } diff --git a/src/x/display.rs b/src/x/display.rs index ca552db..7aa7e2e 100644 --- a/src/x/display.rs +++ b/src/x/display.rs @@ -19,7 +19,7 @@ impl HasConnection for Arc<Display> { impl Display { pub fn new() -> xcb::Result<Display> { - let (connection, screen_index) = Connection::connect(None)?; + let (connection, screen_index) = Connection::connect()?; let atoms = connection.get_atoms()?; |