Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SwitchPresetWindowHeight and WindowHeight presets #655

Merged
merged 3 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 37 additions & 12 deletions niri-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,11 @@ pub struct Layout {
#[knuffel(child, default)]
pub border: Border,
#[knuffel(child, unwrap(children), default)]
pub preset_column_widths: Vec<PresetWidth>,
pub preset_column_widths: Vec<PresetSize>,
#[knuffel(child)]
pub default_column_width: Option<DefaultColumnWidth>,
pub default_column_width: Option<DefaultPresetSize>,
#[knuffel(child, unwrap(children), default)]
pub preset_window_heights: Vec<PresetSize>,
#[knuffel(child, unwrap(argument), default)]
pub center_focused_column: CenterFocusedColumn,
#[knuffel(child)]
Expand All @@ -416,6 +418,7 @@ impl Default for Layout {
always_center_single_column: false,
gaps: FloatOrInt(16.),
struts: Default::default(),
preset_window_heights: Default::default(),
}
}
}
Expand Down Expand Up @@ -624,13 +627,13 @@ impl Default for Cursor {
}

#[derive(knuffel::Decode, Debug, Clone, Copy, PartialEq)]
pub enum PresetWidth {
pub enum PresetSize {
Proportion(#[knuffel(argument)] f64),
Fixed(#[knuffel(argument)] i32),
}

#[derive(Debug, Clone, PartialEq)]
pub struct DefaultColumnWidth(pub Option<PresetWidth>);
pub struct DefaultPresetSize(pub Option<PresetSize>);

#[derive(knuffel::Decode, Debug, Default, Clone, Copy, PartialEq)]
pub struct Struts {
Expand Down Expand Up @@ -898,7 +901,7 @@ pub struct WindowRule {

// Rules applied at initial configure.
#[knuffel(child)]
pub default_column_width: Option<DefaultColumnWidth>,
pub default_column_width: Option<DefaultPresetSize>,
#[knuffel(child, unwrap(argument))]
pub open_on_output: Option<String>,
#[knuffel(child, unwrap(argument))]
Expand Down Expand Up @@ -1155,6 +1158,9 @@ pub enum Action {
#[knuffel(skip)]
ResetWindowHeightById(u64),
SwitchPresetColumnWidth,
SwitchPresetWindowHeight,
#[knuffel(skip)]
SwitchPresetWindowHeightById(u64),
MaximizeColumn,
SetColumnWidth(#[knuffel(argument, str)] SizeChange),
SwitchLayout(#[knuffel(argument, str)] LayoutSwitchTarget),
Expand Down Expand Up @@ -1266,6 +1272,12 @@ impl From<niri_ipc::Action> for Action {
niri_ipc::Action::ResetWindowHeight { id: None } => Self::ResetWindowHeight,
niri_ipc::Action::ResetWindowHeight { id: Some(id) } => Self::ResetWindowHeightById(id),
niri_ipc::Action::SwitchPresetColumnWidth {} => Self::SwitchPresetColumnWidth,
niri_ipc::Action::SwitchPresetWindowHeight { id: None } => {
Self::SwitchPresetWindowHeight
}
niri_ipc::Action::SwitchPresetWindowHeight { id: Some(id) } => {
Self::SwitchPresetWindowHeightById(id)
}
niri_ipc::Action::MaximizeColumn {} => Self::MaximizeColumn,
niri_ipc::Action::SetColumnWidth { change } => Self::SetColumnWidth(change),
niri_ipc::Action::SwitchLayout { layout } => Self::SwitchLayout(layout),
Expand Down Expand Up @@ -1882,7 +1894,7 @@ impl OutputName {
}
}

impl<S> knuffel::Decode<S> for DefaultColumnWidth
impl<S> knuffel::Decode<S> for DefaultPresetSize
where
S: knuffel::traits::ErrorSpan,
{
Expand All @@ -1902,7 +1914,7 @@ where
"expected no more than one child",
));
}
PresetWidth::decode_node(child, ctx).map(Some).map(Self)
PresetSize::decode_node(child, ctx).map(Some).map(Self)
} else {
Ok(Self(None))
}
Expand Down Expand Up @@ -2914,6 +2926,13 @@ mod tests {
fixed 1280
}

preset-window-heights {
proportion 0.25
proportion 0.5
fixed 960
fixed 1280
}

default-column-width { proportion 0.25; }

gaps 8
Expand Down Expand Up @@ -3104,14 +3123,20 @@ mod tests {
inactive_gradient: None,
},
preset_column_widths: vec![
PresetWidth::Proportion(0.25),
PresetWidth::Proportion(0.5),
PresetWidth::Fixed(960),
PresetWidth::Fixed(1280),
PresetSize::Proportion(0.25),
PresetSize::Proportion(0.5),
PresetSize::Fixed(960),
PresetSize::Fixed(1280),
],
default_column_width: Some(DefaultColumnWidth(Some(PresetWidth::Proportion(
default_column_width: Some(DefaultPresetSize(Some(PresetSize::Proportion(
0.25,
)))),
preset_window_heights: vec![
PresetSize::Proportion(0.25),
PresetSize::Proportion(0.5),
PresetSize::Fixed(960),
PresetSize::Fixed(1280),
],
gaps: FloatOrInt(8.),
struts: Struts {
left: FloatOrInt(1.),
Expand Down
8 changes: 8 additions & 0 deletions niri-ipc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,14 @@ pub enum Action {
},
/// Switch between preset column widths.
SwitchPresetColumnWidth {},
/// Switch between preset window heights.
SwitchPresetWindowHeight {
/// Id of the window whose height to switch.
///
/// If `None`, uses the focused window.
#[cfg_attr(feature = "clap", arg(long))]
id: Option<u64>,
},
/// Toggle the maximized state of the focused column.
MaximizeColumn {},
/// Change the width of the focused column.
Expand Down
6 changes: 5 additions & 1 deletion resources/default-config.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ layout {
// fixed 1920
}

// You can also customize the heights that "switch-preset-window-height" (Mod+Shift+R) toggles between.
// preset-window-heights { }

// You can change the default width of the new windows.
default-column-width { proportion 0.5; }
// If you leave the brackets empty, the windows themselves will decide their initial width.
Expand Down Expand Up @@ -427,7 +430,8 @@ binds {
// Mod+BracketRight { consume-or-expel-window-right; }

Mod+R { switch-preset-column-width; }
Mod+Shift+R { reset-window-height; }
Mod+Shift+R { switch-preset-window-height; }
Mod+Ctrl+R { reset-window-height; }
Mod+F { maximize-column; }
Mod+Shift+F { fullscreen-window; }
Mod+C { center-column; }
Expand Down
10 changes: 10 additions & 0 deletions src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,16 @@ impl State {
Action::SwitchPresetColumnWidth => {
self.niri.layout.toggle_width();
}
Action::SwitchPresetWindowHeight => {
self.niri.layout.toggle_window_height(None);
}
Action::SwitchPresetWindowHeightById(id) => {
let window = self.niri.layout.windows().find(|(_, m)| m.id().get() == id);
let window = window.map(|(_, m)| m.window.clone());
if let Some(window) = window {
self.niri.layout.toggle_window_height(Some(&window));
}
}
Action::CenterColumn => {
self.niri.layout.center_column();
// FIXME: granular
Expand Down
100 changes: 87 additions & 13 deletions src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ use std::mem;
use std::rc::Rc;
use std::time::Duration;

use niri_config::{CenterFocusedColumn, Config, FloatOrInt, Struts, Workspace as WorkspaceConfig};
use niri_config::{
CenterFocusedColumn, Config, FloatOrInt, PresetSize, Struts, Workspace as WorkspaceConfig,
};
use niri_ipc::SizeChange;
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
use smithay::backend::renderer::element::Id;
Expand Down Expand Up @@ -238,11 +240,12 @@ pub struct Options {
pub center_focused_column: CenterFocusedColumn,
pub always_center_single_column: bool,
/// Column widths that `toggle_width()` switches between.
pub preset_widths: Vec<ColumnWidth>,
pub preset_column_widths: Vec<ColumnWidth>,
/// Initial width for new columns.
pub default_width: Option<ColumnWidth>,
pub default_column_width: Option<ColumnWidth>,
/// Window height that `toggle_window_height()` switches between.
pub preset_window_heights: Vec<PresetSize>,
pub animations: niri_config::Animations,

// Debug flags.
pub disable_resize_throttling: bool,
pub disable_transactions: bool,
Expand All @@ -257,37 +260,47 @@ impl Default for Options {
border: Default::default(),
center_focused_column: Default::default(),
always_center_single_column: false,
preset_widths: vec![
preset_column_widths: vec![
ColumnWidth::Proportion(1. / 3.),
ColumnWidth::Proportion(0.5),
ColumnWidth::Proportion(2. / 3.),
],
default_width: None,
default_column_width: None,
animations: Default::default(),
disable_resize_throttling: false,
disable_transactions: false,
preset_window_heights: vec![
PresetSize::Proportion(1. / 3.),
PresetSize::Proportion(0.5),
PresetSize::Proportion(2. / 3.),
],
}
}
}

impl Options {
fn from_config(config: &Config) -> Self {
let layout = &config.layout;
let preset_column_widths = &layout.preset_column_widths;

let preset_widths = if preset_column_widths.is_empty() {
Options::default().preset_widths
let preset_column_widths = if layout.preset_column_widths.is_empty() {
Options::default().preset_column_widths
} else {
preset_column_widths
layout
.preset_column_widths
.iter()
.copied()
.map(ColumnWidth::from)
.collect()
};
let preset_window_heights = if layout.preset_window_heights.is_empty() {
Options::default().preset_window_heights
} else {
layout.preset_window_heights.clone()
};

// Missing default_column_width maps to Some(ColumnWidth::Proportion(0.5)),
// while present, but empty, maps to None.
let default_width = layout
let default_column_width = layout
.default_column_width
.as_ref()
.map(|w| w.0.map(ColumnWidth::from))
Expand All @@ -300,11 +313,12 @@ impl Options {
border: layout.border,
center_focused_column: layout.center_focused_column,
always_center_single_column: layout.always_center_single_column,
preset_widths,
default_width,
preset_column_widths,
default_column_width,
animations: config.animations.clone(),
disable_resize_throttling: config.debug.disable_resize_throttling,
disable_transactions: config.debug.disable_transactions,
preset_window_heights,
}
}

Expand Down Expand Up @@ -1937,6 +1951,23 @@ impl<W: LayoutElement> Layout<W> {
monitor.toggle_width();
}

pub fn toggle_window_height(&mut self, window: Option<&W::Id>) {
let workspace = if let Some(window) = window {
Some(
self.workspaces_mut()
.find(|ws| ws.has_window(window))
.unwrap(),
)
} else {
self.active_workspace_mut()
};

let Some(workspace) = workspace else {
return;
};
workspace.toggle_window_height(window);
}

pub fn toggle_full_width(&mut self) {
let Some(monitor) = self.active_monitor() else {
return;
Expand Down Expand Up @@ -3027,6 +3058,10 @@ mod tests {
},
MoveColumnToOutput(#[proptest(strategy = "1..=5u8")] u8),
SwitchPresetColumnWidth,
SwitchPresetWindowHeight {
#[proptest(strategy = "proptest::option::of(1..=5usize)")]
id: Option<usize>,
},
MaximizeColumn,
SetColumnWidth(#[proptest(strategy = "arbitrary_size_change()")] SizeChange),
SetWindowHeight {
Expand Down Expand Up @@ -3453,6 +3488,10 @@ mod tests {
Op::MoveWorkspaceDown => layout.move_workspace_down(),
Op::MoveWorkspaceUp => layout.move_workspace_up(),
Op::SwitchPresetColumnWidth => layout.toggle_width(),
Op::SwitchPresetWindowHeight { id } => {
let id = id.filter(|id| layout.has_window(id));
layout.toggle_window_height(id.as_ref());
}
Op::MaximizeColumn => layout.toggle_full_width(),
Op::SetColumnWidth(change) => layout.set_column_width(change),
Op::SetWindowHeight { id, change } => {
Expand Down Expand Up @@ -4415,6 +4454,41 @@ mod tests {
layout.verify_invariants();
}

#[test]
fn preset_height_change_removes_preset() {
let mut config = Config::default();
config.layout.preset_window_heights = vec![PresetSize::Fixed(1), PresetSize::Fixed(2)];

let mut layout = Layout::new(&config);

let ops = [
Op::AddOutput(1),
Op::AddWindow {
id: 1,
bbox: Rectangle::from_loc_and_size((0, 0), (1280, 200)),
min_max_size: Default::default(),
},
Op::AddWindow {
id: 2,
bbox: Rectangle::from_loc_and_size((0, 0), (1280, 200)),
min_max_size: Default::default(),
},
Op::ConsumeOrExpelWindowLeft,
Op::SwitchPresetWindowHeight { id: None },
Op::SwitchPresetWindowHeight { id: None },
];
for op in ops {
op.apply(&mut layout);
}

// Leave only one.
config.layout.preset_window_heights = vec![PresetSize::Fixed(1)];

layout.update_config(&config);

layout.verify_invariants();
}

#[test]
fn working_area_starts_at_physical_pixel() {
let struts = Struts {
Expand Down
Loading