mirror of
https://github.com/YaLTeR/niri.git
synced 2025-10-05 16:12:47 +02:00
layout: Store Layout directly in Options
This commit is contained in:
@@ -52,20 +52,23 @@ impl Layout {
|
||||
});
|
||||
|
||||
let options = Options {
|
||||
focus_ring: niri_config::FocusRing {
|
||||
off: true,
|
||||
layout: niri_config::Layout {
|
||||
focus_ring: niri_config::FocusRing {
|
||||
off: true,
|
||||
..Default::default()
|
||||
},
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 4.,
|
||||
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
|
||||
inactive_color: Color::from_rgba8_unpremul(50, 50, 50, 255),
|
||||
urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255),
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 4.,
|
||||
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
|
||||
inactive_color: Color::from_rgba8_unpremul(50, 50, 50, 255),
|
||||
urgent_color: Color::from_rgba8_unpremul(155, 0, 0, 255),
|
||||
active_gradient: None,
|
||||
inactive_gradient: None,
|
||||
urgent_gradient: None,
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let mut layout = niri::layout::Layout::with_options(clock.clone(), options);
|
||||
|
@@ -58,14 +58,17 @@ impl Tile {
|
||||
let Args { size, clock } = args;
|
||||
|
||||
let options = Options {
|
||||
focus_ring: niri_config::FocusRing {
|
||||
off: true,
|
||||
..Default::default()
|
||||
},
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 32.,
|
||||
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
|
||||
layout: niri_config::Layout {
|
||||
focus_ring: niri_config::FocusRing {
|
||||
off: true,
|
||||
..Default::default()
|
||||
},
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 32.,
|
||||
active_color: Color::from_rgba8_unpremul(255, 163, 72, 255),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
@@ -340,7 +340,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
}
|
||||
|
||||
pub fn new_window_toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> {
|
||||
let border_config = self.options.border.merged_with(&rules.border);
|
||||
let border_config = self.options.layout.border.merged_with(&rules.border);
|
||||
compute_toplevel_bounds(border_config, self.working_area.size)
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
|
||||
let available_size = self.working_area.size.w;
|
||||
|
||||
let len = self.options.preset_column_widths.len();
|
||||
let len = self.options.layout.preset_column_widths.len();
|
||||
let tile = &mut self.tiles[idx];
|
||||
let preset_idx = if let Some(idx) = tile.floating_preset_width_idx {
|
||||
(idx + if forwards { 1 } else { len - 1 }) % len
|
||||
@@ -643,6 +643,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
|
||||
let mut it = self
|
||||
.options
|
||||
.layout
|
||||
.preset_column_widths
|
||||
.iter()
|
||||
.map(|preset| resolve_preset_size(*preset, available_size));
|
||||
@@ -668,7 +669,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
}
|
||||
};
|
||||
|
||||
let preset = self.options.preset_column_widths[preset_idx];
|
||||
let preset = self.options.layout.preset_column_widths[preset_idx];
|
||||
self.set_window_width(Some(&id), SizeChange::from(preset), true);
|
||||
|
||||
self.tiles[idx].floating_preset_width_idx = Some(preset_idx);
|
||||
@@ -693,7 +694,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
|
||||
let available_size = self.working_area.size.h;
|
||||
|
||||
let len = self.options.preset_window_heights.len();
|
||||
let len = self.options.layout.preset_window_heights.len();
|
||||
let tile = &mut self.tiles[idx];
|
||||
let preset_idx = if let Some(idx) = tile.floating_preset_height_idx {
|
||||
(idx + if forwards { 1 } else { len - 1 }) % len
|
||||
@@ -703,6 +704,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
|
||||
let mut it = self
|
||||
.options
|
||||
.layout
|
||||
.preset_window_heights
|
||||
.iter()
|
||||
.map(|preset| resolve_preset_size(*preset, available_size));
|
||||
@@ -728,7 +730,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
}
|
||||
};
|
||||
|
||||
let preset = self.options.preset_window_heights[preset_idx];
|
||||
let preset = self.options.layout.preset_window_heights[preset_idx];
|
||||
self.set_window_height(Some(&id), SizeChange::from(preset), true);
|
||||
|
||||
let tile = &mut self.tiles[idx];
|
||||
@@ -1156,7 +1158,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
.map(|resize| resize.data);
|
||||
win.set_interactive_resize(resize_data);
|
||||
|
||||
let border_config = self.options.border.merged_with(&win.rules().border);
|
||||
let border_config = self.options.layout.border.merged_with(&win.rules().border);
|
||||
let bounds = compute_toplevel_bounds(border_config, self.working_area.size);
|
||||
win.set_bounds(bounds);
|
||||
|
||||
@@ -1220,7 +1222,7 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
height: Option<PresetSize>,
|
||||
rules: &ResolvedWindowRules,
|
||||
) -> Size<i32, Logical> {
|
||||
let border = self.options.border.merged_with(&rules.border);
|
||||
let border = self.options.layout.border.merged_with(&rules.border);
|
||||
|
||||
let resolve = |size: Option<PresetSize>, working_area_size: f64| {
|
||||
if let Some(size) = size {
|
||||
@@ -1317,10 +1319,10 @@ impl<W: LayoutElement> FloatingSpace<W> {
|
||||
tile.verify_invariants();
|
||||
|
||||
if let Some(idx) = tile.floating_preset_width_idx {
|
||||
assert!(idx < self.options.preset_column_widths.len());
|
||||
assert!(idx < self.options.layout.preset_column_widths.len());
|
||||
}
|
||||
if let Some(idx) = tile.floating_preset_height_idx {
|
||||
assert!(idx < self.options.preset_window_heights.len());
|
||||
assert!(idx < self.options.layout.preset_window_heights.len());
|
||||
}
|
||||
|
||||
assert!(
|
||||
|
@@ -40,8 +40,7 @@ use std::time::Duration;
|
||||
use monitor::{InsertHint, InsertPosition, InsertWorkspace, MonitorAddWindowTarget};
|
||||
use niri_config::utils::MergeWith as _;
|
||||
use niri_config::{
|
||||
CenterFocusedColumn, Config, CornerRadius, PresetSize, Struts, Workspace as WorkspaceConfig,
|
||||
WorkspaceReference,
|
||||
Config, CornerRadius, PresetSize, Workspace as WorkspaceConfig, WorkspaceReference,
|
||||
};
|
||||
use niri_ipc::{ColumnDisplay, PositionChange, SizeChange, WindowLayout};
|
||||
use scrolling::{Column, ColumnWidth};
|
||||
@@ -334,27 +333,9 @@ enum MonitorSet<W: LayoutElement> {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Default, Clone, PartialEq)]
|
||||
pub struct Options {
|
||||
/// Padding around windows in logical pixels.
|
||||
pub gaps: f64,
|
||||
/// Extra padding around the working area in logical pixels.
|
||||
pub struts: Struts,
|
||||
pub focus_ring: niri_config::FocusRing,
|
||||
pub border: niri_config::Border,
|
||||
pub shadow: niri_config::Shadow,
|
||||
pub tab_indicator: niri_config::TabIndicator,
|
||||
pub insert_hint: niri_config::InsertHint,
|
||||
pub center_focused_column: CenterFocusedColumn,
|
||||
pub always_center_single_column: bool,
|
||||
pub empty_workspace_above_first: bool,
|
||||
pub default_column_display: ColumnDisplay,
|
||||
/// Column or window widths that `toggle_width()` switches between.
|
||||
pub preset_column_widths: Vec<PresetSize>,
|
||||
/// Initial width for new columns.
|
||||
pub default_column_width: Option<PresetSize>,
|
||||
/// Window height that `toggle_window_height()` switches between.
|
||||
pub preset_window_heights: Vec<PresetSize>,
|
||||
pub layout: niri_config::Layout,
|
||||
pub animations: niri_config::Animations,
|
||||
pub gestures: niri_config::Gestures,
|
||||
pub overview: niri_config::Overview,
|
||||
@@ -364,41 +345,6 @@ pub struct Options {
|
||||
pub deactivate_unfocused_windows: bool,
|
||||
}
|
||||
|
||||
impl Default for Options {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
gaps: 16.,
|
||||
struts: Default::default(),
|
||||
focus_ring: Default::default(),
|
||||
border: Default::default(),
|
||||
shadow: Default::default(),
|
||||
tab_indicator: Default::default(),
|
||||
insert_hint: Default::default(),
|
||||
center_focused_column: Default::default(),
|
||||
always_center_single_column: false,
|
||||
empty_workspace_above_first: false,
|
||||
default_column_display: ColumnDisplay::Normal,
|
||||
preset_column_widths: vec![
|
||||
PresetSize::Proportion(1. / 3.),
|
||||
PresetSize::Proportion(0.5),
|
||||
PresetSize::Proportion(2. / 3.),
|
||||
],
|
||||
default_column_width: None,
|
||||
animations: Default::default(),
|
||||
gestures: Default::default(),
|
||||
overview: 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.),
|
||||
],
|
||||
deactivate_unfocused_windows: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug)]
|
||||
enum InteractiveMoveState<W: LayoutElement> {
|
||||
@@ -620,49 +566,23 @@ impl HitType {
|
||||
|
||||
impl Options {
|
||||
fn from_config(config: &Config) -> Self {
|
||||
let layout = config.resolve_layout();
|
||||
|
||||
let preset_column_widths = if layout.preset_column_widths.is_empty() {
|
||||
Options::default().preset_column_widths
|
||||
} else {
|
||||
layout.preset_column_widths.clone()
|
||||
};
|
||||
let preset_window_heights = if layout.preset_window_heights.is_empty() {
|
||||
Options::default().preset_window_heights
|
||||
} else {
|
||||
layout.preset_window_heights.clone()
|
||||
};
|
||||
|
||||
Self {
|
||||
gaps: layout.gaps,
|
||||
struts: layout.struts,
|
||||
focus_ring: layout.focus_ring,
|
||||
border: layout.border,
|
||||
shadow: layout.shadow,
|
||||
tab_indicator: layout.tab_indicator,
|
||||
insert_hint: layout.insert_hint,
|
||||
center_focused_column: layout.center_focused_column,
|
||||
always_center_single_column: layout.always_center_single_column,
|
||||
empty_workspace_above_first: layout.empty_workspace_above_first,
|
||||
default_column_display: layout.default_column_display,
|
||||
preset_column_widths,
|
||||
default_column_width: layout.default_column_width,
|
||||
layout: config.resolve_layout(),
|
||||
animations: config.animations.clone(),
|
||||
gestures: config.gestures,
|
||||
overview: config.overview,
|
||||
disable_resize_throttling: config.debug.disable_resize_throttling,
|
||||
disable_transactions: config.debug.disable_transactions,
|
||||
deactivate_unfocused_windows: config.debug.deactivate_unfocused_windows,
|
||||
preset_window_heights,
|
||||
}
|
||||
}
|
||||
|
||||
fn adjusted_for_scale(mut self, scale: f64) -> Self {
|
||||
let round = |logical: f64| round_logical_in_physical_max1(scale, logical);
|
||||
|
||||
self.gaps = round(self.gaps);
|
||||
self.focus_ring.width = round(self.focus_ring.width);
|
||||
self.border.width = round(self.border.width);
|
||||
self.layout.gaps = round(self.layout.gaps);
|
||||
self.layout.focus_ring.width = round(self.layout.focus_ring.width);
|
||||
self.layout.border.width = round(self.layout.border.width);
|
||||
|
||||
self
|
||||
}
|
||||
@@ -775,7 +695,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
// workspaces set up across multiple monitors. Without this check, the
|
||||
// first monitor to connect can end up with the first empty workspace
|
||||
// focused instead of the first named workspace.
|
||||
&& !(self.options.empty_workspace_above_first
|
||||
&& !(self.options.layout.empty_workspace_above_first
|
||||
&& primary.active_workspace_idx == 1)
|
||||
{
|
||||
primary.active_workspace_idx =
|
||||
@@ -790,7 +710,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
// takes care of this.
|
||||
|
||||
if stopped_primary_ws_switch
|
||||
|| (primary.options.empty_workspace_above_first
|
||||
|| (primary.options.layout.empty_workspace_above_first
|
||||
&& primary.workspaces.len() == 2)
|
||||
{
|
||||
primary.clean_up_workspaces();
|
||||
@@ -810,7 +730,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
self.options.clone(),
|
||||
));
|
||||
|
||||
if self.options.empty_workspace_above_first && workspaces.len() > 1 {
|
||||
if self.options.layout.empty_workspace_above_first && workspaces.len() > 1 {
|
||||
workspaces.insert(
|
||||
0,
|
||||
Workspace::new(output.clone(), self.clock.clone(), self.options.clone()),
|
||||
@@ -844,7 +764,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
));
|
||||
|
||||
let mut active_workspace_idx = 0;
|
||||
if self.options.empty_workspace_above_first && workspaces.len() > 1 {
|
||||
if self.options.layout.empty_workspace_above_first && workspaces.len() > 1 {
|
||||
workspaces.insert(
|
||||
0,
|
||||
Workspace::new(output.clone(), self.clock.clone(), self.options.clone()),
|
||||
@@ -944,7 +864,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
|
||||
// If empty_workspace_above_first is set and the first workspace is now no
|
||||
// longer empty, add a new empty workspace on top.
|
||||
if primary.options.empty_workspace_above_first
|
||||
if primary.options.layout.empty_workspace_above_first
|
||||
&& primary.workspaces[0].has_windows_or_name()
|
||||
{
|
||||
primary.add_workspace_top();
|
||||
@@ -1242,7 +1162,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
|
||||
// Special case handling when empty_workspace_above_first is set and all
|
||||
// workspaces are empty.
|
||||
if mon.options.empty_workspace_above_first
|
||||
if mon.options.layout.empty_workspace_above_first
|
||||
&& mon.workspaces.len() == 2
|
||||
&& mon.workspace_switch.is_none()
|
||||
{
|
||||
@@ -2637,7 +2557,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
!monitor.workspaces.last().unwrap().has_windows(),
|
||||
"monitor must have an empty workspace in the end"
|
||||
);
|
||||
if monitor.options.empty_workspace_above_first {
|
||||
if monitor.options.layout.empty_workspace_above_first {
|
||||
assert!(
|
||||
!monitor.workspaces.first().unwrap().has_windows(),
|
||||
"first workspace must be empty when empty_workspace_above_first is set"
|
||||
@@ -2648,14 +2568,14 @@ impl<W: LayoutElement> Layout<W> {
|
||||
monitor.workspaces.last().unwrap().name.is_none(),
|
||||
"monitor must have an unnamed workspace in the end"
|
||||
);
|
||||
if monitor.options.empty_workspace_above_first {
|
||||
if monitor.options.layout.empty_workspace_above_first {
|
||||
assert!(
|
||||
monitor.workspaces.first().unwrap().name.is_none(),
|
||||
"first workspace must be unnamed when empty_workspace_above_first is set"
|
||||
)
|
||||
}
|
||||
|
||||
if monitor.options.empty_workspace_above_first {
|
||||
if monitor.options.layout.empty_workspace_above_first {
|
||||
assert!(
|
||||
monitor.workspaces.len() != 2,
|
||||
"if empty_workspace_above_first is set there must be just 1 or 3+ workspaces"
|
||||
@@ -2665,7 +2585,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
// If there's no workspace switch in progress, there can't be any non-last non-active
|
||||
// empty workspaces. If empty_workspace_above_first is set then the first workspace
|
||||
// will be empty too.
|
||||
let pre_skip = if monitor.options.empty_workspace_above_first {
|
||||
let pre_skip = if monitor.options.layout.empty_workspace_above_first {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@@ -3107,7 +3027,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
let mon = &mut monitors[mon_idx];
|
||||
|
||||
let mut insert_idx = 0;
|
||||
if mon.options.empty_workspace_above_first {
|
||||
if mon.options.layout.empty_workspace_above_first {
|
||||
// need to insert new empty workspace on top
|
||||
mon.add_workspace_top();
|
||||
insert_idx += 1;
|
||||
@@ -3622,7 +3542,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
// Insert a new empty workspace.
|
||||
current.add_workspace_bottom();
|
||||
}
|
||||
if current.options.empty_workspace_above_first && current.active_workspace_idx == 0 {
|
||||
if current.options.layout.empty_workspace_above_first && current.active_workspace_idx == 0 {
|
||||
current.add_workspace_top();
|
||||
}
|
||||
|
||||
@@ -3642,7 +3562,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
|
||||
target.previous_workspace_id = Some(target.workspaces[target.active_workspace_idx].id());
|
||||
|
||||
if target.options.empty_workspace_above_first && target.workspaces.len() == 1 {
|
||||
if target.options.layout.empty_workspace_above_first && target.workspaces.len() == 1 {
|
||||
// Insert a new empty workspace on top to prepare for insertion of new workspace.
|
||||
target.add_workspace_top();
|
||||
}
|
||||
@@ -3711,7 +3631,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
|
||||
let mut ws = current.workspaces.remove(old_idx);
|
||||
|
||||
if current.options.empty_workspace_above_first && old_idx == 0 {
|
||||
if current.options.layout.empty_workspace_above_first && old_idx == 0 {
|
||||
current.add_workspace_top();
|
||||
}
|
||||
|
||||
@@ -3728,7 +3648,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
|
||||
target.previous_workspace_id = Some(target.workspaces[target.active_workspace_idx].id());
|
||||
|
||||
if target.options.empty_workspace_above_first && target.workspaces.len() == 1 {
|
||||
if target.options.layout.empty_workspace_above_first && target.workspaces.len() == 1 {
|
||||
// Insert a new empty workspace on top to prepare for insertion of new workspace.
|
||||
target.add_workspace_top();
|
||||
}
|
||||
@@ -4480,7 +4400,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
.position(|ws| ws.id() == ws_id)
|
||||
.unwrap(),
|
||||
InsertWorkspace::NewAt(ws_idx) => {
|
||||
if self.options.empty_workspace_above_first && ws_idx == 0 {
|
||||
if self.options.layout.empty_workspace_above_first && ws_idx == 0 {
|
||||
// Reuse the top empty workspace.
|
||||
0
|
||||
} else if mon.workspaces.len() - 1 <= ws_idx {
|
||||
@@ -4813,7 +4733,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
} = &mut self.monitor_set
|
||||
{
|
||||
let monitor = &mut monitors[*active_monitor_idx];
|
||||
if self.options.empty_workspace_above_first
|
||||
if self.options.layout.empty_workspace_above_first
|
||||
&& monitor
|
||||
.workspaces
|
||||
.first()
|
||||
@@ -5242,7 +5162,7 @@ impl<W: LayoutElement> Layout<W> {
|
||||
|
||||
// Add border width since ColumnWidth includes borders.
|
||||
let rules = window.rules();
|
||||
let border = self.options.border.merged_with(&rules.border);
|
||||
let border = self.options.layout.border.merged_with(&rules.border);
|
||||
if !border.off {
|
||||
fixed += border.width * 2.;
|
||||
}
|
||||
|
@@ -293,7 +293,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
active_workspace_idx: 0,
|
||||
previous_workspace_id: None,
|
||||
insert_hint: None,
|
||||
insert_hint_element: InsertHintElement::new(options.insert_hint),
|
||||
insert_hint_element: InsertHintElement::new(options.layout.insert_hint),
|
||||
insert_hint_render_loc: None,
|
||||
overview_open: false,
|
||||
overview_progress: None,
|
||||
@@ -463,7 +463,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
if workspace_idx == self.workspaces.len() - 1 {
|
||||
self.add_workspace_bottom();
|
||||
}
|
||||
if self.options.empty_workspace_above_first && workspace_idx == 0 {
|
||||
if self.options.layout.empty_workspace_above_first && workspace_idx == 0 {
|
||||
self.add_workspace_top();
|
||||
workspace_idx += 1;
|
||||
}
|
||||
@@ -522,7 +522,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
self.add_workspace_bottom();
|
||||
}
|
||||
|
||||
if self.options.empty_workspace_above_first && workspace_idx == 0 {
|
||||
if self.options.layout.empty_workspace_above_first && workspace_idx == 0 {
|
||||
self.add_workspace_top();
|
||||
workspace_idx += 1;
|
||||
}
|
||||
@@ -562,7 +562,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
pub fn clean_up_workspaces(&mut self) {
|
||||
assert!(self.workspace_switch.is_none());
|
||||
|
||||
let range_start = if self.options.empty_workspace_above_first {
|
||||
let range_start = if self.options.layout.empty_workspace_above_first {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
@@ -582,7 +582,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
|
||||
// Special case handling when empty_workspace_above_first is set and all workspaces
|
||||
// are empty.
|
||||
if self.options.empty_workspace_above_first && self.workspaces.len() == 2 {
|
||||
if self.options.layout.empty_workspace_above_first && self.workspaces.len() == 2 {
|
||||
assert!(!self.workspaces[0].has_windows_or_name());
|
||||
assert!(!self.workspaces[1].has_windows_or_name());
|
||||
self.workspaces.remove(1);
|
||||
@@ -1023,10 +1023,11 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
}
|
||||
|
||||
pub fn update_config(&mut self, options: Rc<Options>) {
|
||||
if self.options.empty_workspace_above_first != options.empty_workspace_above_first
|
||||
if self.options.layout.empty_workspace_above_first
|
||||
!= options.layout.empty_workspace_above_first
|
||||
&& self.workspaces.len() > 1
|
||||
{
|
||||
if options.empty_workspace_above_first {
|
||||
if options.layout.empty_workspace_above_first {
|
||||
self.add_workspace_top();
|
||||
} else if self.workspace_switch.is_none() && self.active_workspace_idx != 0 {
|
||||
self.workspaces.remove(0);
|
||||
@@ -1038,7 +1039,8 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
ws.update_config(options.clone());
|
||||
}
|
||||
|
||||
self.insert_hint_element.update_config(options.insert_hint);
|
||||
self.insert_hint_element
|
||||
.update_config(options.layout.insert_hint);
|
||||
|
||||
self.options = options;
|
||||
}
|
||||
@@ -1074,7 +1076,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
self.add_workspace_bottom();
|
||||
}
|
||||
|
||||
if self.options.empty_workspace_above_first && self.active_workspace_idx == 0 {
|
||||
if self.options.layout.empty_workspace_above_first && self.active_workspace_idx == 0 {
|
||||
self.add_workspace_top();
|
||||
new_idx += 1;
|
||||
}
|
||||
@@ -1100,7 +1102,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
self.add_workspace_bottom();
|
||||
}
|
||||
|
||||
if self.options.empty_workspace_above_first && new_idx == 0 {
|
||||
if self.options.layout.empty_workspace_above_first && new_idx == 0 {
|
||||
self.add_workspace_top();
|
||||
new_idx += 1;
|
||||
}
|
||||
@@ -1132,7 +1134,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
self.add_workspace_bottom();
|
||||
}
|
||||
|
||||
if self.options.empty_workspace_above_first && old_idx == 0 {
|
||||
if self.options.layout.empty_workspace_above_first && old_idx == 0 {
|
||||
self.add_workspace_top();
|
||||
new_idx += 1;
|
||||
}
|
||||
@@ -1142,7 +1144,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
self.add_workspace_bottom();
|
||||
}
|
||||
|
||||
if self.options.empty_workspace_above_first && new_idx == 0 {
|
||||
if self.options.layout.empty_workspace_above_first && new_idx == 0 {
|
||||
self.add_workspace_top();
|
||||
new_idx += 1;
|
||||
}
|
||||
@@ -1464,7 +1466,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
) -> impl Iterator<Item = MonitorRenderElement<R>> {
|
||||
let mut rv = None;
|
||||
|
||||
if !self.options.insert_hint.off {
|
||||
if !self.options.layout.insert_hint.off {
|
||||
if let Some(render_loc) = self.insert_hint_render_loc {
|
||||
if let InsertWorkspace::NewAt(_) = render_loc.workspace {
|
||||
let iter = self
|
||||
@@ -1525,7 +1527,7 @@ impl<W: LayoutElement> Monitor<W> {
|
||||
|
||||
// Draw the insert hint.
|
||||
let mut insert_hint = None;
|
||||
if !self.options.insert_hint.off {
|
||||
if !self.options.layout.insert_hint.off {
|
||||
if let Some(render_loc) = self.insert_hint_render_loc {
|
||||
if let InsertWorkspace::Existing(workspace_id) = render_loc.workspace {
|
||||
insert_hint = Some((
|
||||
|
@@ -276,7 +276,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
clock: Clock,
|
||||
options: Rc<Options>,
|
||||
) -> Self {
|
||||
let working_area = compute_working_area(parent_area, scale, options.struts);
|
||||
let working_area = compute_working_area(parent_area, scale, options.layout.struts);
|
||||
|
||||
Self {
|
||||
columns: Vec::new(),
|
||||
@@ -303,7 +303,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
scale: f64,
|
||||
options: Rc<Options>,
|
||||
) {
|
||||
let working_area = compute_working_area(parent_area, scale, options.struts);
|
||||
let working_area = compute_working_area(parent_area, scale, options.layout.struts);
|
||||
|
||||
for (column, data) in zip(&mut self.columns, &mut self.data) {
|
||||
column.update_config(view_size, working_area, scale, options.clone());
|
||||
@@ -444,14 +444,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
}
|
||||
|
||||
pub fn new_window_toplevel_bounds(&self, rules: &ResolvedWindowRules) -> Size<i32, Logical> {
|
||||
let border_config = self.options.border.merged_with(&rules.border);
|
||||
let border_config = self.options.layout.border.merged_with(&rules.border);
|
||||
|
||||
let display_mode = rules
|
||||
.default_column_display
|
||||
.unwrap_or(self.options.default_column_display);
|
||||
.unwrap_or(self.options.layout.default_column_display);
|
||||
let will_tab = display_mode == ColumnDisplay::Tabbed;
|
||||
let extra_size = if will_tab {
|
||||
TabIndicator::new(self.options.tab_indicator).extra_size(1, self.scale)
|
||||
TabIndicator::new(self.options.layout.tab_indicator).extra_size(1, self.scale)
|
||||
} else {
|
||||
Size::from((0., 0.))
|
||||
};
|
||||
@@ -460,7 +460,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
border_config,
|
||||
self.working_area.size,
|
||||
extra_size,
|
||||
self.options.gaps,
|
||||
self.options.layout.gaps,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -470,14 +470,14 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
height: Option<PresetSize>,
|
||||
rules: &ResolvedWindowRules,
|
||||
) -> Size<i32, Logical> {
|
||||
let border = self.options.border.merged_with(&rules.border);
|
||||
let border = self.options.layout.border.merged_with(&rules.border);
|
||||
|
||||
let display_mode = rules
|
||||
.default_column_display
|
||||
.unwrap_or(self.options.default_column_display);
|
||||
.unwrap_or(self.options.layout.default_column_display);
|
||||
let will_tab = display_mode == ColumnDisplay::Tabbed;
|
||||
let extra = if will_tab {
|
||||
TabIndicator::new(self.options.tab_indicator).extra_size(1, self.scale)
|
||||
TabIndicator::new(self.options.layout.tab_indicator).extra_size(1, self.scale)
|
||||
} else {
|
||||
Size::from((0., 0.))
|
||||
};
|
||||
@@ -500,7 +500,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
0
|
||||
};
|
||||
|
||||
let mut full_height = self.working_area.size.h - self.options.gaps * 2.;
|
||||
let mut full_height = self.working_area.size.h - self.options.layout.gaps * 2.;
|
||||
if !border.off {
|
||||
full_height -= border.width * 2.;
|
||||
}
|
||||
@@ -524,8 +524,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
}
|
||||
|
||||
pub fn is_centering_focused_column(&self) -> bool {
|
||||
self.options.center_focused_column == CenterFocusedColumn::Always
|
||||
|| (self.options.always_center_single_column && self.columns.len() <= 1)
|
||||
self.options.layout.center_focused_column == CenterFocusedColumn::Always
|
||||
|| (self.options.layout.always_center_single_column && self.columns.len() <= 1)
|
||||
}
|
||||
|
||||
fn compute_new_view_offset_fit(
|
||||
@@ -546,7 +546,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
self.working_area.size.w,
|
||||
col_x,
|
||||
width,
|
||||
self.options.gaps,
|
||||
self.options.layout.gaps,
|
||||
);
|
||||
|
||||
// Non-fullscreen windows are always offset at least by the working area position.
|
||||
@@ -606,7 +606,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
return self.compute_new_view_offset_for_column_centered(target_x, idx);
|
||||
}
|
||||
|
||||
match self.options.center_focused_column {
|
||||
match self.options.layout.center_focused_column {
|
||||
CenterFocusedColumn::Always => {
|
||||
self.compute_new_view_offset_for_column_centered(target_x, idx)
|
||||
}
|
||||
@@ -639,7 +639,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
} else {
|
||||
// Source is right from target.
|
||||
source_col_x - target_col_x + source_col_width
|
||||
} + self.options.gaps * 2.;
|
||||
} + self.options.layout.gaps * 2.;
|
||||
|
||||
// If it fits together, do a normal animation, otherwise center the new column.
|
||||
if total_width <= self.working_area.size.w {
|
||||
@@ -783,8 +783,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let x = pos.x + self.view_pos();
|
||||
|
||||
// Aim for the center of the gap.
|
||||
let x = x + self.options.gaps / 2.;
|
||||
let y = pos.y + self.options.gaps / 2.;
|
||||
let x = x + self.options.layout.gaps / 2.;
|
||||
let y = pos.y + self.options.layout.gaps / 2.;
|
||||
|
||||
// Insert position is before the first column.
|
||||
if x < 0. {
|
||||
@@ -2224,7 +2224,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let mut leftmost_col_x = None;
|
||||
let mut active_col_x = None;
|
||||
|
||||
let gap = self.options.gaps;
|
||||
let gap = self.options.layout.gaps;
|
||||
let col_xs = self.column_xs(self.data.iter().copied());
|
||||
for (idx, col_x) in col_xs.take(self.columns.len()).enumerate() {
|
||||
if col_x < view_x + working_x + gap {
|
||||
@@ -2274,7 +2274,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
// HACK: pass a self.data iterator in manually as a workaround for the lack of method partial
|
||||
// borrowing. Note that this method's return value does not borrow the entire &Self!
|
||||
fn column_xs(&self, data: impl Iterator<Item = ColumnData>) -> impl Iterator<Item = f64> {
|
||||
let gaps = self.options.gaps;
|
||||
let gaps = self.options.layout.gaps;
|
||||
let mut x = 0.;
|
||||
|
||||
// Chain with a dummy value to be able to get one past all columns' X.
|
||||
@@ -2408,25 +2408,29 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let mut hint_area = match position {
|
||||
InsertPosition::NewColumn(column_index) => {
|
||||
if column_index == 0 || column_index == self.columns.len() {
|
||||
let size =
|
||||
Size::from((300., self.working_area.size.h - self.options.gaps * 2.));
|
||||
let size = Size::from((
|
||||
300.,
|
||||
self.working_area.size.h - self.options.layout.gaps * 2.,
|
||||
));
|
||||
let mut loc = Point::from((
|
||||
self.column_x(column_index),
|
||||
self.working_area.loc.y + self.options.gaps,
|
||||
self.working_area.loc.y + self.options.layout.gaps,
|
||||
));
|
||||
if column_index == 0 && !self.columns.is_empty() {
|
||||
loc.x -= size.w + self.options.gaps;
|
||||
loc.x -= size.w + self.options.layout.gaps;
|
||||
}
|
||||
Rectangle::new(loc, size)
|
||||
} else if column_index > self.columns.len() {
|
||||
error!("insert hint column index is out of range");
|
||||
return None;
|
||||
} else {
|
||||
let size =
|
||||
Size::from((300., self.working_area.size.h - self.options.gaps * 2.));
|
||||
let size = Size::from((
|
||||
300.,
|
||||
self.working_area.size.h - self.options.layout.gaps * 2.,
|
||||
));
|
||||
let loc = Point::from((
|
||||
self.column_x(column_index) - size.w / 2. - self.options.gaps / 2.,
|
||||
self.working_area.loc.y + self.options.gaps,
|
||||
self.column_x(column_index) - size.w / 2. - self.options.layout.gaps / 2.,
|
||||
self.working_area.loc.y + self.options.layout.gaps,
|
||||
));
|
||||
Rectangle::new(loc, size)
|
||||
}
|
||||
@@ -2462,9 +2466,9 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
if tile_index == 0 {
|
||||
(150., top)
|
||||
} else if tile_index == col.tiles.len() {
|
||||
(150., top - self.options.gaps - 150.)
|
||||
(150., top - self.options.layout.gaps - 150.)
|
||||
} else {
|
||||
(300., top - self.options.gaps / 2. - 150.)
|
||||
(300., top - self.options.layout.gaps / 2. - 150.)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2716,7 +2720,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let mut active_col_x = None;
|
||||
let mut counted_non_active_column = false;
|
||||
|
||||
let gap = self.options.gaps;
|
||||
let gap = self.options.layout.gaps;
|
||||
let col_xs = self.column_xs(self.data.iter().copied());
|
||||
for (idx, col_x) in col_xs.take(self.columns.len()).enumerate() {
|
||||
if col_x < view_x + working_x + gap {
|
||||
@@ -3051,7 +3055,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
let (leftmost, rightmost) = if self.columns.is_empty() {
|
||||
(0., 0.)
|
||||
} else {
|
||||
let gaps = self.options.gaps;
|
||||
let gaps = self.options.layout.gaps;
|
||||
|
||||
let mut leftmost = -self.working_area.size.w;
|
||||
|
||||
@@ -3147,17 +3151,17 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
};
|
||||
snapping_points.push(Snap { view_pos, col_idx });
|
||||
|
||||
col_x += col_w + self.options.gaps;
|
||||
col_x += col_w + self.options.layout.gaps;
|
||||
}
|
||||
} else {
|
||||
let center_on_overflow = matches!(
|
||||
self.options.center_focused_column,
|
||||
self.options.layout.center_focused_column,
|
||||
CenterFocusedColumn::OnOverflow
|
||||
);
|
||||
|
||||
let view_width = self.view_size.w;
|
||||
let working_area_width = self.working_area.size.w;
|
||||
let gaps = self.options.gaps;
|
||||
let gaps = self.options.layout.gaps;
|
||||
|
||||
let snap_points =
|
||||
|col_x, col: &Column<W>, prev_col_w: Option<f64>, next_col_w: Option<f64>| {
|
||||
@@ -3297,8 +3301,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let padding =
|
||||
((self.working_area.size.w - col_w) / 2.).clamp(0., self.options.gaps);
|
||||
let padding = ((self.working_area.size.w - col_w) / 2.)
|
||||
.clamp(0., self.options.layout.gaps);
|
||||
if target_snap.view_pos + left_strut + self.working_area.size.w
|
||||
< col_x + col_w + padding
|
||||
{
|
||||
@@ -3319,8 +3323,8 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let padding =
|
||||
((self.working_area.size.w - col_w) / 2.).clamp(0., self.options.gaps);
|
||||
let padding = ((self.working_area.size.w - col_w) / 2.)
|
||||
.clamp(0., self.options.layout.gaps);
|
||||
if col_x - padding < target_snap.view_pos + left_strut {
|
||||
break;
|
||||
}
|
||||
@@ -3548,12 +3552,12 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
|
||||
win.set_interactive_resize(col_resize_data);
|
||||
|
||||
let border_config = self.options.border.merged_with(&win.rules().border);
|
||||
let border_config = self.options.layout.border.merged_with(&win.rules().border);
|
||||
let bounds = compute_toplevel_bounds(
|
||||
border_config,
|
||||
self.working_area.size,
|
||||
extra_size,
|
||||
self.options.gaps,
|
||||
self.options.layout.gaps,
|
||||
);
|
||||
win.set_bounds(bounds);
|
||||
|
||||
@@ -3614,7 +3618,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
|
||||
assert_eq!(self.columns.len(), self.data.len());
|
||||
assert_eq!(
|
||||
self.working_area,
|
||||
compute_working_area(self.parent_area, self.scale, self.options.struts)
|
||||
compute_working_area(self.parent_area, self.scale, self.options.layout.struts)
|
||||
);
|
||||
|
||||
if !self.columns.is_empty() {
|
||||
@@ -3802,7 +3806,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
.window()
|
||||
.rules()
|
||||
.default_column_display
|
||||
.unwrap_or(options.default_column_display);
|
||||
.unwrap_or(options.layout.default_column_display);
|
||||
|
||||
let mut rv = Self {
|
||||
tiles: vec![],
|
||||
@@ -3813,7 +3817,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
is_full_width,
|
||||
is_pending_fullscreen: false,
|
||||
display_mode,
|
||||
tab_indicator: TabIndicator::new(options.tab_indicator),
|
||||
tab_indicator: TabIndicator::new(options.layout.tab_indicator),
|
||||
move_animation: None,
|
||||
view_size,
|
||||
working_area,
|
||||
@@ -3832,7 +3836,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
// Animate the tab indicator for new columns.
|
||||
if display_mode == ColumnDisplay::Tabbed
|
||||
&& !rv.options.tab_indicator.hide_when_single_tab
|
||||
&& !rv.options.layout.tab_indicator.hide_when_single_tab
|
||||
&& !rv.is_fullscreen()
|
||||
{
|
||||
// Usually new columns are created together with window movement actions. For new
|
||||
@@ -3858,27 +3862,27 @@ impl<W: LayoutElement> Column<W> {
|
||||
}
|
||||
|
||||
// If preset widths changed, clear our stored preset index.
|
||||
if self.options.preset_column_widths != options.preset_column_widths {
|
||||
if self.options.layout.preset_column_widths != options.layout.preset_column_widths {
|
||||
self.preset_width_idx = None;
|
||||
}
|
||||
|
||||
// If preset heights changed, make our heights non-preset.
|
||||
if self.options.preset_window_heights != options.preset_window_heights {
|
||||
if self.options.layout.preset_window_heights != options.layout.preset_window_heights {
|
||||
self.convert_heights_to_auto();
|
||||
update_sizes = true;
|
||||
}
|
||||
|
||||
if self.options.gaps != options.gaps {
|
||||
if self.options.layout.gaps != options.layout.gaps {
|
||||
update_sizes = true;
|
||||
}
|
||||
|
||||
if self.options.border.off != options.border.off
|
||||
|| self.options.border.width != options.border.width
|
||||
if self.options.layout.border.off != options.layout.border.off
|
||||
|| self.options.layout.border.width != options.layout.border.width
|
||||
{
|
||||
update_sizes = true;
|
||||
}
|
||||
|
||||
if self.options.tab_indicator != options.tab_indicator {
|
||||
if self.options.layout.tab_indicator != options.layout.tab_indicator {
|
||||
update_sizes = true;
|
||||
}
|
||||
|
||||
@@ -3887,7 +3891,8 @@ impl<W: LayoutElement> Column<W> {
|
||||
data.update(tile);
|
||||
}
|
||||
|
||||
self.tab_indicator.update_config(options.tab_indicator);
|
||||
self.tab_indicator
|
||||
.update_config(options.layout.tab_indicator);
|
||||
self.view_size = view_size;
|
||||
self.working_area = working_area;
|
||||
self.scale = scale;
|
||||
@@ -4192,7 +4197,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
fn resolve_column_width(&self, width: ColumnWidth) -> f64 {
|
||||
let working_size = self.working_area.size;
|
||||
let gaps = self.options.gaps;
|
||||
let gaps = self.options.layout.gaps;
|
||||
let extra = self.extra_size();
|
||||
|
||||
match width {
|
||||
@@ -4274,7 +4279,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
let width = self.resolve_column_width(width);
|
||||
let width = f64::max(f64::min(width, max_width), min_width);
|
||||
let max_tile_height = working_size.h - self.options.gaps * 2. - extra_size.h;
|
||||
let max_tile_height = working_size.h - self.options.layout.gaps * 2. - extra_size.h;
|
||||
|
||||
// If there are multiple windows in a column, clamp the non-auto window's height according
|
||||
// to other windows' min sizes.
|
||||
@@ -4289,7 +4294,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(idx, _)| *idx != non_auto_idx)
|
||||
.map(|(_, min_size)| min_size.h + self.options.gaps)
|
||||
.map(|(_, min_size)| min_size.h + self.options.layout.gaps)
|
||||
.sum::<f64>();
|
||||
|
||||
let tile = &self.tiles[non_auto_idx];
|
||||
@@ -4318,7 +4323,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
WindowHeight::Fixed(tile.tile_height_for_window_height(window_height))
|
||||
}
|
||||
WindowHeight::Preset(idx) => {
|
||||
let preset = self.options.preset_window_heights[idx];
|
||||
let preset = self.options.layout.preset_window_heights[idx];
|
||||
let window_height = match self.resolve_preset_height(preset) {
|
||||
ResolvedSize::Tile(h) => tile.window_height_for_tile_height(h),
|
||||
ResolvedSize::Window(h) => h,
|
||||
@@ -4366,7 +4371,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
// The following logic will apply individual min/max height, etc.
|
||||
}
|
||||
|
||||
let gaps_left = self.options.gaps * (self.tiles.len() + 1) as f64;
|
||||
let gaps_left = self.options.layout.gaps * (self.tiles.len() + 1) as f64;
|
||||
let mut height_left = working_size.h - gaps_left;
|
||||
let mut auto_tiles_left = self.tiles.len();
|
||||
|
||||
@@ -4589,7 +4594,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
self.preset_width_idx
|
||||
};
|
||||
|
||||
let len = self.options.preset_column_widths.len();
|
||||
let len = self.options.layout.preset_column_widths.len();
|
||||
let preset_idx = if let Some(idx) = preset_idx {
|
||||
(idx + if forwards { 1 } else { len - 1 }) % len
|
||||
} else {
|
||||
@@ -4599,6 +4604,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
let mut it = self
|
||||
.options
|
||||
.layout
|
||||
.preset_column_widths
|
||||
.iter()
|
||||
.map(|preset| self.resolve_preset_width(*preset));
|
||||
@@ -4624,7 +4630,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
}
|
||||
};
|
||||
|
||||
let preset = self.options.preset_column_widths[preset_idx];
|
||||
let preset = self.options.layout.preset_column_widths[preset_idx];
|
||||
self.set_column_width(SizeChange::from(preset), Some(tile_idx), true);
|
||||
|
||||
self.preset_width_idx = Some(preset_idx);
|
||||
@@ -4672,11 +4678,11 @@ impl<W: LayoutElement> Column<W> {
|
||||
ColumnWidth::Proportion(proportion)
|
||||
}
|
||||
(ColumnWidth::Fixed(_), SizeChange::AdjustProportion(delta)) => {
|
||||
let full = self.working_area.size.w - self.options.gaps;
|
||||
let full = self.working_area.size.w - self.options.layout.gaps;
|
||||
let current = if full == 0. {
|
||||
1.
|
||||
} else {
|
||||
(current_px + self.options.gaps + self.extra_size().w) / full
|
||||
(current_px + self.options.layout.gaps + self.extra_size().w) / full
|
||||
};
|
||||
let proportion = (current + delta / 100.).clamp(0., MAX_F);
|
||||
ColumnWidth::Proportion(proportion)
|
||||
@@ -4710,7 +4716,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
let current_tile_px = tile.tile_height_for_window_height(current_window_px);
|
||||
|
||||
let working_size = self.working_area.size.h;
|
||||
let gaps = self.options.gaps;
|
||||
let gaps = self.options.layout.gaps;
|
||||
let extra_size = self.extra_size().h;
|
||||
let full = working_size - gaps;
|
||||
let current_prop = if full == 0. {
|
||||
@@ -4794,7 +4800,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
self.convert_heights_to_auto();
|
||||
}
|
||||
|
||||
let len = self.options.preset_window_heights.len();
|
||||
let len = self.options.layout.preset_window_heights.len();
|
||||
let preset_idx = match self.data[tile_idx].height {
|
||||
WindowHeight::Preset(idx) => (idx + if forwards { 1 } else { len - 1 }) % len,
|
||||
_ => {
|
||||
@@ -4803,6 +4809,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
let mut it = self
|
||||
.options
|
||||
.layout
|
||||
.preset_window_heights
|
||||
.iter()
|
||||
.copied()
|
||||
@@ -4933,7 +4940,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
return origin;
|
||||
}
|
||||
|
||||
origin.y += self.working_area.loc.y + self.options.gaps;
|
||||
origin.y += self.working_area.loc.y + self.options.layout.gaps;
|
||||
|
||||
if self.display_mode == ColumnDisplay::Tabbed {
|
||||
origin += self
|
||||
@@ -4953,8 +4960,8 @@ impl<W: LayoutElement> Column<W> {
|
||||
// FIXME: this should take into account always-center-single-column, which means that
|
||||
// Column should somehow know when it is being centered due to being the single column on
|
||||
// the workspace or some other reason.
|
||||
let center = self.options.center_focused_column == CenterFocusedColumn::Always;
|
||||
let gaps = self.options.gaps;
|
||||
let center = self.options.layout.center_focused_column == CenterFocusedColumn::Always;
|
||||
let gaps = self.options.layout.gaps;
|
||||
let tabbed = self.display_mode == ColumnDisplay::Tabbed;
|
||||
|
||||
// Does not include extra size from the tab indicator.
|
||||
@@ -5117,7 +5124,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
}
|
||||
|
||||
if let Some(idx) = self.preset_width_idx {
|
||||
assert!(idx < self.options.preset_column_widths.len());
|
||||
assert!(idx < self.options.layout.preset_column_widths.len());
|
||||
}
|
||||
|
||||
let is_tabbed = self.display_mode == ColumnDisplay::Tabbed;
|
||||
@@ -5134,7 +5141,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
|
||||
let working_size = self.working_area.size;
|
||||
let extra_size = self.extra_size();
|
||||
let gaps = self.options.gaps;
|
||||
let gaps = self.options.layout.gaps;
|
||||
|
||||
let mut found_fixed = false;
|
||||
let mut total_height = 0.;
|
||||
@@ -5163,7 +5170,7 @@ impl<W: LayoutElement> Column<W> {
|
||||
}
|
||||
|
||||
if let WindowHeight::Preset(idx) = data.height {
|
||||
assert!(self.options.preset_window_heights.len() > idx);
|
||||
assert!(self.options.layout.preset_window_heights.len() > idx);
|
||||
}
|
||||
|
||||
let requested_size = tile.window().requested_size().unwrap();
|
||||
@@ -5312,9 +5319,9 @@ fn resolve_preset_size(
|
||||
extra_size: f64,
|
||||
) -> ResolvedSize {
|
||||
match preset {
|
||||
PresetSize::Proportion(proportion) => {
|
||||
ResolvedSize::Tile((view_size - options.gaps) * proportion - options.gaps - extra_size)
|
||||
}
|
||||
PresetSize::Proportion(proportion) => ResolvedSize::Tile(
|
||||
(view_size - options.layout.gaps) * proportion - options.layout.gaps - extra_size,
|
||||
),
|
||||
PresetSize::Fixed(width) => ResolvedSize::Window(f64::from(width)),
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,8 @@ use std::cell::{Cell, OnceCell, RefCell};
|
||||
|
||||
use niri_config::workspace::WorkspaceName;
|
||||
use niri_config::{
|
||||
FloatOrInt, OutputName, TabIndicatorLength, TabIndicatorPosition, WorkspaceReference,
|
||||
CenterFocusedColumn, FloatOrInt, OutputName, Struts, TabIndicatorLength, TabIndicatorPosition,
|
||||
WorkspaceReference,
|
||||
};
|
||||
use proptest::prelude::*;
|
||||
use proptest_derive::Arbitrary;
|
||||
@@ -2066,8 +2067,8 @@ fn large_negative_height_change() {
|
||||
];
|
||||
|
||||
let mut options = Options::default();
|
||||
options.border.off = false;
|
||||
options.border.width = 1.;
|
||||
options.layout.border.off = false;
|
||||
options.layout.border.width = 1.;
|
||||
|
||||
check_ops_with_options(options, ops);
|
||||
}
|
||||
@@ -2085,8 +2086,8 @@ fn large_max_size() {
|
||||
];
|
||||
|
||||
let mut options = Options::default();
|
||||
options.border.off = false;
|
||||
options.border.width = 1.;
|
||||
options.layout.border.off = false;
|
||||
options.layout.border.width = 1.;
|
||||
|
||||
check_ops_with_options(options, ops);
|
||||
}
|
||||
@@ -2244,7 +2245,10 @@ fn open_right_of_on_different_workspace_ewaf() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let layout = check_ops_with_options(options, ops);
|
||||
@@ -2306,11 +2310,7 @@ fn config_change_updates_cached_sizes() {
|
||||
}
|
||||
.apply(&mut layout);
|
||||
|
||||
config
|
||||
.layout
|
||||
.border
|
||||
.get_or_insert_with(Default::default)
|
||||
.width = Some(FloatOrInt(4.));
|
||||
config.layout.border.as_mut().unwrap().width = Some(FloatOrInt(4.));
|
||||
layout.update_config(&config);
|
||||
|
||||
layout.verify_invariants();
|
||||
@@ -2427,12 +2427,15 @@ fn fixed_height_takes_max_non_auto_into_account() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 4.,
|
||||
layout: niri_config::Layout {
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 4.,
|
||||
..Default::default()
|
||||
},
|
||||
gaps: 0.,
|
||||
..Default::default()
|
||||
},
|
||||
gaps: 0.,
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2511,7 +2514,10 @@ fn interactive_move_onto_empty_output_ewaf() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2572,7 +2578,10 @@ fn interactive_move_onto_first_empty_workspace() {
|
||||
Op::InteractiveMoveEnd { window: 1 },
|
||||
];
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2653,7 +2662,10 @@ fn named_workspace_to_output_ewaf() {
|
||||
Op::AddOutput(2),
|
||||
];
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2672,7 +2684,10 @@ fn move_window_to_empty_workspace_above_first() {
|
||||
Op::MoveWorkspaceDown,
|
||||
];
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2689,7 +2704,10 @@ fn move_window_to_different_output() {
|
||||
Op::MoveWorkspaceToOutput(2),
|
||||
];
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2705,7 +2723,10 @@ fn close_window_empty_ws_above_first() {
|
||||
Op::CloseWindow(1),
|
||||
];
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2722,7 +2743,10 @@ fn add_and_remove_output() {
|
||||
Op::RemoveOutput(2),
|
||||
];
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -2739,7 +2763,10 @@ fn switch_ewaf_on() {
|
||||
|
||||
let mut layout = check_ops(ops);
|
||||
layout.update_options(Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
layout.verify_invariants();
|
||||
@@ -2755,7 +2782,10 @@ fn switch_ewaf_off() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let mut layout = check_ops_with_options(options, ops);
|
||||
@@ -3074,7 +3104,10 @@ fn set_first_workspace_name_ewaf() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
empty_workspace_above_first: true,
|
||||
layout: niri_config::Layout {
|
||||
empty_workspace_above_first: true,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
check_ops_with_options(options, ops);
|
||||
@@ -3165,7 +3198,10 @@ fn preset_column_width_fixed_correct_with_border() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
preset_column_widths: vec![PresetSize::Fixed(500)],
|
||||
layout: niri_config::Layout {
|
||||
preset_column_widths: vec![PresetSize::Fixed(500)],
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let mut layout = check_ops_with_options(options, ops);
|
||||
@@ -3175,10 +3211,13 @@ fn preset_column_width_fixed_correct_with_border() {
|
||||
|
||||
// Add border.
|
||||
let options = Options {
|
||||
preset_column_widths: vec![PresetSize::Fixed(500)],
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 5.,
|
||||
layout: niri_config::Layout {
|
||||
preset_column_widths: vec![PresetSize::Fixed(500)],
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 5.,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
@@ -3211,7 +3250,10 @@ fn preset_column_width_reset_after_set_width() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
preset_column_widths: vec![PresetSize::Fixed(500), PresetSize::Fixed(1000)],
|
||||
layout: niri_config::Layout {
|
||||
preset_column_widths: vec![PresetSize::Fixed(500), PresetSize::Fixed(1000)],
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
let layout = check_ops_with_options(options, ops);
|
||||
@@ -3469,7 +3511,7 @@ prop_compose! {
|
||||
}
|
||||
|
||||
prop_compose! {
|
||||
fn arbitrary_options()(
|
||||
fn arbitrary_layout_config()(
|
||||
gaps in arbitrary_spacing(),
|
||||
struts in arbitrary_struts(),
|
||||
focus_ring in arbitrary_focus_ring(),
|
||||
@@ -3479,8 +3521,8 @@ prop_compose! {
|
||||
center_focused_column in arbitrary_center_focused_column(),
|
||||
always_center_single_column in any::<bool>(),
|
||||
empty_workspace_above_first in any::<bool>(),
|
||||
) -> Options {
|
||||
Options {
|
||||
) -> niri_config::Layout {
|
||||
niri_config::Layout {
|
||||
gaps,
|
||||
struts,
|
||||
center_focused_column,
|
||||
@@ -3495,6 +3537,17 @@ prop_compose! {
|
||||
}
|
||||
}
|
||||
|
||||
prop_compose! {
|
||||
fn arbitrary_options()(
|
||||
layout in arbitrary_layout_config()
|
||||
) -> Options {
|
||||
Options {
|
||||
layout,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proptest! {
|
||||
#![proptest_config(ProptestConfig {
|
||||
cases: if std::env::var_os("RUN_SLOW_TESTS").is_none() {
|
||||
|
@@ -29,7 +29,10 @@ fn make_options() -> Options {
|
||||
});
|
||||
|
||||
let mut options = Options {
|
||||
gaps: 0.0,
|
||||
layout: niri_config::Layout {
|
||||
gaps: 0.0,
|
||||
..Default::default()
|
||||
},
|
||||
..Options::default()
|
||||
};
|
||||
options.animations.window_resize.anim.kind = LINEAR;
|
||||
|
@@ -188,9 +188,12 @@ fn unfullscreen_with_large_border() {
|
||||
];
|
||||
|
||||
let options = Options {
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 10000.,
|
||||
layout: niri_config::Layout {
|
||||
border: niri_config::Border {
|
||||
off: false,
|
||||
width: 10000.,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
@@ -175,9 +175,9 @@ impl<W: LayoutElement> Tile<W> {
|
||||
options: Rc<Options>,
|
||||
) -> Self {
|
||||
let rules = window.rules();
|
||||
let border_config = options.border.merged_with(&rules.border);
|
||||
let focus_ring_config = options.focus_ring.merged_with(&rules.focus_ring);
|
||||
let shadow_config = options.shadow.merged_with(&rules.shadow);
|
||||
let border_config = options.layout.border.merged_with(&rules.border);
|
||||
let focus_ring_config = options.layout.focus_ring.merged_with(&rules.focus_ring);
|
||||
let shadow_config = options.layout.shadow.merged_with(&rules.shadow);
|
||||
let is_fullscreen = window.is_fullscreen();
|
||||
|
||||
Self {
|
||||
@@ -214,10 +214,10 @@ impl<W: LayoutElement> Tile<W> {
|
||||
options: Rc<Options>,
|
||||
) {
|
||||
// If preset widths or heights changed, clear our stored preset index.
|
||||
if self.options.preset_column_widths != options.preset_column_widths {
|
||||
if self.options.layout.preset_column_widths != options.layout.preset_column_widths {
|
||||
self.floating_preset_width_idx = None;
|
||||
}
|
||||
if self.options.preset_window_heights != options.preset_window_heights {
|
||||
if self.options.layout.preset_window_heights != options.layout.preset_window_heights {
|
||||
self.floating_preset_height_idx = None;
|
||||
}
|
||||
|
||||
@@ -227,13 +227,17 @@ impl<W: LayoutElement> Tile<W> {
|
||||
|
||||
let rules = self.window.rules();
|
||||
|
||||
let border_config = self.options.border.merged_with(&rules.border);
|
||||
let border_config = self.options.layout.border.merged_with(&rules.border);
|
||||
self.border.update_config(border_config.into());
|
||||
|
||||
let focus_ring_config = self.options.focus_ring.merged_with(&rules.focus_ring);
|
||||
let focus_ring_config = self
|
||||
.options
|
||||
.layout
|
||||
.focus_ring
|
||||
.merged_with(&rules.focus_ring);
|
||||
self.focus_ring.update_config(focus_ring_config);
|
||||
|
||||
let shadow_config = self.options.shadow.merged_with(&rules.shadow);
|
||||
let shadow_config = self.options.layout.shadow.merged_with(&rules.shadow);
|
||||
self.shadow.update_config(shadow_config);
|
||||
}
|
||||
|
||||
@@ -332,12 +336,16 @@ impl<W: LayoutElement> Tile<W> {
|
||||
}
|
||||
|
||||
let rules = self.window.rules();
|
||||
let border_config = self.options.border.merged_with(&rules.border);
|
||||
let border_config = self.options.layout.border.merged_with(&rules.border);
|
||||
self.border.update_config(border_config.into());
|
||||
let focus_ring_config = self.options.focus_ring.merged_with(&rules.focus_ring);
|
||||
let focus_ring_config = self
|
||||
.options
|
||||
.layout
|
||||
.focus_ring
|
||||
.merged_with(&rules.focus_ring);
|
||||
self.focus_ring.update_config(focus_ring_config);
|
||||
|
||||
let shadow_config = self.options.shadow.merged_with(&rules.shadow);
|
||||
let shadow_config = self.options.layout.shadow.merged_with(&rules.shadow);
|
||||
self.shadow.update_config(shadow_config);
|
||||
|
||||
let window_size = self.window_size();
|
||||
|
@@ -754,7 +754,7 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
Some(Some(width)) => Some(width),
|
||||
Some(None) => None,
|
||||
None if is_floating => None,
|
||||
None => self.options.default_column_width,
|
||||
None => self.options.layout.default_column_width,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1272,11 +1272,12 @@ impl<W: LayoutElement> Workspace<W> {
|
||||
// Come up with a default floating position close to the tile position.
|
||||
let stored_or_default = self.floating.stored_or_default_tile_pos(&removed.tile);
|
||||
if stored_or_default.is_none() {
|
||||
let offset = if self.options.center_focused_column == CenterFocusedColumn::Always {
|
||||
Point::from((0., 0.))
|
||||
} else {
|
||||
Point::from((50., 50.))
|
||||
};
|
||||
let offset =
|
||||
if self.options.layout.center_focused_column == CenterFocusedColumn::Always {
|
||||
Point::from((0., 0.))
|
||||
} else {
|
||||
Point::from((50., 50.))
|
||||
};
|
||||
let pos = render_pos + offset;
|
||||
let size = removed.tile.tile_size();
|
||||
let pos = self.floating.clamp_within_working_area(pos, size);
|
||||
|
Reference in New Issue
Block a user