refactor(layouts): add darwin feature gate and expand win32 feature gate

This commit builds on the newly introduced komorebi-layouts crate to
make it suitable for wholesale adoption in komorebi for Mac.
This commit is contained in:
LGUG2Z
2026-02-07 14:19:23 -08:00
parent 0b5141e7a4
commit 1dad13106a
8 changed files with 100 additions and 0 deletions
Generated
+1
View File
@@ -3238,6 +3238,7 @@ version = "0.1.40"
dependencies = [ dependencies = [
"clap", "clap",
"color-eyre", "color-eyre",
"objc2-core-foundation",
"schemars 1.2.1", "schemars 1.2.1",
"serde", "serde",
"serde_json_lenient", "serde_json_lenient",
+5
View File
@@ -50,6 +50,11 @@ crate = "komorebi-client"
expression = "LicenseRef-Komorebi-2.0" expression = "LicenseRef-Komorebi-2.0"
license-files = [] license-files = []
[[licenses.clarify]]
crate = "komorebi-layouts"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]] [[licenses.clarify]]
crate = "komorebic" crate = "komorebic"
expression = "LicenseRef-Komorebi-2.0" expression = "LicenseRef-Komorebi-2.0"
+5
View File
@@ -15,7 +15,12 @@ tracing = { workspace = true }
# Optional dependencies # Optional dependencies
schemars = { workspace = true, optional = true } schemars = { workspace = true, optional = true }
windows = { workspace = true, optional = true } windows = { workspace = true, optional = true }
objc2-core-foundation = { version = "0.3", default-features = false, features = [
"std",
"CFCGTypes",
], optional = true }
[features] [features]
schemars = ["dep:schemars"] schemars = ["dep:schemars"]
win32 = ["dep:windows"] win32 = ["dep:windows"]
darwin = ["dep:objc2-core-foundation"]
+7
View File
@@ -6,11 +6,15 @@ use serde::Serialize;
use strum::Display; use strum::Display;
use strum::EnumString; use strum::EnumString;
#[cfg(feature = "win32")]
use super::CustomLayout; use super::CustomLayout;
use super::DefaultLayout; use super::DefaultLayout;
use super::Rect; use super::Rect;
#[cfg(feature = "win32")]
use super::custom_layout::Column; use super::custom_layout::Column;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplit; use super::custom_layout::ColumnSplit;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplitWithCapacity; use super::custom_layout::ColumnSplitWithCapacity;
use crate::default_layout::DEFAULT_RATIO; use crate::default_layout::DEFAULT_RATIO;
use crate::default_layout::DEFAULT_SECONDARY_RATIO; use crate::default_layout::DEFAULT_SECONDARY_RATIO;
@@ -719,6 +723,7 @@ impl Arrangement for DefaultLayout {
} }
} }
#[cfg(feature = "win32")]
impl Arrangement for CustomLayout { impl Arrangement for CustomLayout {
fn calculate( fn calculate(
&self, &self,
@@ -857,6 +862,7 @@ pub enum Axis {
HorizontalAndVertical, HorizontalAndVertical,
} }
#[cfg(feature = "win32")]
#[must_use] #[must_use]
fn columns(area: &Rect, len: usize) -> Vec<Rect> { fn columns(area: &Rect, len: usize) -> Vec<Rect> {
columns_with_ratios(area, len, None) columns_with_ratios(area, len, None)
@@ -931,6 +937,7 @@ fn columns_with_ratios(
layouts layouts
} }
#[cfg(feature = "win32")]
#[must_use] #[must_use]
fn rows(area: &Rect, len: usize) -> Vec<Rect> { fn rows(area: &Rect, len: usize) -> Vec<Rect> {
rows_with_ratios(area, len, None) rows_with_ratios(area, len, None)
+5
View File
@@ -1,8 +1,12 @@
use super::DefaultLayout; use super::DefaultLayout;
use super::OperationDirection; use super::OperationDirection;
#[cfg(feature = "win32")]
use super::custom_layout::Column; use super::custom_layout::Column;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplit; use super::custom_layout::ColumnSplit;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplitWithCapacity; use super::custom_layout::ColumnSplitWithCapacity;
#[cfg(feature = "win32")]
use super::custom_layout::CustomLayout; use super::custom_layout::CustomLayout;
use crate::default_layout::LayoutOptions; use crate::default_layout::LayoutOptions;
@@ -400,6 +404,7 @@ fn grid_neighbor(
} }
} }
#[cfg(feature = "win32")]
impl Direction for CustomLayout { impl Direction for CustomLayout {
fn index_in_direction( fn index_in_direction(
&self, &self,
+4
View File
@@ -2,6 +2,7 @@ use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use super::Arrangement; use super::Arrangement;
#[cfg(feature = "win32")]
use super::CustomLayout; use super::CustomLayout;
use super::DefaultLayout; use super::DefaultLayout;
use super::Direction; use super::Direction;
@@ -10,6 +11,7 @@ use super::Direction;
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Layout { pub enum Layout {
Default(DefaultLayout), Default(DefaultLayout),
#[cfg(feature = "win32")]
Custom(CustomLayout), Custom(CustomLayout),
} }
@@ -18,6 +20,7 @@ impl Layout {
pub fn as_boxed_direction(&self) -> Box<dyn Direction> { pub fn as_boxed_direction(&self) -> Box<dyn Direction> {
match self { match self {
Layout::Default(layout) => Box::new(*layout), Layout::Default(layout) => Box::new(*layout),
#[cfg(feature = "win32")]
Layout::Custom(layout) => Box::new(layout.clone()), Layout::Custom(layout) => Box::new(layout.clone()),
} }
} }
@@ -26,6 +29,7 @@ impl Layout {
pub fn as_boxed_arrangement(&self) -> Box<dyn Arrangement> { pub fn as_boxed_arrangement(&self) -> Box<dyn Arrangement> {
match self { match self {
Layout::Default(layout) => Box::new(*layout), Layout::Default(layout) => Box::new(*layout),
#[cfg(feature = "win32")]
Layout::Custom(layout) => Box::new(layout.clone()), Layout::Custom(layout) => Box::new(layout.clone()),
} }
} }
+2
View File
@@ -8,6 +8,7 @@
//! behind the `win32` feature flag. //! behind the `win32` feature flag.
pub mod arrangement; pub mod arrangement;
#[cfg(feature = "win32")]
pub mod custom_layout; pub mod custom_layout;
pub mod cycle_direction; pub mod cycle_direction;
pub mod default_layout; pub mod default_layout;
@@ -18,6 +19,7 @@ pub mod rect;
pub mod sizing; pub mod sizing;
pub use arrangement::*; pub use arrangement::*;
#[cfg(feature = "win32")]
pub use custom_layout::*; pub use custom_layout::*;
pub use cycle_direction::*; pub use cycle_direction::*;
pub use default_layout::*; pub use default_layout::*;
+71
View File
@@ -4,6 +4,15 @@ use serde::Serialize;
#[cfg(feature = "win32")] #[cfg(feature = "win32")]
use windows::Win32::Foundation::RECT; use windows::Win32::Foundation::RECT;
#[cfg(feature = "darwin")]
use objc2_core_foundation::CGFloat;
#[cfg(feature = "darwin")]
use objc2_core_foundation::CGPoint;
#[cfg(feature = "darwin")]
use objc2_core_foundation::CGRect;
#[cfg(feature = "darwin")]
use objc2_core_foundation::CGSize;
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)] #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
/// Rectangle dimensions /// Rectangle dimensions
@@ -42,6 +51,53 @@ impl From<Rect> for RECT {
} }
} }
#[cfg(feature = "darwin")]
impl From<CGSize> for Rect {
fn from(value: CGSize) -> Self {
Self {
left: 0,
top: 0,
right: value.width as i32,
bottom: value.height as i32,
}
}
}
#[cfg(feature = "darwin")]
impl From<CGRect> for Rect {
fn from(value: CGRect) -> Self {
Self {
left: value.origin.x as i32,
top: value.origin.y as i32,
right: value.size.width as i32,
bottom: value.size.height as i32,
}
}
}
#[cfg(feature = "darwin")]
impl From<&Rect> for CGRect {
fn from(value: &Rect) -> Self {
Self {
origin: CGPoint {
x: value.left as CGFloat,
y: value.top as CGFloat,
},
size: CGSize {
width: value.right as CGFloat,
height: value.bottom as CGFloat,
},
}
}
}
#[cfg(feature = "darwin")]
impl From<Rect> for CGRect {
fn from(value: Rect) -> Self {
CGRect::from(&value)
}
}
impl Rect { impl Rect {
pub fn is_same_size_as(&self, rhs: &Self) -> bool { pub fn is_same_size_as(&self, rhs: &Self) -> bool {
self.right == rhs.right && self.bottom == rhs.bottom self.right == rhs.right && self.bottom == rhs.bottom
@@ -110,4 +166,19 @@ impl Rect {
bottom: self.top + self.bottom, bottom: self.top + self.bottom,
} }
} }
#[cfg(feature = "darwin")]
#[must_use]
pub fn percentage_within_horizontal_bounds(&self, other: &Rect) -> f64 {
let overlap_left = self.left.max(other.left);
let overlap_right = (self.left + self.right).min(other.left + other.right);
let overlap_width = overlap_right - overlap_left;
if overlap_width <= 0 {
0.0
} else {
(overlap_width as f64) / (other.right as f64) * 100.0
}
}
} }