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

1
Cargo.lock generated
View File

@@ -3238,6 +3238,7 @@ version = "0.1.40"
dependencies = [
"clap",
"color-eyre",
"objc2-core-foundation",
"schemars 1.2.1",
"serde",
"serde_json_lenient",

View File

@@ -50,6 +50,11 @@ crate = "komorebi-client"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebi-layouts"
expression = "LicenseRef-Komorebi-2.0"
license-files = []
[[licenses.clarify]]
crate = "komorebic"
expression = "LicenseRef-Komorebi-2.0"

View File

@@ -15,7 +15,12 @@ tracing = { workspace = true }
# Optional dependencies
schemars = { workspace = true, optional = true }
windows = { workspace = true, optional = true }
objc2-core-foundation = { version = "0.3", default-features = false, features = [
"std",
"CFCGTypes",
], optional = true }
[features]
schemars = ["dep:schemars"]
win32 = ["dep:windows"]
darwin = ["dep:objc2-core-foundation"]

View File

@@ -6,11 +6,15 @@ use serde::Serialize;
use strum::Display;
use strum::EnumString;
#[cfg(feature = "win32")]
use super::CustomLayout;
use super::DefaultLayout;
use super::Rect;
#[cfg(feature = "win32")]
use super::custom_layout::Column;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplit;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplitWithCapacity;
use crate::default_layout::DEFAULT_RATIO;
use crate::default_layout::DEFAULT_SECONDARY_RATIO;
@@ -719,6 +723,7 @@ impl Arrangement for DefaultLayout {
}
}
#[cfg(feature = "win32")]
impl Arrangement for CustomLayout {
fn calculate(
&self,
@@ -857,6 +862,7 @@ pub enum Axis {
HorizontalAndVertical,
}
#[cfg(feature = "win32")]
#[must_use]
fn columns(area: &Rect, len: usize) -> Vec<Rect> {
columns_with_ratios(area, len, None)
@@ -931,6 +937,7 @@ fn columns_with_ratios(
layouts
}
#[cfg(feature = "win32")]
#[must_use]
fn rows(area: &Rect, len: usize) -> Vec<Rect> {
rows_with_ratios(area, len, None)

View File

@@ -1,8 +1,12 @@
use super::DefaultLayout;
use super::OperationDirection;
#[cfg(feature = "win32")]
use super::custom_layout::Column;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplit;
#[cfg(feature = "win32")]
use super::custom_layout::ColumnSplitWithCapacity;
#[cfg(feature = "win32")]
use super::custom_layout::CustomLayout;
use crate::default_layout::LayoutOptions;
@@ -400,6 +404,7 @@ fn grid_neighbor(
}
}
#[cfg(feature = "win32")]
impl Direction for CustomLayout {
fn index_in_direction(
&self,

View File

@@ -2,6 +2,7 @@ use serde::Deserialize;
use serde::Serialize;
use super::Arrangement;
#[cfg(feature = "win32")]
use super::CustomLayout;
use super::DefaultLayout;
use super::Direction;
@@ -10,6 +11,7 @@ use super::Direction;
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Layout {
Default(DefaultLayout),
#[cfg(feature = "win32")]
Custom(CustomLayout),
}
@@ -18,6 +20,7 @@ impl Layout {
pub fn as_boxed_direction(&self) -> Box<dyn Direction> {
match self {
Layout::Default(layout) => Box::new(*layout),
#[cfg(feature = "win32")]
Layout::Custom(layout) => Box::new(layout.clone()),
}
}
@@ -26,6 +29,7 @@ impl Layout {
pub fn as_boxed_arrangement(&self) -> Box<dyn Arrangement> {
match self {
Layout::Default(layout) => Box::new(*layout),
#[cfg(feature = "win32")]
Layout::Custom(layout) => Box::new(layout.clone()),
}
}

View File

@@ -8,6 +8,7 @@
//! behind the `win32` feature flag.
pub mod arrangement;
#[cfg(feature = "win32")]
pub mod custom_layout;
pub mod cycle_direction;
pub mod default_layout;
@@ -18,6 +19,7 @@ pub mod rect;
pub mod sizing;
pub use arrangement::*;
#[cfg(feature = "win32")]
pub use custom_layout::*;
pub use cycle_direction::*;
pub use default_layout::*;

View File

@@ -4,6 +4,15 @@ use serde::Serialize;
#[cfg(feature = "win32")]
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)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
/// 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 {
pub fn is_same_size_as(&self, rhs: &Self) -> bool {
self.right == rhs.right && self.bottom == rhs.bottom
@@ -110,4 +166,19 @@ impl Rect {
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
}
}
}