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

View file

@ -836,6 +836,16 @@ impl<'a> StackedPanes<'a> {
} }
Some(positions_and_sizes_of_all_stacks) 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( fn reset_stack_size(
&self, &self,
new_position_and_size_of_stack: &PaneGeom, new_position_and_size_of_stack: &PaneGeom,