sort by output

This commit is contained in:
Henry Hiles 2026-04-21 11:18:03 -04:00
commit bb9fdfa83d
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 97 additions and 31 deletions

View file

@ -36,6 +36,7 @@ pub fn listen_workspaces(sink: StreamSink<Vec<Vec<Workspace>>>) -> Result<()> {
let qh = event_queue.handle(); let qh = event_queue.handle();
let mut state = AppState { let mut state = AppState {
outputs: HashMap::new(),
workspaces: HashMap::new(), workspaces: HashMap::new(),
workspace_groups: HashMap::new(), workspace_groups: HashMap::new(),
workspace_handles: HashMap::new(), workspace_handles: HashMap::new(),

View file

@ -2,7 +2,7 @@ use crate::{frb_generated::StreamSink, workspace_api::Workspace};
use std::collections::HashMap; use std::collections::HashMap;
use wayland_client::{ 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::{ use wayland_protocols::ext::workspace::v1::client::{
@ -14,36 +14,47 @@ pub struct WorkspaceHandles {
pub manager_handle: ext_workspace_manager_v1::ExtWorkspaceManagerV1, pub manager_handle: ext_workspace_manager_v1::ExtWorkspaceManagerV1,
} }
pub struct Output {
pub coords: (i32, i32),
}
pub struct WorkspaceGroup {
pub output_id: Option<u32>,
pub children: Vec<u32>,
}
pub struct AppState { pub struct AppState {
pub outputs: HashMap<u32, Output>,
pub workspaces: HashMap<u32, Workspace>, pub workspaces: HashMap<u32, Workspace>,
pub workspace_groups: HashMap<u32, u32>, pub workspace_groups: HashMap<u32, WorkspaceGroup>,
pub workspace_handles: HashMap<u32, WorkspaceHandles>, pub workspace_handles: HashMap<u32, WorkspaceHandles>,
pub sink: StreamSink<Vec<Vec<Workspace>>>, pub sink: StreamSink<Vec<Vec<Workspace>>>,
} }
impl AppState { impl AppState {
fn emit(&self) { fn emit(&self) {
let mut groups: HashMap<u32, Vec<(&u32, &Workspace)>> = HashMap::new(); let mut groups: Vec<_> = self.workspace_groups.values().collect();
for (ws_id, ws) in &self.workspaces { groups.sort_by_key(|group| {
if let Some(group_id) = self.workspace_groups.get(ws_id) { group.output_id.as_ref().and_then(|o| {
groups self.outputs.get(o).map(|info| info.coords.0)
.entry(group_id.clone()) })
.or_insert_with(Vec::new) });
.push((ws_id, ws));
}
}
let mut grouped: Vec<(u32, Vec<(&u32, &Workspace)>)> = groups.into_iter().collect(); let result: Vec<Vec<Workspace>> = groups
grouped.sort_by_key(|(group_id, _)| group_id.clone());
let result = grouped
.into_iter() .into_iter()
.map(|(_, mut entries)| { .map(|group| {
entries.sort_by_key(|(_, value)| value.coords); let mut workspaces: Vec<Workspace> = group
.children
.iter()
.filter_map(|id| self.workspaces.get(id))
.cloned()
.collect();
entries.into_iter().map(|(_, ws)| ws.clone()).collect() workspaces.sort_by_key(|ws|
ws.coords.as_ref().map(|coords| coords.0)
);
workspaces
}) })
.collect(); .collect();
@ -66,7 +77,8 @@ impl Dispatch<wl_registry::WlRegistry, ()> for AppState {
version, version,
} = event } = event
{ {
if interface == "ext_workspace_manager_v1" { match interface.as_str() {
"ext_workspace_manager_v1" => {
registry.bind::<ext_workspace_manager_v1::ExtWorkspaceManagerV1, (), AppState>( registry.bind::<ext_workspace_manager_v1::ExtWorkspaceManagerV1, (), AppState>(
name, name,
version, version,
@ -74,6 +86,18 @@ impl Dispatch<wl_registry::WlRegistry, ()> for AppState {
(), (),
); );
} }
"wl_output" => {
registry.bind::<wl_output::WlOutput, (), AppState>(
name,
version,
qh,
(),
);
}
_ => {}
}
} }
} }
} }
@ -192,7 +216,25 @@ impl Dispatch<ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, ()> for
ext_workspace_group_handle_v1::Event::WorkspaceEnter { workspace } => { ext_workspace_group_handle_v1::Event::WorkspaceEnter { workspace } => {
state state
.workspace_groups .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(); state.emit();
} }
@ -205,3 +247,26 @@ impl Dispatch<ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, ()> for
} }
} }
} }
impl Dispatch<wl_output::WlOutput, ()> for AppState {
fn event(
state: &mut Self,
proxy: &wl_output::WlOutput,
event: wl_output::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
match event {
wl_output::Event::Geometry {
x,
y,
..
} => {
state.outputs.insert(proxy.id().protocol_id(), Output { coords: ( x, y ) });
state.emit();
}
_ => {}
}
}
}