summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock18
-rw-r--r--Cargo.toml6
-rw-r--r--src/main.rs169
-rw-r--r--src/x/connection.rs10
-rw-r--r--src/x/display.rs2
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()?;