From dbcaa1989747e7a00cc37d411172c02a32e1107a Mon Sep 17 00:00:00 2001 From: MaxVerevkin Date: Wed, 11 Sep 2024 00:19:30 +0300 Subject: [PATCH] scrolling between tags/workspaces --- src/bar.rs | 5 ++- src/button_manager.rs | 10 ++++++ src/wm_info_provider.rs | 4 +-- src/wm_info_provider/hyprland.rs | 43 ++++++++++++++++++++--- src/wm_info_provider/river.rs | 58 ++++++++++++++++++++++++-------- 5 files changed, 99 insertions(+), 21 deletions(-) diff --git a/src/bar.rs b/src/bar.rs index 18be97e..afb221d 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -123,7 +123,10 @@ impl Bar { ) -> anyhow::Result<()> { if let Some(tag_id) = self.tags_btns.click(x) { ss.wm_info_provider - .click_on_tag(conn, self.output.wl, seat, *tag_id, button); + .click_on_tag(conn, &self.output, seat, Some(*tag_id), button); + } else if self.tags_btns.is_between(x) { + ss.wm_info_provider + .click_on_tag(conn, &self.output, seat, None, button); } else if let Some((name, instance)) = self.blocks_btns.click(x) { if let Some(cmd) = &mut ss.status_cmd { cmd.send_click_event(&i3bar_protocol::Event { diff --git a/src/button_manager.rs b/src/button_manager.rs index 9981229..13f9124 100644 --- a/src/button_manager.rs +++ b/src/button_manager.rs @@ -16,4 +16,14 @@ impl ButtonManager { .find(|(x_off, w, _)| x >= *x_off && x <= *x_off + *w) .map(|(_, _, e)| e) } + + pub fn is_between(&self, x: f64) -> bool { + let mut left = false; + let mut right = false; + for &(x_off, w, _) in &self.0 { + left |= x_off <= x; + right |= x_off + w >= x; + } + left && right + } } diff --git a/src/wm_info_provider.rs b/src/wm_info_provider.rs index 80f4f35..a8ee3be 100644 --- a/src/wm_info_provider.rs +++ b/src/wm_info_provider.rs @@ -38,9 +38,9 @@ pub trait WmInfoProvider { fn click_on_tag( &mut self, _conn: &mut Connection, - _output: WlOutput, + _output: &Output, _seat: WlSeat, - _tag_id: u32, + _tag_id: Option, _btn: PointerBtn, ) { } diff --git a/src/wm_info_provider/hyprland.rs b/src/wm_info_provider/hyprland.rs index 29b86b3..a59a68f 100644 --- a/src/wm_info_provider/hyprland.rs +++ b/src/wm_info_provider/hyprland.rs @@ -1,3 +1,5 @@ +#![allow(clippy::collapsible_else_if)] + use std::io::{self, Write}; use std::os::fd::AsRawFd; use std::os::unix::net::UnixStream; @@ -25,6 +27,10 @@ impl HyprlandInfoProvider { ipc, }) } + + fn set_workspace(&self, id: u32) { + let _ = self.ipc.exec(&format!("/dispatch workspace {id}")); + } } impl WmInfoProvider for HyprlandInfoProvider { @@ -57,13 +63,42 @@ impl WmInfoProvider for HyprlandInfoProvider { fn click_on_tag( &mut self, _: &mut Connection, - _: WlOutput, + output: &Output, _: WlSeat, - tag_id: u32, + tag_id: Option, btn: PointerBtn, ) { - if btn == PointerBtn::Left { - let _ = self.ipc.exec(&format!("/dispatch workspace {tag_id}")); + match btn { + PointerBtn::Left => { + if let Some(tag_id) = tag_id { + self.set_workspace(tag_id); + } + } + PointerBtn::WheelUp | PointerBtn::WheelDown => { + if let Some(active_i) = self + .workspaces + .iter() + .position(|ws| ws.monitor == output.name && self.active_id == ws.id) + { + if btn == PointerBtn::WheelUp { + if let Some(prev) = self.workspaces[..active_i] + .iter() + .rfind(|ws| ws.monitor == output.name) + { + self.set_workspace(prev.id); + } + } else { + if let Some(next) = self.workspaces[active_i..] + .iter() + .skip(1) + .find(|ws| ws.monitor == output.name) + { + self.set_workspace(next.id); + } + } + } + } + _ => (), } } diff --git a/src/wm_info_provider/river.rs b/src/wm_info_provider/river.rs index 4763f9f..f50eefe 100644 --- a/src/wm_info_provider/river.rs +++ b/src/wm_info_provider/river.rs @@ -52,6 +52,15 @@ impl RiverInfoProvider { }, }) } + + fn set_focused_tags(&self, seat: WlSeat, conn: &mut Connection, tags: u32) { + self.control + .add_argument(conn, c"set-focused-tags".to_owned()); + self.control + .add_argument(conn, CString::new(tags.to_string()).unwrap()); + self.control + .run_command_with_cb(conn, seat, river_command_cb); + } } impl WmInfoProvider for RiverInfoProvider { @@ -109,23 +118,44 @@ impl WmInfoProvider for RiverInfoProvider { fn click_on_tag( &mut self, conn: &mut Connection, - _output: WlOutput, + output: &Output, seat: WlSeat, - tag_id: u32, + tag_id: Option, btn: PointerBtn, ) { - let cmd = match btn { - PointerBtn::Left => c"set-focused-tags", - PointerBtn::Right => c"toggle-focused-tags", - _ => return, - }; - self.control.add_argument(conn, cmd.to_owned()); - self.control.add_argument( - conn, - CString::new((1u32 << (tag_id - 1)).to_string()).unwrap(), - ); - self.control - .run_command_with_cb(conn, seat, river_command_cb); + match btn { + PointerBtn::Left => { + if let Some(tag_id) = tag_id { + self.set_focused_tags(seat, conn, 1u32 << (tag_id - 1)); + } + } + PointerBtn::Right => { + if let Some(tag_id) = tag_id { + self.control + .add_argument(conn, c"toggle-focused-tags".to_owned()); + self.control.add_argument( + conn, + CString::new((1u32 << (tag_id - 1)).to_string()).unwrap(), + ); + self.control + .run_command_with_cb(conn, seat, river_command_cb); + } + } + PointerBtn::WheelUp | PointerBtn::WheelDown => { + if let Some(status) = self.output_statuses.iter().find(|s| s.output == output.wl) { + let mut new_tags = if btn == PointerBtn::WheelUp { + status.focused_tags >> 1 + } else { + status.focused_tags << 1 + }; + if new_tags == 0 { + new_tags |= status.focused_tags & 0x8000_0001; + } + self.set_focused_tags(seat, conn, new_tags); + } + } + _ => (), + } } fn as_any(&mut self) -> &mut dyn Any {