summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-11-12 00:36:19 -0700
committerIrene Knapp <ireneista@irenes.space>2026-11-12 14:23:50 -0700
commit7c457902864fd3e54832dd22bf33f324b6ec3cdb (patch)
tree6991a0dc8f0eb832e8b60f094789e15a2b59f737 /src/main.rs
parent6480f84e8ee9839fb486916d708712daf34a0aff (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
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs169
1 files changed, 121 insertions, 48 deletions
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 {