diff --git a/rust/src/api/workspace_api.rs b/rust/src/api/workspace_api.rs index 3daed88..46bc884 100644 --- a/rust/src/api/workspace_api.rs +++ b/rust/src/api/workspace_api.rs @@ -36,6 +36,7 @@ pub fn listen_workspaces(sink: StreamSink>>) -> Result<()> { let qh = event_queue.handle(); let mut state = AppState { + outputs: HashMap::new(), workspaces: HashMap::new(), workspace_groups: HashMap::new(), workspace_handles: HashMap::new(), diff --git a/rust/src/internal/wayland.rs b/rust/src/internal/wayland.rs index 4b83601..8cac70e 100644 --- a/rust/src/internal/wayland.rs +++ b/rust/src/internal/wayland.rs @@ -2,7 +2,7 @@ use crate::{frb_generated::StreamSink, workspace_api::Workspace}; use std::collections::HashMap; use wayland_client::{ - self, event_created_child, protocol::wl_registry, Connection, Dispatch, Proxy, QueueHandle, + self, event_created_child, protocol::{wl_registry, wl_output}, Connection, Dispatch, Proxy, QueueHandle, }; use wayland_protocols::ext::workspace::v1::client::{ @@ -14,38 +14,49 @@ pub struct WorkspaceHandles { pub manager_handle: ext_workspace_manager_v1::ExtWorkspaceManagerV1, } +pub struct Output { + pub coords: (i32, i32), +} + +pub struct WorkspaceGroup { + pub output_id: Option, + pub children: Vec, +} + pub struct AppState { + pub outputs: HashMap, pub workspaces: HashMap, - pub workspace_groups: HashMap, + pub workspace_groups: HashMap, pub workspace_handles: HashMap, pub sink: StreamSink>>, } impl AppState { fn emit(&self) { - let mut groups: HashMap> = HashMap::new(); + let mut groups: Vec<_> = self.workspace_groups.values().collect(); - for (ws_id, ws) in &self.workspaces { - if let Some(group_id) = self.workspace_groups.get(ws_id) { - groups - .entry(group_id.clone()) - .or_insert_with(Vec::new) - .push((ws_id, ws)); - } - } + groups.sort_by_key(|group| { + group.output_id.as_ref().and_then(|o| { + self.outputs.get(o).map(|info| info.coords.0) + }) + }); - let mut grouped: Vec<(u32, Vec<(&u32, &Workspace)>)> = groups.into_iter().collect(); + let result: Vec> = groups + .into_iter() + .map(|group| { + let mut workspaces: Vec = group + .children + .iter() + .filter_map(|id| self.workspaces.get(id)) + .cloned() + .collect(); - grouped.sort_by_key(|(group_id, _)| group_id.clone()); - - let result = grouped - .into_iter() - .map(|(_, mut entries)| { - entries.sort_by_key(|(_, value)| value.coords); - - entries.into_iter().map(|(_, ws)| ws.clone()).collect() - }) - .collect(); + workspaces.sort_by_key(|ws| + ws.coords.as_ref().map(|coords| coords.0) + ); + workspaces + }) + .collect(); self.sink.add(result).expect("Updating stream failed"); } @@ -66,14 +77,27 @@ impl Dispatch for AppState { version, } = event { - if interface == "ext_workspace_manager_v1" { - registry.bind::( - name, - version, - qh, - (), - ); - } + match interface.as_str() { + "ext_workspace_manager_v1" => { + registry.bind::( + name, + version, + qh, + (), + ); + } + + "wl_output" => { + registry.bind::( + name, + version, + qh, + (), + ); + } + + _ => {} + } } } } @@ -192,7 +216,25 @@ impl Dispatch for ext_workspace_group_handle_v1::Event::WorkspaceEnter { workspace } => { state .workspace_groups - .insert(workspace.id().protocol_id(), group_id.protocol_id()); + .entry(group_id.protocol_id()) + .or_insert_with(|| WorkspaceGroup { + output_id: None, + children: Vec::new(), + }) + .children + .push(workspace.id().protocol_id()); + state.emit(); + } + + ext_workspace_group_handle_v1::Event::OutputEnter { output } => { + state + .workspace_groups + .entry(group_id.protocol_id()) + .or_insert_with(|| WorkspaceGroup { + output_id: None, + children: Vec::new(), + }) + .output_id = Some(output.id().protocol_id()); state.emit(); } @@ -205,3 +247,26 @@ impl Dispatch for } } } + +impl Dispatch for AppState { + fn event( + state: &mut Self, + proxy: &wl_output::WlOutput, + event: wl_output::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle, + ) { + match event { + wl_output::Event::Geometry { + x, + y, + .. + } => { + state.outputs.insert(proxy.id().protocol_id(), Output { coords: ( x, y ) }); + state.emit(); + } + _ => {} + } + } +} \ No newline at end of file