Skip to content

Commit

Permalink
client-toolkit/toplevel-info: Work with only ext foreign toplevel
Browse files Browse the repository at this point in the history
With this, `toplevel-monitor` works on Sway, but doesn't have the
information exposed through the Cosmic protocol, naturally.

The API is changed to use `ExtForeignToplevelHandleV1`. For convenience,
`ToplevelInfo` contains the foreign handle, and the optional cosmic
handle.

I assume `identifier` is meant to be mandatory, so that is no longer an
`Option` here. Though there's no check that the server sends this (is
server-side code, this would send a protocol error; I guess cctk could
panic, or log an error.)
  • Loading branch information
ids1024 committed Feb 4, 2025
1 parent bc8eded commit 61eb193
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 38 deletions.
8 changes: 4 additions & 4 deletions client-toolkit/examples/toplevel-monitor.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use cosmic_client_toolkit::toplevel_info::{ToplevelInfoHandler, ToplevelInfoState};
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1;
use sctk::{
output::{OutputHandler, OutputState},
registry::{ProvidesRegistryState, RegistryState},
};
use wayland_client::{globals::registry_queue_init, protocol::wl_output, Connection, QueueHandle};
use wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1;

struct AppData {
output_state: OutputState,
Expand Down Expand Up @@ -60,7 +60,7 @@ impl ToplevelInfoHandler for AppData {
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
) {
println!(
"New toplevel: {:?}",
Expand All @@ -72,7 +72,7 @@ impl ToplevelInfoHandler for AppData {
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
) {
println!(
"Update toplevel: {:?}",
Expand All @@ -84,7 +84,7 @@ impl ToplevelInfoHandler for AppData {
&mut self,
_conn: &Connection,
_qh: &QueueHandle<Self>,
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
) {
println!(
"Closed toplevel: {:?}",
Expand Down
82 changes: 48 additions & 34 deletions client-toolkit/src/toplevel_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@ pub struct ToplevelGeometry {
pub struct ToplevelInfo {
pub title: String,
pub app_id: String,
pub identifier: Option<String>,
pub identifier: String,
/// Requires zcosmic_toplevel_info_v1 version 2
pub state: HashSet<zcosmic_toplevel_handle_v1::State>,
/// Requires zcosmic_toplevel_info_v1 version 2
pub output: HashSet<wl_output::WlOutput>,
/// Requires zcosmic_toplevel_info_v1 version 2
pub geometry: HashMap<wl_output::WlOutput, ToplevelGeometry>,
/// Requires zcosmic_toplevel_info_v1 version 2
pub workspace: HashSet<zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1>,
pub cosmic_toplevel: Option<zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1>,
pub foreign_toplevel: ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
}

Expand All @@ -44,11 +49,12 @@ impl ToplevelData {
let pending_info = ToplevelInfo {
title: String::new(),
app_id: String::new(),
identifier: None,
identifier: String::new(),
state: HashSet::new(),
output: HashSet::new(),
geometry: HashMap::new(),
workspace: HashSet::new(),
cosmic_toplevel: None,
foreign_toplevel,
};
Self {
Expand All @@ -57,16 +63,23 @@ impl ToplevelData {
has_cosmic_info: false,
}
}

fn cosmic_toplevel(&self) -> Option<&zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1> {
self.pending_info.cosmic_toplevel.as_ref()
}

fn foreign_toplevel(&self) -> &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1 {
&self.pending_info.foreign_toplevel
}
}

/// Handler for `ext-foreign-toplevel-list-v1`, and optionally
/// `cosmic-toplevel-info-unstable-v1` which extends it with additional information.
#[derive(Debug)]
pub struct ToplevelInfoState {
pub foreign_toplevel_list: ext_foreign_toplevel_list_v1::ExtForeignToplevelListV1,
pub cosmic_toplevel_info: zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1,
toplevels: Vec<(
zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
ToplevelData,
)>,
pub cosmic_toplevel_info: Option<zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1>,
toplevels: Vec<ToplevelData>,
}

impl ToplevelInfoState {
Expand All @@ -89,7 +102,7 @@ impl ToplevelInfoState {
2..=2,
GlobalData,
)
.ok()?;
.ok();

Some(Self {
foreign_toplevel_list,
Expand All @@ -109,12 +122,11 @@ impl ToplevelInfoState {

pub fn info(
&self,
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
) -> Option<&ToplevelInfo> {
self.toplevels
.iter()
.find(|(x, _)| x == toplevel)?
.1
.find(|data| data.foreign_toplevel() == toplevel)?
.current_info
.as_ref()
}
Expand All @@ -123,13 +135,13 @@ impl ToplevelInfoState {
&self,
) -> impl Iterator<
Item = (
&zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
&ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
Option<&ToplevelInfo>,
),
> {
self.toplevels
.iter()
.map(|(toplevel, data)| (toplevel, data.current_info.as_ref()))
.map(|data| (data.foreign_toplevel(), data.current_info.as_ref()))
}
}

Expand All @@ -140,21 +152,21 @@ pub trait ToplevelInfoHandler: Sized {
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
);

fn update_toplevel(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
);

fn toplevel_closed(
&mut self,
conn: &Connection,
qh: &QueueHandle<Self>,
toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
toplevel: &ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
);

fn info_done(&mut self, _conn: &Connection, _qh: &QueueHandle<Self>) {}
Expand Down Expand Up @@ -213,9 +225,8 @@ where
.toplevel_info_state()
.toplevels
.iter_mut()
.find(|(x, _)| x == toplevel)
.expect("Received event for dead toplevel")
.1;
.find(|data| data.cosmic_toplevel() == Some(toplevel))
.expect("Received event for dead toplevel");
match event {
zcosmic_toplevel_handle_v1::Event::OutputEnter { output } => {
data.pending_info.output.insert(output);
Expand Down Expand Up @@ -288,11 +299,13 @@ where
match event {
ext_foreign_toplevel_list_v1::Event::Toplevel { toplevel } => {
let info_state = state.toplevel_info_state();
let cosmic_toplevel = info_state
.cosmic_toplevel_info
.get_cosmic_toplevel(&toplevel, qh, GlobalData);
let toplevel_data = ToplevelData::new(toplevel);
info_state.toplevels.push((cosmic_toplevel, toplevel_data));
let mut toplevel_data = ToplevelData::new(toplevel.clone());
if let Some(cosmic_toplevel_info) = &info_state.cosmic_toplevel_info {
let cosmic_toplevel =
cosmic_toplevel_info.get_cosmic_toplevel(&toplevel, qh, GlobalData);
toplevel_data.pending_info.cosmic_toplevel = Some(cosmic_toplevel);
}
info_state.toplevels.push(toplevel_data);
}
ext_foreign_toplevel_list_v1::Event::Finished => {
state.finished(conn, qh);
Expand Down Expand Up @@ -321,36 +334,37 @@ where
conn: &Connection,
qh: &QueueHandle<D>,
) {
let (toplevel, data) = &mut state
let data = &mut state
.toplevel_info_state()
.toplevels
.iter_mut()
.find(|(_, data)| data.pending_info.foreign_toplevel == *handle)
.find(|data| data.foreign_toplevel() == handle)
.expect("Received event for dead toplevel");
match event {
ext_foreign_toplevel_handle_v1::Event::Closed => {
let toplevel = toplevel.clone();
state.toplevel_closed(conn, qh, &toplevel);
state.toplevel_closed(conn, qh, handle);

let toplevels = &mut state.toplevel_info_state().toplevels;
if let Some(idx) = toplevels.iter().position(|(handle, _)| handle == &toplevel) {
if let Some(idx) = toplevels
.iter()
.position(|data| data.foreign_toplevel() == handle)
{
toplevels.remove(idx);
}
}
ext_foreign_toplevel_handle_v1::Event::Done => {
if !data.has_cosmic_info {
if data.cosmic_toplevel().is_some() && !data.has_cosmic_info {
// Don't call `new_toplevel` if we have the `ext_foreign_toplevel_handle_v1`,
// but don't have any `zcosmic_toplevel_handle_v1` events yet.
return;
}

let is_new = data.current_info.is_none();
data.current_info = Some(data.pending_info.clone());
let toplevel = toplevel.clone();
if is_new {
state.new_toplevel(conn, qh, &toplevel);
state.new_toplevel(conn, qh, handle);
} else {
state.update_toplevel(conn, qh, &toplevel);
state.update_toplevel(conn, qh, handle);
}
}
ext_foreign_toplevel_handle_v1::Event::Title { title } => {
Expand All @@ -360,7 +374,7 @@ where
data.pending_info.app_id = app_id;
}
ext_foreign_toplevel_handle_v1::Event::Identifier { identifier } => {
data.pending_info.identifier = Some(identifier);
data.pending_info.identifier = identifier;
}
_ => unreachable!(),
}
Expand Down

0 comments on commit 61eb193

Please sign in to comment.