From 7c457902864fd3e54832dd22bf33f324b6ec3cdb Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Thu, 12 Nov 2026 00:36:19 -0700 Subject: 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 --- src/main.rs | 169 +++++++++++++++++++++++++++++++++++++--------------- src/x/connection.rs | 10 ++-- src/x/display.rs | 2 +- 3 files changed, 128 insertions(+), 53 deletions(-) (limited to 'src') 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>, + 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 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 { impl Display { pub fn new() -> xcb::Result { - let (connection, screen_index) = Connection::connect(None)?; + let (connection, screen_index) = Connection::connect()?; let atoms = connection.get_atoms()?; -- cgit 1.4.1