1
0
Fork 0
forked from wry/wry

fix split bug on single windows and elide titles

This commit is contained in:
kossLAN 2026-05-03 15:35:34 -04:00
parent 7f71a6556b
commit c555593ae2
No known key found for this signature in database
8 changed files with 207 additions and 145 deletions

View file

@ -97,10 +97,10 @@ alt-shift-l = "move-right"
```toml ```toml
[shortcuts] [shortcuts]
alt-d = "split-horizontal" alt-d = "make-group-h"
alt-v = "split-vertical" alt-v = "make-group-v"
alt-t = "toggle-split" alt-t = "change-group-opposite"
alt-m = "toggle-mono" alt-m = "toggle-tab"
alt-f = "focus-parent" alt-f = "focus-parent"
``` ```
@ -475,7 +475,7 @@ table and reference them with `$name`:
```toml ```toml
[actions] [actions]
my-layout = [ my-layout = [
"split-horizontal", "make-group-h",
{ type = "exec", exec = "alacritty" }, { type = "exec", exec = "alacritty" },
] ]
@ -535,10 +535,9 @@ mode = {
When certain simple actions are used inside a [window rule](../window-rules.md), When certain simple actions are used inside a [window rule](../window-rules.md),
they apply to the **matched window** instead of the focused window. The they apply to the **matched window** instead of the focused window. The
affected actions are: `move-left`, `move-down`, `move-up`, `move-right`, affected actions are: `move-left`, `move-down`, `move-up`, `move-right`,
`split-horizontal`, `split-vertical`, `toggle-split`, `tile-horizontal`, `toggle-fullscreen`, `enter-fullscreen`, `exit-fullscreen`, `close`,
`tile-vertical`, `show-single`, `show-all`, `toggle-fullscreen`, `toggle-floating`, `float`, `tile`, `toggle-float-pinned`, `pin-float`,
`enter-fullscreen`, `exit-fullscreen`, `close`, `toggle-floating`, `float`, `unpin-float`, and `resize`.
`tile`, `toggle-float-pinned`, `pin-float`, `unpin-float`, and `resize`.
Similarly, `kill-client` applies to the matched window's client in a window Similarly, `kill-client` applies to the matched window's client in a window
rule, or to the matched client in a client rule. rule, or to the matched client in a client rule.

View file

@ -4,32 +4,20 @@ Jay uses an i3-like tiling layout. Windows are arranged automatically in
containers that can be split horizontally or vertically. Containers can be nested containers that can be split horizontally or vertically. Containers can be nested
to create complex layouts. to create complex layouts.
## Splitting Containers ## Grouping Containers
When you split a window, Jay wraps it in a new container with the specified When you group a window, Jay wraps it in a new container with the specified
direction. Subsequent windows opened in that container are placed side by side direction. Subsequent windows opened in that group are placed side by side
(horizontal split) or stacked top to bottom (vertical split). (horizontal group) or stacked top to bottom (vertical group).
`alt-d` -- `split-horizontal` `alt-d` -- `make-group-h`
: Split the focused window horizontally : Group the focused window horizontally
`alt-v` -- `split-vertical` `alt-v` -- `make-group-v`
: Split the focused window vertically : Group the focused window vertically
`alt-t` -- `toggle-split` `alt-t` -- `change-group-opposite`
: Toggle the container's split direction : Toggle the current group's direction
You can also set the direction explicitly without toggling:
```toml
[shortcuts]
alt-shift-d = "tile-horizontal"
alt-shift-v = "tile-vertical"
```
The `tile-horizontal` action sets the container to horizontal, and
`tile-vertical` sets it to vertical -- unlike `split-horizontal`/`split-vertical`
which wrap the window in a new container first.
## Moving Focus ## Moving Focus
@ -81,22 +69,14 @@ windows at once. For example, focusing a parent container and then using
By default, a container shows all its children side by side. Mono mode changes By default, a container shows all its children side by side. Mono mode changes
this so only one child is visible at a time, similar to a tabbed view. this so only one child is visible at a time, similar to a tabbed view.
`alt-m` -- `toggle-mono` `alt-m` -- `toggle-tab`
: Toggle between mono and side-by-side : Toggle between tabbed and side-by-side
You can also right-click any title in a container to toggle mono mode. You can also right-click any title in a container to toggle mono mode.
In mono mode, scroll over the title bar to cycle between windows in the In mono mode, scroll over the title bar to cycle between windows in the
container. container.
For explicit control without toggling:
```toml
[shortcuts]
alt-s = "show-single" # Enter mono mode
alt-a = "show-all" # Exit mono mode
```
## Fullscreen ## Fullscreen
Press `alt-u` (`toggle-fullscreen`) to make the focused window fill the entire Press `alt-u` (`toggle-fullscreen`) to make the focused window fill the entire
@ -137,20 +117,17 @@ Double-click a tile's title bar to toggle it between tiled and floating. See
## Summary of Tiling Actions ## Summary of Tiling Actions
`split-horizontal` `make-group-h`
: Wrap focused window in a horizontal container : Wrap focused window in a horizontal group
`split-vertical` `make-group-v`
: Wrap focused window in a vertical container : Wrap focused window in a vertical group
`toggle-split` `make-group-tab`
: Toggle container split direction : Wrap focused window in a tabbed group
`tile-horizontal` `change-group-opposite`
: Set container direction to horizontal : Toggle group direction
`tile-vertical`
: Set container direction to vertical
`focus-left/right/up/down` `focus-left/right/up/down`
: Move keyboard focus : Move keyboard focus
@ -161,14 +138,8 @@ Double-click a tile's title bar to toggle it between tiled and floating. See
`focus-parent` `focus-parent`
: Focus the parent container : Focus the parent container
`toggle-mono` `toggle-tab`
: Toggle mono mode : Toggle tabbed mode
`show-single`
: Enter mono mode
`show-all`
: Exit mono mode
`toggle-fullscreen` `toggle-fullscreen`
: Toggle fullscreen : Toggle fullscreen

View file

@ -92,6 +92,23 @@ impl<'a> Config<'a> {
markup, markup,
scale, scale,
}, },
Config::RenderFittingOrEllipsized {
height,
max_width,
font,
text,
color,
markup,
scale,
} => Config::RenderFittingOrEllipsized {
height,
max_width,
font,
text: text.into_owned().into(),
color,
markup,
scale,
},
Config::Render { Config::Render {
x, x,
y, y,
@ -262,6 +279,26 @@ fn render_fitting(
) )
} }
fn render_fitting_or_ellipsized(
memfd: &Memfd,
height: Option<i32>,
max_width: i32,
font: &str,
text: &str,
color: Color,
markup: bool,
scale: Option<f64>,
) -> Result<RenderedText, TextError> {
let measurement = measure(memfd, font, text, markup, scale)?;
if measurement.ink_rect.width() <= max_width {
return render_fitting(memfd, height, font, text, color, markup, scale);
}
let height = height.unwrap_or(measurement.ink_rect.height());
render(
memfd, 0, None, max_width, height, 0, font, text, color, true, markup, scale,
)
}
#[derive(Debug, Copy, Clone, Default)] #[derive(Debug, Copy, Clone, Default)]
pub struct TextMeasurement { pub struct TextMeasurement {
pub ink_rect: Rect, pub ink_rect: Rect,
@ -303,6 +340,24 @@ impl RenderWork {
markup, markup,
scale, scale,
} => render_fitting(&self.memfd, height, font, text, color, markup, scale), } => render_fitting(&self.memfd, height, font, text, color, markup, scale),
Config::RenderFittingOrEllipsized {
height,
max_width,
ref font,
ref text,
color,
markup,
scale,
} => render_fitting_or_ellipsized(
&self.memfd,
height,
max_width,
font,
text,
color,
markup,
scale,
),
Config::Render { Config::Render {
x, x,
y, y,
@ -428,6 +483,15 @@ enum Config<'a> {
markup: bool, markup: bool,
scale: Option<f64>, scale: Option<f64>,
}, },
RenderFittingOrEllipsized {
height: Option<i32>,
max_width: i32,
font: Arc<String>,
text: Cow<'a, str>,
color: Color,
markup: bool,
scale: Option<f64>,
},
Render { Render {
x: i32, x: i32,
y: Option<i32>, y: Option<i32>,
@ -573,6 +637,29 @@ impl TextTexture {
self.apply_config(on_completed, config) self.apply_config(on_completed, config)
} }
pub fn schedule_render_fitting_or_ellipsized(
&self,
on_completed: Rc<dyn OnCompleted>,
height: Option<i32>,
max_width: i32,
font: &Arc<String>,
text: &str,
color: Color,
markup: bool,
scale: Option<f64>,
) {
let config = Config::RenderFittingOrEllipsized {
height,
max_width,
font: font.clone(),
text: text.into(),
color,
markup,
scale,
};
self.apply_config(on_completed, config)
}
pub fn flip(&self) -> Result<(), TextError> { pub fn flip(&self) -> Result<(), TextError> {
let res = self let res = self
.data .data

View file

@ -937,14 +937,29 @@ impl ContainerNode {
.persistent .persistent
.scale .scale
.get(); .get();
let old_textures: AHashMap<_, _> = self
.tab_bar
.borrow()
.as_ref()
.map(|bar| {
bar.entries
.iter()
.map(|entry| (entry.child_id, entry.title_texture.clone()))
.collect()
})
.unwrap_or_default();
let mut bar = TabBar::new(height, render_scale); let mut bar = TabBar::new(height, render_scale);
for child in self.children.iter() { for child in self.children.iter() {
let child_id = child.node.node_id(); let child_id = child.node.node_id();
let title = self.get_child_tab_title(&child, override_id, override_title); let title = self.get_child_tab_title(&child, override_id, override_title);
let title_texture = old_textures
.get(&child_id)
.cloned()
.unwrap_or_else(|| Rc::new(RefCell::new(None)));
bar.entries.push(TabBarEntry { bar.entries.push(TabBarEntry {
child_id, child_id,
title, title,
title_texture: Rc::new(RefCell::new(None)), title_texture,
active: child_id == active_id, active: child_id == active_id,
attention_requested: child.attention_requested.get(), attention_requested: child.attention_requested.get(),
x: Cell::new(0), x: Cell::new(0),
@ -964,10 +979,27 @@ impl ContainerNode {
let Some(focused) = self.focus_history.last() else { let Some(focused) = self.focus_history.last() else {
return; return;
}; };
if self.num_children.get() <= 1 { let focused_node = focused.node.clone();
let focused_active = focused_node.tl_data().active();
if self.num_children.get() == 1 {
let sub = ContainerNode::new(
&self.state,
&self.workspace.get(),
focused_node.clone(),
split,
);
let sub_id = sub.node_id();
if ephemeral {
sub.ephemeral.set(Ephemeral::On);
}
self.clone().cnode_replace_child(&*focused_node, sub);
if focused_active
&& let Some(group) = self.child_nodes.borrow().get(&sub_id).map(|n| n.to_ref())
{
self.update_child_active(&group, true, 1);
}
return; return;
} }
let focused_node = focused.node.clone();
// Record the sibling that comes AFTER the focused child so we can // Record the sibling that comes AFTER the focused child so we can
// insert the new group at the same position. // insert the new group at the same position.
let next_sibling: Option<Rc<dyn ToplevelNode>> = { let next_sibling: Option<Rc<dyn ToplevelNode>> = {
@ -1774,6 +1806,7 @@ impl ContainerNode {
e.title.clone(), e.title.clone(),
TabBar::entry_colors(&self.state, e), TabBar::entry_colors(&self.state, e),
e.title_texture.clone(), e.title_texture.clone(),
e.width.get(),
) )
}) })
.collect(); .collect();
@ -1794,12 +1827,24 @@ impl ContainerNode {
texture_height = (bar_height as f64 * s).round() as _; texture_height = (bar_height as f64 * s).round() as _;
} }
let mut texture_refs = Vec::new(); let mut texture_refs = Vec::new();
for (title, (_, _, text_color), title_texture) in &entries { let text_padding = self.state.theme.sizes.tab_bar_text_padding.get();
let border_width = self.state.theme.sizes.tab_bar_border_width.get();
for (title, (_, _, text_color), title_texture, tab_width) in &entries {
let max_width = (*tab_width - 2 * (text_padding + border_width)).max(0);
let max_width = if let Some(s) = scale {
(max_width as f64 * s).round() as i32
} else {
max_width
};
if max_width <= 0 {
continue;
}
let mut tex_ref = title_texture.borrow_mut(); let mut tex_ref = title_texture.borrow_mut();
let tex = tex_ref.get_or_insert_with(|| TextTexture::new(&self.state, &ctx)); let tex = tex_ref.get_or_insert_with(|| TextTexture::new(&self.state, &ctx));
tex.schedule_render_fitting( tex.schedule_render_fitting_or_ellipsized(
on_completed.clone(), on_completed.clone(),
Some(texture_height), Some(texture_height),
max_width,
&font, &font,
title, title,
*text_color, *text_color,
@ -2465,6 +2510,7 @@ impl ToplevelNodeBase for ContainerNode {
let padding = self.state.theme.sizes.tab_bar_padding.get(); let padding = self.state.theme.sizes.tab_bar_padding.get();
bar.layout_entries(rect.width(), padding); bar.layout_entries(rect.width(), padding);
} }
self.schedule_update_tab_textures();
} }
// log::info!("tl_change_extents"); // log::info!("tl_change_extents");
self.perform_layout(); self.perform_layout();

View file

@ -23,11 +23,11 @@ alt-shift-j = "move-down"
alt-shift-k = "move-up" alt-shift-k = "move-up"
alt-shift-l = "move-right" alt-shift-l = "move-right"
alt-d = "split-horizontal" alt-d = "make-group-h"
alt-v = "split-vertical" alt-v = "make-group-v"
alt-t = "toggle-split" alt-t = "change-group-opposite"
alt-m = "toggle-mono" alt-m = "toggle-tab"
alt-u = "toggle-fullscreen" alt-u = "toggle-fullscreen"
alt-f = "focus-parent" alt-f = "focus-parent"

View file

@ -930,7 +930,7 @@
"required": [] "required": []
}, },
"Config": { "Config": {
"description": "This is the top-level table.\n\n- Example:\n\n ```toml\n keymap = \"\"\"\n xkb_keymap {\n xkb_keycodes { include \"evdev+aliases(qwerty)\" };\n xkb_types { include \"complete\" };\n xkb_compat { include \"complete\" };\n xkb_symbols { include \"pc+us+inet(evdev)\" };\n };\n \"\"\"\n\n on-graphics-initialized = { type = \"exec\", exec = \"mako\" }\n\n [shortcuts]\n alt-h = \"focus-left\"\n alt-j = \"focus-down\"\n alt-k = \"focus-up\"\n alt-l = \"focus-right\"\n\n alt-shift-h = \"move-left\"\n alt-shift-j = \"move-down\"\n alt-shift-k = \"move-up\"\n alt-shift-l = \"move-right\"\n\n alt-d = \"split-horizontal\"\n alt-v = \"split-vertical\"\n\n alt-t = \"toggle-split\"\n alt-m = \"toggle-mono\"\n alt-u = \"toggle-fullscreen\"\n\n alt-f = \"focus-parent\"\n alt-shift-c = \"close\"\n alt-shift-f = \"toggle-floating\"\n Super_L = { type = \"exec\", exec = \"alacritty\" }\n alt-p = { type = \"exec\", exec = \"bemenu-run\" }\n alt-q = \"quit\"\n alt-shift-r = \"reload-config-toml\"\n\n ctrl-alt-F1 = { type = \"switch-to-vt\", num = 1 }\n ctrl-alt-F2 = { type = \"switch-to-vt\", num = 2 }\n # ...\n\n alt-F1 = { type = \"show-workspace\", name = \"1\" }\n alt-F2 = { type = \"show-workspace\", name = \"2\" }\n # ...\n\n alt-shift-F1 = { type = \"move-to-workspace\", name = \"1\" }\n alt-shift-F2 = { type = \"move-to-workspace\", name = \"2\" }\n # ...\n ```\n", "description": "This is the top-level table.\n\n- Example:\n\n ```toml\n keymap = \"\"\"\n xkb_keymap {\n xkb_keycodes { include \"evdev+aliases(qwerty)\" };\n xkb_types { include \"complete\" };\n xkb_compat { include \"complete\" };\n xkb_symbols { include \"pc+us+inet(evdev)\" };\n };\n \"\"\"\n\n on-graphics-initialized = { type = \"exec\", exec = \"mako\" }\n\n [shortcuts]\n alt-h = \"focus-left\"\n alt-j = \"focus-down\"\n alt-k = \"focus-up\"\n alt-l = \"focus-right\"\n\n alt-shift-h = \"move-left\"\n alt-shift-j = \"move-down\"\n alt-shift-k = \"move-up\"\n alt-shift-l = \"move-right\"\n\n alt-d = \"make-group-h\"\n alt-v = \"make-group-v\"\n\n alt-t = \"change-group-opposite\"\n alt-m = \"toggle-tab\"\n alt-u = \"toggle-fullscreen\"\n\n alt-f = \"focus-parent\"\n alt-shift-c = \"close\"\n alt-shift-f = \"toggle-floating\"\n Super_L = { type = \"exec\", exec = \"alacritty\" }\n alt-p = { type = \"exec\", exec = \"bemenu-run\" }\n alt-q = \"quit\"\n alt-shift-r = \"reload-config-toml\"\n\n ctrl-alt-F1 = { type = \"switch-to-vt\", num = 1 }\n ctrl-alt-F2 = { type = \"switch-to-vt\", num = 2 }\n # ...\n\n alt-F1 = { type = \"show-workspace\", name = \"1\" }\n alt-F2 = { type = \"show-workspace\", name = \"2\" }\n # ...\n\n alt-shift-F1 = { type = \"move-to-workspace\", name = \"1\" }\n alt-shift-F2 = { type = \"move-to-workspace\", name = \"2\" }\n # ...\n ```\n",
"type": "object", "type": "object",
"properties": { "properties": {
"keymap": { "keymap": {
@ -1993,7 +1993,7 @@
}, },
"SimpleActionName": { "SimpleActionName": {
"type": "string", "type": "string",
"description": "The name of a `simple` Action.\n\nWhen used inside a window rule, the following actions apply to the matched window\ninstead fo the focused window:\n\n- `move-left`\n- `move-down`\n- `move-up`\n- `move-right`\n- `split-horizontal`\n- `split-vertical`\n- `toggle-split`\n- `tile-horizontal`\n- `tile-vertical`\n- `toggle-split`\n- `show-single`\n- `show-all`\n- `toggle-fullscreen`\n- `enter-fullscreen`\n- `exit-fullscreen`\n- `close`\n- `toggle-floating`\n- `float`\n- `tile`\n- `toggle-float-pinned`\n- `pin-float`\n- `unpin-float`\n\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-q = \"quit\"\n ```\n", "description": "The name of a `simple` Action.\n\nWhen used inside a window rule, the following actions apply to the matched window\ninstead fo the focused window:\n\n- `move-left`\n- `move-down`\n- `move-up`\n- `move-right`\n- `toggle-fullscreen`\n- `enter-fullscreen`\n- `exit-fullscreen`\n- `close`\n- `toggle-floating`\n- `float`\n- `tile`\n- `toggle-float-pinned`\n- `pin-float`\n- `unpin-float`\n\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-q = \"quit\"\n ```\n",
"enum": [ "enum": [
"focus-left", "focus-left",
"focus-down", "focus-down",
@ -2004,14 +2004,11 @@
"move-up", "move-up",
"move-right", "move-right",
"move-right", "move-right",
"split-horizontal", "make-group-h",
"split-vertical", "make-group-v",
"toggle-split", "make-group-tab",
"tile-horizontal", "change-group-opposite",
"tile-vertical", "toggle-tab",
"toggle-mono",
"show-single",
"show-all",
"toggle-fullscreen", "toggle-fullscreen",
"enter-fullscreen", "enter-fullscreen",
"exit-fullscreen", "exit-fullscreen",

View file

@ -1659,11 +1659,11 @@ This is the top-level table.
alt-shift-k = "move-up" alt-shift-k = "move-up"
alt-shift-l = "move-right" alt-shift-l = "move-right"
alt-d = "split-horizontal" alt-d = "make-group-h"
alt-v = "split-vertical" alt-v = "make-group-v"
alt-t = "toggle-split" alt-t = "change-group-opposite"
alt-m = "toggle-mono" alt-m = "toggle-tab"
alt-u = "toggle-fullscreen" alt-u = "toggle-fullscreen"
alt-f = "focus-parent" alt-f = "focus-parent"
@ -4397,14 +4397,6 @@ instead fo the focused window:
- `move-down` - `move-down`
- `move-up` - `move-up`
- `move-right` - `move-right`
- `split-horizontal`
- `split-vertical`
- `toggle-split`
- `tile-horizontal`
- `tile-vertical`
- `toggle-split`
- `show-single`
- `show-all`
- `toggle-fullscreen` - `toggle-fullscreen`
- `enter-fullscreen` - `enter-fullscreen`
- `exit-fullscreen` - `exit-fullscreen`
@ -4464,38 +4456,25 @@ The string should have one of the following values:
Move the currently focused window one to the right. Move the currently focused window one to the right.
- `split-horizontal`: - `make-group-h`:
Split the currently focused window horizontally. Wraps the focused window in a horizontal group.
- `split-vertical`: - `make-group-v`:
Split the currently focused window vertically. Wraps the focused window in a vertical group.
- `toggle-split`: - `make-group-tab`:
Toggle the split of the currently focused container between vertical and Wraps the focused window in a tabbed group.
horizontal.
- `tile-horizontal`: - `change-group-opposite`:
Sets the split of the currently focused container to horizontal. Toggles the current group's direction.
- `tile-vertical`: - `toggle-tab`:
Sets the split of the currently focused container to vertical. Toggles the current group between tabbed and split mode.
- `toggle-mono`:
Toggle the currently focused container between showing a single and all children.
- `show-single`:
Makes the currently focused container show a single child.
- `show-all`:
Makes the currently focused container show all children.
- `toggle-fullscreen`: - `toggle-fullscreen`:

View file

@ -1016,14 +1016,6 @@ SimpleActionName:
- `move-down` - `move-down`
- `move-up` - `move-up`
- `move-right` - `move-right`
- `split-horizontal`
- `split-vertical`
- `toggle-split`
- `tile-horizontal`
- `tile-vertical`
- `toggle-split`
- `show-single`
- `show-all`
- `toggle-fullscreen` - `toggle-fullscreen`
- `enter-fullscreen` - `enter-fullscreen`
- `exit-fullscreen` - `exit-fullscreen`
@ -1062,25 +1054,16 @@ SimpleActionName:
description: Move the currently focused window one to the right. description: Move the currently focused window one to the right.
- value: move-right - value: move-right
description: Move the currently focused window one to the right. description: Move the currently focused window one to the right.
- value: split-horizontal - value: make-group-h
description: Split the currently focused window horizontally. description: Wraps the focused window in a horizontal group.
- value: split-vertical - value: make-group-v
description: Split the currently focused window vertically. description: Wraps the focused window in a vertical group.
- value: toggle-split - value: make-group-tab
description: | description: Wraps the focused window in a tabbed group.
Toggle the split of the currently focused container between vertical and - value: change-group-opposite
horizontal. description: Toggles the current group's direction.
- value: tile-horizontal - value: toggle-tab
description: Sets the split of the currently focused container to horizontal. description: Toggles the current group between tabbed and split mode.
- value: tile-vertical
description: Sets the split of the currently focused container to vertical.
- value: toggle-mono
description: |
Toggle the currently focused container between showing a single and all children.
- value: show-single
description: Makes the currently focused container show a single child.
- value: show-all
description: Makes the currently focused container show all children.
- value: toggle-fullscreen - value: toggle-fullscreen
description: Toggle the currently focused window between fullscreen and windowed. description: Toggle the currently focused window between fullscreen and windowed.
- value: enter-fullscreen - value: enter-fullscreen
@ -2467,11 +2450,11 @@ Config:
alt-shift-k = "move-up" alt-shift-k = "move-up"
alt-shift-l = "move-right" alt-shift-l = "move-right"
alt-d = "split-horizontal" alt-d = "make-group-h"
alt-v = "split-vertical" alt-v = "make-group-v"
alt-t = "toggle-split" alt-t = "change-group-opposite"
alt-m = "toggle-mono" alt-m = "toggle-tab"
alt-u = "toggle-fullscreen" alt-u = "toggle-fullscreen"
alt-f = "focus-parent" alt-f = "focus-parent"