fix(panes): multiplayer stack issues (#4038)

* fix(panes): interactions between multiplayer and stacked panes

* remove extraneous focus

* style(fmt): rustfmt

* docs(changelog): update pr
This commit is contained in:
Aram Drevekenin 2025-03-03 17:11:35 +01:00 committed by GitHub
parent f096dc7b88
commit 489534f29d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 30 deletions

View file

@ -39,6 +39,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* fix(grid): reap sixel images on clear (https://github.com/zellij-org/zellij/pull/3982)
* fix(panes): properly render stacked panes when pane frames are disabled (https://github.com/zellij-org/zellij/pull/4035)
* fix(panes): break ties by last focus time when focusing panes on screen edge (https://github.com/zellij-org/zellij/pull/4037)
* fix(multiplayer): some issues in conjunction with stacked panes and multiple users (https://github.com/zellij-org/zellij/pull/4038)
## [0.41.2] - 2024-11-19
* fix(input): keypresses not being identified properly with kitty keyboard protocol in some terminals (https://github.com/zellij-org/zellij/pull/3725)

View file

@ -658,21 +658,50 @@ impl TiledPanes {
self.set_force_render();
self.reapply_pane_frames();
}
pub fn focus_pane_for_all_clients_in_stack(&mut self, pane_id: PaneId, stack_id: usize) {
let connected_clients: Vec<ClientId> =
self.connected_clients.borrow().iter().copied().collect();
let pane_ids_in_stack = {
StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.pane_ids_in_stack(stack_id)
};
if self
.panes
.get(&pane_id)
.map(|p| p.current_geom().is_stacked())
.unwrap_or(false)
{
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.expand_pane(&pane_id);
}
for client_id in connected_clients {
if self
.active_panes
.get(&client_id)
.map(|p_id| pane_ids_in_stack.contains(p_id))
.unwrap_or(false)
{
self.active_panes
.insert(client_id, pane_id, &mut self.panes);
self.set_pane_active_at(pane_id);
}
}
self.set_force_render();
self.reapply_pane_frames();
}
pub fn reapply_pane_focus(&mut self) {
let connected_clients: Vec<ClientId> =
self.connected_clients.borrow().iter().copied().collect();
let mut stack_ids_to_pane_ids_to_expand = vec![];
for client_id in connected_clients {
match &self.active_panes.get(&client_id).copied() {
Some(pane_id) => {
if self
if let Some(stack_id) = self
.panes
.get(&pane_id)
.map(|p| p.current_geom().is_stacked())
.unwrap_or(false)
.and_then(|p| p.current_geom().stacked)
{
let _ =
StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.expand_pane(&pane_id);
stack_ids_to_pane_ids_to_expand.push((stack_id, *pane_id));
}
self.active_panes
.insert(client_id, *pane_id, &mut self.panes);
@ -680,18 +709,13 @@ impl TiledPanes {
},
None => {
if let Some(first_pane_id) = self.first_selectable_pane_id() {
let pane_id = first_pane_id; // TODO: combine with above
if self
let pane_id = first_pane_id;
if let Some(stack_id) = self
.panes
.get(&pane_id)
.map(|p| p.current_geom().is_stacked())
.unwrap_or(false)
.and_then(|p| p.current_geom().stacked)
{
let _ = StackedPanes::new_from_btreemap(
&mut self.panes,
&self.panes_to_hide,
)
.expand_pane(&pane_id);
stack_ids_to_pane_ids_to_expand.push((stack_id, pane_id));
}
self.active_panes
.insert(client_id, pane_id, &mut self.panes);
@ -700,6 +724,11 @@ impl TiledPanes {
},
}
}
for (stack_id, pane_id) in stack_ids_to_pane_ids_to_expand {
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.expand_pane(&pane_id);
self.focus_pane_for_all_clients_in_stack(pane_id, stack_id);
}
self.set_force_render();
self.reapply_pane_frames();
}
@ -745,14 +774,14 @@ impl TiledPanes {
// before changing focus
self.unset_fullscreen();
}
if self
if let Some(stack_id) = self
.panes
.get(&pane_id)
.map(|p| p.current_geom().is_stacked())
.unwrap_or(false)
.and_then(|p| p.current_geom().stacked)
{
let _ = StackedPanes::new_from_btreemap(&mut self.panes, &self.panes_to_hide)
.expand_pane(&pane_id);
self.focus_pane_for_all_clients_in_stack(pane_id, stack_id);
self.reapply_pane_frames();
}
self.active_panes
@ -1698,16 +1727,13 @@ impl TiledPanes {
.get_mut(self.active_panes.get(&client_id).unwrap())
.unwrap();
let previously_active_pane_is_stacked =
previously_active_pane.current_geom().is_stacked();
previously_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
previously_active_pane.render_full_viewport();
let next_active_pane = self.panes.get_mut(&p).unwrap();
let next_active_pane_is_stacked =
next_active_pane.current_geom().is_stacked();
let next_active_pane_stack_id = next_active_pane.current_geom().stacked;
next_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
@ -1715,11 +1741,11 @@ impl TiledPanes {
self.focus_pane(p, client_id);
self.set_pane_active_at(p);
if previously_active_pane_is_stacked || next_active_pane_is_stacked {
if let Some(stack_id) = next_active_pane_stack_id {
// we do this because a stack pane focus change also changes its
// geometry and we need to let the pty know about this (like in a
// normal size change)
self.focus_pane_for_all_clients(p); // TODO: for all client *in stack*
self.focus_pane_for_all_clients_in_stack(p, stack_id);
self.reapply_pane_frames();
}
@ -1752,16 +1778,13 @@ impl TiledPanes {
.get_mut(self.active_panes.get(&client_id).unwrap())
.unwrap();
let previously_active_pane_is_stacked =
previously_active_pane.current_geom().is_stacked();
previously_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
previously_active_pane.render_full_viewport();
let next_active_pane = self.panes.get_mut(&p).unwrap();
let next_active_pane_is_stacked =
next_active_pane.current_geom().is_stacked();
let next_active_pane_stack_id = next_active_pane.current_geom().stacked;
next_active_pane.set_should_render(true);
// we render the full viewport to remove any ui elements that might have been
// there before (eg. another user's cursor)
@ -1769,11 +1792,11 @@ impl TiledPanes {
self.focus_pane(p, client_id);
self.set_pane_active_at(p);
if previously_active_pane_is_stacked || next_active_pane_is_stacked {
if let Some(stack_id) = next_active_pane_stack_id {
// we do this because a stack pane focus change also changes its
// geometry and we need to let the pty know about this (like in a
// normal size change)
self.focus_pane_for_all_clients(p); // TODO: for all client *in stack*
self.focus_pane_for_all_clients_in_stack(p, stack_id);
self.reapply_pane_frames();
}

View file

@ -836,6 +836,16 @@ impl<'a> StackedPanes<'a> {
}
Some(positions_and_sizes_of_all_stacks)
}
pub fn pane_ids_in_stack(&self, stack_id: usize) -> Vec<PaneId> {
let panes = self.panes.borrow();
let mut pane_ids_in_stack = vec![];
for pane in panes.values() {
if pane.current_geom().stacked == Some(stack_id) {
pane_ids_in_stack.push(pane.pid());
}
}
pane_ids_in_stack
}
fn reset_stack_size(
&self,
new_position_and_size_of_stack: &PaneGeom,