refactor: allow multiple actions for do_action

This commit is contained in:
atagen 2025-07-05 15:26:56 +10:00
parent 5a98a2022c
commit 555ffca915

View file

@ -135,7 +135,7 @@ impl NiriTag {
}
}
async fn do_action(&mut self, action: TagAction) -> Result<()> {
async fn do_actions(&mut self, actions: &[TagAction]) -> Result<()> {
use TagAction::*;
let (active, inactive): (HashMap<_, _>, HashMap<_, _>) = self
.state
@ -144,102 +144,103 @@ impl NiriTag {
.clone()
.into_iter()
.partition(|(_, ws)| ws.is_active);
match action {
Window(wid) => {
let current_tag = *self.windows.entry(wid).or_insert(0);
let tag_visible = self.tags.entry(current_tag).or_default().enabled;
let win = self
.state
.windows
.windows
.get(&wid)
.ok_or(anyhow!("Failed to retrieve window {} from niri state", wid))?;
let wsid: u64 = win
.workspace_id
.ok_or(anyhow!("Retrieving workspace id of a changed window"))?;
let win_visible = active.contains_key(&wsid);
match (win_visible, tag_visible) {
(true, false) => {
let inactive_same_output = self.same_output(wsid, &inactive)?;
tell(
&mut self.socket,
Request::Action(Action::MoveWindowToWorkspace {
window_id: Some(wid),
reference: WorkspaceReferenceArg::Id(inactive_same_output.id),
focus: false,
}),
)
.await
for action in actions {
match action {
Window(wid) => {
let current_tag = *self.windows.entry(*wid).or_insert(0);
let tag_visible = self.tags.entry(current_tag).or_default().enabled;
let win = self
.state
.windows
.windows
.get(wid)
.ok_or(anyhow!("Failed to retrieve window {} from niri state", wid))?;
let wsid: u64 = win
.workspace_id
.ok_or(anyhow!("Retrieving workspace id of a changed window"))?;
let win_visible = active.contains_key(&wsid);
match (win_visible, tag_visible) {
(true, false) => {
let inactive_same_output = self.same_output(wsid, &inactive)?;
tell(
&mut self.socket,
Request::Action(Action::MoveWindowToWorkspace {
window_id: Some(*wid),
reference: WorkspaceReferenceArg::Id(inactive_same_output.id),
focus: false,
}),
)
.await?
}
(false, true) => {
let active_same_output = self.same_output(wsid, &active)?;
tell(
&mut self.socket,
Request::Action(Action::MoveWindowToWorkspace {
window_id: Some(*wid),
reference: WorkspaceReferenceArg::Id(active_same_output.id),
focus: true,
}),
)
.await?
}
_ => (),
}
(false, true) => {
let active_same_output = self.same_output(wsid, &active)?;
tell(
&mut self.socket,
Request::Action(Action::MoveWindowToWorkspace {
window_id: Some(wid),
reference: WorkspaceReferenceArg::Id(active_same_output.id),
focus: true,
}),
)
.await
}
_ => Ok(()),
}
}
Tag(tag) => {
tracing::debug!("Changing tag {}", tag);
let tag_visible = self.tags.entry(tag).or_default().enabled;
let affected_windows: Vec<u64> = self
.windows
.iter()
.filter(|(_, t)| tag == **t)
.map(|(wid, _)| *wid)
.collect();
tracing::debug!(
"{} affected windows of tag {}: {:?}",
affected_windows.len(),
tag,
affected_windows
);
let focus = affected_windows.last().cloned();
self.move_windows(
if tag_visible { &active } else { &inactive },
affected_windows,
)
.await;
if let Some(focus) = focus {
if tag_visible {
Tag(tag) => {
tracing::debug!("Changing tag {}", tag);
let tag_visible = self.tags.entry(*tag).or_default().enabled;
let affected_windows: Vec<u64> = self
.windows
.iter()
.filter(|(_, t)| *tag == **t)
.map(|(wid, _)| *wid)
.collect();
tracing::debug!(
"{} affected windows of tag {}: {:?}",
affected_windows.len(),
tag,
affected_windows
);
let focus = affected_windows.last().cloned();
self.move_windows(
if tag_visible { &active } else { &inactive },
affected_windows,
)
.await;
if let Some(focus) = focus {
if tag_visible {
tell(
&mut self.socket,
Request::Action(Action::FocusWindow { id: focus }),
)
.await?;
}
}
}
TagExclusive(t) => {
tracing::debug!("Changing all tags");
let (active_wid, inactive_wid): (HashMap<u64, u8>, HashMap<u64, u8>) = self
.windows
.iter()
.filter(|(_, it)| **it != 0)
.partition(|(_, it)| **it == *t);
let focus = active_wid.keys().last();
self.move_windows(&inactive, inactive_wid.keys().cloned().collect())
.await;
self.move_windows(&active, active_wid.keys().cloned().collect())
.await;
if let Some(f) = focus {
tell(
&mut self.socket,
Request::Action(Action::FocusWindow { id: focus }),
Request::Action(Action::FocusWindow { id: *f }),
)
.await?;
}
}
Ok(())
}
TagExclusive(t) => {
tracing::debug!("Changing all tags");
let (active_wid, inactive_wid): (HashMap<u64, u8>, HashMap<u64, u8>) = self
.windows
.iter()
.filter(|(_, it)| **it != 0)
.partition(|(_, it)| **it == t);
let focus = active_wid.keys().last();
self.move_windows(&inactive, inactive_wid.keys().cloned().collect())
.await;
self.move_windows(&active, active_wid.keys().cloned().collect())
.await;
if let Some(f) = focus {
tell(
&mut self.socket,
Request::Action(Action::FocusWindow { id: *f }),
)
.await?;
}
Ok(())
}
}
Ok(())
}
async fn get_focused_window(&mut self) -> Result<Window> {
@ -275,7 +276,7 @@ impl NiriTag {
async fn handle_recvd(&mut self, recvd: Receivable) -> Result<()> {
use TagAction::*;
// first do any local mutations
let action: TagAction = match recvd {
let actions: &[TagAction] = match recvd {
Receivable::Event(ev) => {
let _ = self.state.apply(ev.clone());
return self.handle_event(ev).await;
@ -294,12 +295,12 @@ impl NiriTag {
TagCmd::AddTagToWin(t) => {
let wid = self.get_focused_window().await?.id;
self.change_window_tag(wid, Some(t)).await?;
Window(wid)
&[Window(wid)]
}
TagCmd::RemoveTagFromWin(_) => {
let wid = self.get_focused_window().await?.id;
self.change_window_tag(wid, None).await?;
Window(wid)
&[Window(wid)]
}
TagCmd::ToggleTagOnWin(t) => {
let wid = self.get_focused_window().await?.id;
@ -310,7 +311,7 @@ impl NiriTag {
};
self.change_window_tag(wid, Some(new_tag)).await?;
tracing::debug!("toggling {} to tag {}", wid, new_tag);
Window(wid)
&[Window(wid)]
}
TagCmd::EnableTag(t) => {
@ -319,7 +320,7 @@ impl NiriTag {
.and_modify(|ts| ts.enabled = true)
.or_default();
self.fire_event(TagEvent::TagEnabled(t)).await;
Tag(t)
&[Tag(t)]
}
TagCmd::DisableTag(t) => {
self.tags
@ -327,7 +328,7 @@ impl NiriTag {
.and_modify(|ts| ts.enabled = false)
.or_default();
self.fire_event(TagEvent::TagDisabled(t)).await;
Tag(t)
&[Tag(t)]
}
TagCmd::ToggleTag(t) => {
let new_state = self
@ -342,7 +343,7 @@ impl NiriTag {
TagEvent::TagDisabled(t)
})
.await;
Tag(t)
&[Tag(t)]
}
TagCmd::ExclusiveTag(t) => {
self.tags
@ -354,12 +355,12 @@ impl NiriTag {
.filter(|(it, _)| **it != 0)
.for_each(|(it, ts)| ts.enabled = *it == t);
self.fire_event(TagEvent::TagExclusive(t)).await;
TagExclusive(t)
&[TagExclusive(t)]
}
},
};
// then arrange corresponding state in the compositor
self.do_action(action).await?;
self.do_actions(actions).await?;
tell(
&mut self.socket,
Request::Action(Action::CenterVisibleColumns {}),
@ -431,7 +432,7 @@ impl NiriTag {
WindowsChanged { windows } => {
for w in windows {
self.change_window_tag(w.id, None).await?;
let action = self.do_action(TagAction::Window(w.id)).await;
let action = self.do_actions(&[TagAction::Window(w.id)]).await;
if let Err(e) = action {
tracing::warn!("Failed to ChangeWindow on {}: {}", w.id, e);
}