summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMax Verevkin <34583604+MaxVerevkin@users.noreply.github.com>2023-06-01 16:34:33 +0300
committerGitHub <noreply@github.com>2023-06-01 16:34:33 +0300
commitaaaa16d9b7c54ff04e8548fe990fb1a54d454fa0 (patch)
tree9fe36b384cf106a02da8ecb4fb4cd93185b3755c /src
parent84b8dfe8cd190de33221f465a7059be6a30769f5 (diff)
parent13c08ca31ee1ccbbeceb8962d739a077048d59ac (diff)
downloadi3bar-mango-aaaa16d9b7c54ff04e8548fe990fb1a54d454fa0.tar.gz
Merge pull request #8 from MaxVerevkin/hyprland
Hyprland
Diffstat (limited to 'src')
-rw-r--r--src/pointer_btn.rs2
-rw-r--r--src/protocol.rs3
-rw-r--r--src/text.rs3
-rw-r--r--src/wm_info_provider.rs41
-rw-r--r--src/wm_info_provider/ext_workspace_unstable.rs215
-rw-r--r--src/wm_info_provider/river.rs1
6 files changed, 253 insertions, 12 deletions
diff --git a/src/pointer_btn.rs b/src/pointer_btn.rs
index 829fc9c..e5e0722 100644
--- a/src/pointer_btn.rs
+++ b/src/pointer_btn.rs
@@ -10,7 +10,7 @@ const BTN_FORWARD: u32 = 0x115;
const BTN_BACK: u32 = 0x116;
// const BTN_TASK: u32 = 0x117;
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PointerBtn {
Left,
Middle,
diff --git a/src/protocol.rs b/src/protocol.rs
index 5b30463..d14d92a 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -4,3 +4,6 @@ pub use wayrs_protocols::viewporter::*;
pub use wayrs_protocols::wlr_layer_shell_unstable_v1::*;
wayrs_client::scanner::generate!("protocols/river-status-unstable-v1.xml");
wayrs_client::scanner::generate!("protocols/river-control-unstable-v1.xml");
+
+#[cfg(feature = "hyprland")]
+wayrs_client::scanner::generate!("protocols/ext-workspace-unstable-v1.xml");
diff --git a/src/text.rs b/src/text.rs
index 61bf5ca..bc1516d 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -106,7 +106,8 @@ impl ComputedText {
context,
0.0,
0.0,
- self.width + options.overlap,
+ // HACK: this `+ 0.5` fixes some artifacts of fractional scaling
+ self.width + options.overlap + 0.5,
options.bar_height,
options.r_left,
options.r_right,
diff --git a/src/wm_info_provider.rs b/src/wm_info_provider.rs
index 12e4fb8..e11e48e 100644
--- a/src/wm_info_provider.rs
+++ b/src/wm_info_provider.rs
@@ -1,5 +1,3 @@
-mod river;
-
use wayrs_client::connection::Connection;
use wayrs_client::global::*;
@@ -7,9 +5,19 @@ use crate::pointer_btn::PointerBtn;
use crate::protocol::*;
use crate::state::State;
+#[cfg(feature = "hyprland")]
+mod ext_workspace_unstable;
+#[cfg(feature = "hyprland")]
+use ext_workspace_unstable::*;
+
+mod river;
+use river::*;
+
pub enum WmInfoProvider {
None,
- River(river::RiverInfoProvider),
+ River(RiverInfoProvider),
+ #[cfg(feature = "hyprland")]
+ Ewu(ExtWorkspaceUnstable),
}
pub type WmInfoCallback = fn(&mut Connection<State>, &mut State, WlOutput, WmInfo);
@@ -20,21 +28,33 @@ impl WmInfoProvider {
globals: &Globals,
callback: WmInfoCallback,
) -> WmInfoProvider {
- let Some(river) = river::RiverInfoProvider::bind(conn, globals, callback) else { return Self::None };
- Self::River(river)
+ if let Some(river) = RiverInfoProvider::bind(conn, globals, callback) {
+ return Self::River(river);
+ }
+
+ #[cfg(feature = "hyprland")]
+ if let Some(ext_wp_u) = ExtWorkspaceUnstable::bind(conn, globals, callback) {
+ return Self::Ewu(ext_wp_u);
+ }
+
+ Self::None
}
pub fn new_ouput(&mut self, conn: &mut Connection<State>, output: WlOutput) {
match self {
Self::None => (),
- Self::River(river) => river.new_output(conn, output),
+ Self::River(x) => x.new_output(conn, output),
+ #[cfg(feature = "hyprland")]
+ Self::Ewu(x) => x.new_ouput(conn, output),
}
}
pub fn output_removed(&mut self, conn: &mut Connection<State>, output: WlOutput) {
match self {
Self::None => (),
- Self::River(river) => river.output_removed(conn, output),
+ Self::River(x) => x.output_removed(conn, output),
+ #[cfg(feature = "hyprland")]
+ Self::Ewu(x) => x.output_removed(conn, output),
}
}
@@ -48,17 +68,20 @@ impl WmInfoProvider {
) {
match self {
Self::None => (),
- Self::River(river) => river.click_on_tag(conn, output, seat, tag, btn),
+ Self::River(x) => x.click_on_tag(conn, output, seat, tag, btn),
+ #[cfg(feature = "hyprland")]
+ Self::Ewu(x) => x.click_on_tag(conn, output, seat, tag, btn),
}
}
}
-#[derive(Default)]
+#[derive(Default, Debug)]
pub struct WmInfo {
pub layout_name: Option<String>,
pub tags: Vec<Tag>,
}
+#[derive(Debug)]
pub struct Tag {
pub name: String,
pub is_focused: bool,
diff --git a/src/wm_info_provider/ext_workspace_unstable.rs b/src/wm_info_provider/ext_workspace_unstable.rs
new file mode 100644
index 0000000..0af550b
--- /dev/null
+++ b/src/wm_info_provider/ext_workspace_unstable.rs
@@ -0,0 +1,215 @@
+use wayrs_client::connection::Connection;
+use wayrs_client::global::*;
+use wayrs_client::object::ObjectId;
+use wayrs_client::proxy::Proxy;
+
+use super::*;
+use crate::state::State;
+
+pub struct ExtWorkspaceUnstable {
+ manager: ZextWorkspaceManagerV1,
+ groups: Vec<Group>,
+ known_outputs: Vec<WlOutput>,
+ callback: WmInfoCallback,
+}
+
+#[derive(Debug)]
+struct Group {
+ group_handle: ZextWorkspaceGroupHandleV1,
+ workspaces: Vec<Workspace>,
+ outputs: Vec<ObjectId>,
+}
+
+#[derive(Debug)]
+struct Workspace {
+ workspace_handle: ZextWorkspaceHandleV1,
+ name: Option<String>,
+ is_focused: bool,
+ is_urgent: bool,
+}
+
+impl ExtWorkspaceUnstable {
+ pub fn bind(
+ conn: &mut Connection<State>,
+ globals: &Globals,
+ callback: WmInfoCallback,
+ ) -> Option<Self> {
+ Some(Self {
+ manager: globals.bind_with_cb(conn, 1..=1, manager_cb).ok()?,
+ groups: Vec::new(),
+ known_outputs: Vec::new(),
+ callback,
+ })
+ }
+}
+
+impl ExtWorkspaceUnstable {
+ pub fn new_ouput(&mut self, _: &mut Connection<State>, output: WlOutput) {
+ self.known_outputs.push(output);
+ }
+
+ pub fn output_removed(&mut self, _: &mut Connection<State>, output: WlOutput) {
+ self.known_outputs.retain(|&o| o != output);
+ for group in &mut self.groups {
+ group.outputs.retain(|&id| id != output.id());
+ }
+ }
+
+ pub fn click_on_tag(
+ &mut self,
+ conn: &mut Connection<State>,
+ _: WlOutput,
+ _: WlSeat,
+ tag: &str,
+ btn: PointerBtn,
+ ) {
+ if btn != PointerBtn::Left {
+ return;
+ }
+
+ let Some(ws) = self
+ .groups
+ .iter()
+ .find_map(|g| g.workspaces.iter().find(|w| w.name.as_deref() == Some(tag)))
+ else { return };
+
+ ws.workspace_handle.activate(conn);
+ self.manager.commit(conn);
+ }
+}
+
+fn manager_cb(
+ conn: &mut Connection<State>,
+ s: &mut State,
+ _: ZextWorkspaceManagerV1,
+ event: zext_workspace_manager_v1::Event,
+) {
+ let WmInfoProvider::Ewu(state) = &mut s.shared_state.wm_info_provider else { unreachable!() };
+
+ match event {
+ zext_workspace_manager_v1::Event::WorkspaceGroup(group_handle) => {
+ conn.set_callback_for(group_handle, group_cb);
+ state.groups.push(Group {
+ group_handle,
+ workspaces: Vec::new(),
+ outputs: Vec::new(),
+ });
+ }
+ zext_workspace_manager_v1::Event::Done => {
+ let mut events = Vec::new();
+ for &output in &state.known_outputs {
+ if let Some(group) = state
+ .groups
+ .iter()
+ .find(|g| g.outputs.contains(&output.id()))
+ {
+ let mut tags: Vec<_> = group
+ .workspaces
+ .iter()
+ .flat_map(|w| {
+ let name = w.name.clone()?;
+ Some(Tag {
+ name,
+ is_focused: w.is_focused,
+ is_active: true,
+ is_urgent: w.is_urgent,
+ })
+ })
+ .collect();
+ tags.sort_unstable_by(|a, b| a.name.cmp(&b.name));
+ events.push((output, tags));
+ }
+ }
+
+ let cb = state.callback;
+ for (output, tags) in events {
+ let info = WmInfo {
+ layout_name: None,
+ tags,
+ };
+ (cb)(conn, s, output, info);
+ }
+ }
+ zext_workspace_manager_v1::Event::Finished => unreachable!(),
+ }
+}
+
+fn group_cb(
+ conn: &mut Connection<State>,
+ state: &mut State,
+ group_handle: ZextWorkspaceGroupHandleV1,
+ event: zext_workspace_group_handle_v1::Event,
+) {
+ let WmInfoProvider::Ewu(state) = &mut state.shared_state.wm_info_provider else { unreachable!() };
+ let group = state
+ .groups
+ .iter_mut()
+ .find(|g| g.group_handle == group_handle)
+ .unwrap();
+
+ match event {
+ zext_workspace_group_handle_v1::Event::OutputEnter(output) => {
+ group.outputs.push(output);
+ }
+ zext_workspace_group_handle_v1::Event::OutputLeave(_) => todo!(),
+ zext_workspace_group_handle_v1::Event::Workspace(workspace_handle) => {
+ conn.set_callback_for(workspace_handle, workspace_cb);
+ group.workspaces.push(Workspace {
+ workspace_handle,
+ name: None,
+ is_focused: false,
+ is_urgent: false,
+ });
+ }
+ zext_workspace_group_handle_v1::Event::Remove => {
+ todo!();
+ }
+ }
+}
+
+fn workspace_cb(
+ conn: &mut Connection<State>,
+ state: &mut State,
+ workspace_handle: ZextWorkspaceHandleV1,
+ event: zext_workspace_handle_v1::Event,
+) {
+ let WmInfoProvider::Ewu(state) = &mut state.shared_state.wm_info_provider else { unreachable!() };
+ let group = state
+ .groups
+ .iter_mut()
+ .find(|g| {
+ g.workspaces
+ .iter()
+ .any(|w| w.workspace_handle == workspace_handle)
+ })
+ .unwrap();
+ let workspace = group
+ .workspaces
+ .iter_mut()
+ .find(|w| w.workspace_handle == workspace_handle)
+ .unwrap();
+
+ match event {
+ zext_workspace_handle_v1::Event::Name(name) => {
+ workspace.name = Some(name.to_string_lossy().into_owned());
+ }
+ zext_workspace_handle_v1::Event::Coordinates(_) => (),
+ zext_workspace_handle_v1::Event::State(state) => {
+ workspace.is_focused = false;
+ workspace.is_urgent = false;
+ for state in state
+ .chunks_exact(4)
+ .map(|b| u32::from_ne_bytes(b.try_into().unwrap()))
+ {
+ workspace.is_focused |= state == zext_workspace_handle_v1::State::Active as u32;
+ workspace.is_urgent |= state == zext_workspace_handle_v1::State::Urgent as u32;
+ }
+ }
+ zext_workspace_handle_v1::Event::Remove => {
+ group
+ .workspaces
+ .retain(|w| w.workspace_handle != workspace_handle);
+ workspace_handle.destroy(conn);
+ }
+ }
+}
diff --git a/src/wm_info_provider/river.rs b/src/wm_info_provider/river.rs
index c7740a3..82fa5d8 100644
--- a/src/wm_info_provider/river.rs
+++ b/src/wm_info_provider/river.rs
@@ -4,7 +4,6 @@ use wayrs_client::connection::Connection;
use wayrs_client::{cstr, global::*};
use super::*;
-use crate::protocol::*;
use crate::state::State;
pub struct RiverInfoProvider {