1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
use std::collections::HashMap;
use zbus::fdo::{self, RequestNameFlags};
use zbus::interface;
use zbus::object_server::SignalEmitter;
use zbus::zvariant::{SerializeDict, Type, Value};
use super::Start;
pub struct Introspect {
to_niri: calloop::channel::Sender<IntrospectToNiri>,
from_niri: async_channel::Receiver<NiriToIntrospect>,
}
pub enum IntrospectToNiri {
GetWindows,
}
pub enum NiriToIntrospect {
Windows(HashMap<u64, WindowProperties>),
}
#[derive(Debug, SerializeDict, Type, Value)]
#[zvariant(signature = "dict")]
pub struct WindowProperties {
/// Window title.
pub title: String,
/// Window app ID.
///
/// This is actually the name of the .desktop file, and Shell does internal tracking to match
/// Wayland app IDs to desktop files. We don't do that yet, which is the reason why
/// xdg-desktop-portal-gnome's window list is missing icons.
#[zvariant(rename = "app-id")]
pub app_id: String,
}
#[interface(name = "org.gnome.Shell.Introspect")]
impl Introspect {
async fn get_windows(&self) -> fdo::Result<HashMap<u64, WindowProperties>> {
if let Err(err) = self.to_niri.send(IntrospectToNiri::GetWindows) {
warn!("error sending message to niri: {err:?}");
return Err(fdo::Error::Failed("internal error".to_owned()));
}
match self.from_niri.recv().await {
Ok(NiriToIntrospect::Windows(windows)) => Ok(windows),
Err(err) => {
warn!("error receiving message from niri: {err:?}");
Err(fdo::Error::Failed("internal error".to_owned()))
}
}
}
// FIXME: call this upon window changes, once more of the infrastructure is there (will be
// needed for the event stream IPC anyway).
#[zbus(signal)]
pub async fn windows_changed(ctxt: &SignalEmitter<'_>) -> zbus::Result<()>;
}
impl Introspect {
pub fn new(
to_niri: calloop::channel::Sender<IntrospectToNiri>,
from_niri: async_channel::Receiver<NiriToIntrospect>,
) -> Self {
Self { to_niri, from_niri }
}
}
impl Start for Introspect {
fn start(self) -> anyhow::Result<zbus::blocking::Connection> {
let conn = zbus::blocking::Connection::session()?;
let flags = RequestNameFlags::AllowReplacement
| RequestNameFlags::ReplaceExisting
| RequestNameFlags::DoNotQueue;
conn.object_server()
.at("/org/gnome/Shell/Introspect", self)?;
conn.request_name_with_flags("org.gnome.Shell.Introspect", flags)?;
Ok(conn)
}
}
|