summary refs log tree commit diff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs137
1 files changed, 96 insertions, 41 deletions
diff --git a/src/main.rs b/src/main.rs
index 5ad82a4..5b2f853 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,28 +1,31 @@
+use crate::geometry::*;
 use crate::x::*;
 
+use std::ops::Sub;
 use std::sync::Arc;
 
 use xcb::{ Xid };
 use xcb::x::{
   ClientMessageData,
+  Gc, ChangeGc,
   Cw, CreateWindow,
   Drawable,
   EventMask,
-  PolyFillRectangle,
+  PolyFillArc, PolyFillRectangle,
   Screen,
   WindowClass
 };
 
+mod geometry;
 mod x;
 
 
-#[derive(Clone, Copy, PartialEq, Eq)]
-enum ScreenSide { Top, Bottom, Left, Right }
-
 struct DockConfiguration {
   thickness: u16,
-  side: ScreenSide,
+  side: Side,
   background_pixel: u32,
+  use_rounded_inside_corners: bool,
+  use_rounded_outside_corners: bool,
 }
 
 struct Dock {
@@ -36,16 +39,6 @@ impl HasWindow for Dock {
 }
 
 
-#[derive(Debug)]
-struct Rectangle<T> {
-  left: T,
-  top: T,
-  width: T,
-  height: T,
-}
-
-
-
 fn main() -> xcb::Result<()> {
   let display = Arc::new(Display::new()?);
 
@@ -54,14 +47,16 @@ fn main() -> xcb::Result<()> {
 
   let dock = Dock::new(Arc::clone(&display), DockConfiguration {
     thickness: 50,
-    side: ScreenSide::Bottom,
+    side: Side::Bottom,
     background_pixel,
+    use_rounded_inside_corners: false,
+    use_rounded_outside_corners: true,
   })?;
 
   loop {
     match display.wait_for_event()? {
       xcb::Event::X(xcb::x::Event::Expose(_event)) => {
-	let _ = dock.redraw(); // TODO
+        let _ = dock.redraw(); // TODO
       }
 
       xcb::Event::X(xcb::x::Event::ButtonPress(event)) => {
@@ -132,10 +127,10 @@ impl Dock {
     let thickness = self.configuration.thickness as u32;
 
     let strut_values = match self.configuration.side {
-      ScreenSide::Left => &[thickness, 0 as u32, 0 as u32, 0 as u32],
-      ScreenSide::Right => &[0 as u32, thickness, 0 as u32, 0 as u32],
-      ScreenSide::Top => &[0 as u32, 0 as u32, thickness, 0 as u32],
-      ScreenSide::Bottom => &[0 as u32, 0 as u32, 0 as u32, thickness],
+      Side::Left => &[thickness, 0 as u32, 0 as u32, 0 as u32],
+      Side::Right => &[0 as u32, thickness, 0 as u32, 0 as u32],
+      Side::Top => &[0 as u32, 0 as u32, thickness, 0 as u32],
+      Side::Bottom => &[0 as u32, 0 as u32, 0 as u32, thickness],
     };
     self.set_cardinal_property(&atoms.wm_strut, strut_values)?;
 
@@ -146,22 +141,22 @@ impl Dock {
       strut_values[3],
 
       0 as u32,
-      if self.configuration.side == ScreenSide::Left {
+      if self.configuration.side == Side::Left {
         screen.height_in_pixels() as u32
       } else { 0 as u32 },
 
       0 as u32,
-      if self.configuration.side == ScreenSide::Right {
+      if self.configuration.side == Side::Right {
         screen.height_in_pixels() as u32
       } else { 0 as u32 },
 
       0 as u32,
-      if self.configuration.side == ScreenSide::Top {
+      if self.configuration.side == Side::Top {
         screen.width_in_pixels() as u32
       } else { 0 as u32 },
 
       0 as u32,
-      if self.configuration.side == ScreenSide::Bottom {
+      if self.configuration.side == Side::Bottom {
         screen.width_in_pixels() as u32
       } else { 0 as u32 },
     ];
@@ -176,14 +171,14 @@ impl Dock {
   fn compute_bounds(screen: &Screen, configuration: &DockConfiguration)
     -> Rectangle<u16>
   {
-    if configuration.side == ScreenSide::Top
-       || configuration.side == ScreenSide::Bottom
+    if configuration.side == Side::Top
+       || configuration.side == Side::Bottom
     {
       let left = 0;
       let width = screen.width_in_pixels();
       let height = configuration.thickness;
 
-      let top = if configuration.side == ScreenSide::Bottom {
+      let top = if configuration.side == Side::Bottom {
         screen.height_in_pixels() - height
       } else { 0 };
 
@@ -193,7 +188,7 @@ impl Dock {
       let height = screen.height_in_pixels();
       let width = configuration.thickness;
 
-      let left = if configuration.side == ScreenSide::Right {
+      let left = if configuration.side == Side::Right {
         screen.width_in_pixels() - width
       } else { 0 };
 
@@ -203,25 +198,85 @@ impl Dock {
 
 
   fn redraw(&self) -> xcb::Result<()> {
-    println!("redraw");
-
     let drawable = Drawable::Window(self.window_id());
     let context = GraphicContext::new(
-	              Arc::clone(self.display()), drawable)?;
+                      Arc::clone(self.display()), drawable)?;
+
+    if self.configuration.use_rounded_inside_corners
+       || self.configuration.use_rounded_outside_corners
+    {
+      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 black = self.screen().black_pixel();
+          corner_squares.push(corner_square);
+          corner_arcs.push(corner_arc);
+        }
+      }
 
-    let cookie = self.send_request_checked(&PolyFillRectangle {
-      drawable: drawable,
-      gc: context.graphic_context_id(),
-      rectangles: &[xcb::x::Rectangle {
-	x: 0, y: 0, width: 25, height: 25
-      }],
-    });
-    self.check_request(cookie)?;
+      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)
+  {
+    let radius = self.configuration.thickness / 2;
+    let diameter = self.configuration.thickness;
+
+    let bounds = &self.bounds;
+
+    let corner_square = bounds.corner_square(corner, radius)
+                              .to_x_rectangle();
+
+    let angle1 = corner.first_clockwise_side().to_x_angle();
+    let corner_arc = bounds.corner_square(corner, diameter)
+                           .to_x_arc(angle1, X_CLOCKWISE_RIGHT_ANGLE);
+
+    (corner_square, corner_arc)
+  }
 }
 
 impl HasDisplay for Dock {