Skip to content

Commit

Permalink
Add cosmic support for window tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
Exidex committed Dec 31, 2024
1 parent 434dd7a commit 4f2add8
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 20 deletions.
37 changes: 37 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/plugin_runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ encoding = "0.2"
freedesktop_entry_parser = "1.3"
freedesktop-icons = "0.2"
wayland-protocols-wlr = { version = "0.3.5", features = ["client"] }
cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols.git" }
wayland-client = "0.31.7"
smithay-client-toolkit = "0.19.2"

Expand Down
4 changes: 3 additions & 1 deletion rust/plugin_runtime/src/plugins/applications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,16 +101,18 @@ pub enum DesktopEnvironment {

impl DesktopEnvironment {
fn new() -> anyhow::Result<Self> {
#[cfg(target_os = "linux")]
let result = Ok(Self::Linux(linux::LinuxDesktopEnvironment::new()?));

#[cfg(not(target_os = "linux"))]
let result = None;
let result = Ok(Self::None);

result
}

fn is_wayland(&self) -> bool {
match self {
#[cfg(target_os = "linux")]
DesktopEnvironment::Linux(linux) => linux.is_wayland(),
DesktopEnvironment::None => false
}
Expand Down
177 changes: 177 additions & 0 deletions rust/plugin_runtime/src/plugins/applications/linux/wayland/cosmic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use anyhow::anyhow;
use smithay_client_toolkit::reexports::calloop::channel::Sender;
use smithay_client_toolkit::seat::SeatState;
use tokio::runtime::Handle;
use crate::plugins::applications::linux::wayland::{send_event, JsWaylandApplicationEvent, WaylandState, WaylandStateInner};
use wayland_client::globals::GlobalList;
use wayland_client::{event_created_child, Connection, Dispatch, Proxy, QueueHandle};
use wayland_client::backend::ObjectId;
use wayland_client::protocol::wl_seat::WlSeat;
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1;
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_info_v1;
use cosmic_protocols::toplevel_management::v1::client::zcosmic_toplevel_manager_v1;

pub struct CosmicWaylandState {
uuid_to_obj_id: HashMap<String, ObjectId>,
obj_id_to_uuid: HashMap<ObjectId, String>,
toplevels: HashMap<ObjectId, zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1>,
management: zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1,
}

impl CosmicWaylandState {
pub fn new(globals: &GlobalList, queue_handle: &QueueHandle<WaylandState>) -> anyhow::Result<Self> {
let management = globals
.bind::<zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1, _, _>(
&queue_handle,
3..=3,
(),
)?;

Ok(Self {
management,
uuid_to_obj_id: HashMap::new(),
obj_id_to_uuid: HashMap::new(),
toplevels: HashMap::new(),
})
}

pub fn focus_window(&self, window_uuid: String, seat_state: &SeatState) -> anyhow::Result<()> {
let obj_id = self.uuid_to_obj_id
.get(&window_uuid)
.ok_or(anyhow!("Unable to find object id for window uuid: {}", window_uuid))?;

let toplevel = self.toplevels
.get(&obj_id)
.ok_or(anyhow!("Unable to find object id for window uuid: {}", window_uuid))?;

match seat_state.seats().next() {
Some(seat) => self.management.activate(&toplevel, &seat),
None => Err(anyhow!("no wayland seats found"))?
};

Ok(())
}
}

impl Dispatch<zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1, ()> for WaylandState {
fn event(
_state: &mut Self,
_proxy: &zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1,
_event: <zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1 as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>
) {
}
}

impl Dispatch<zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1, ()> for WaylandState {
fn event(
state: &mut Self,
_proxy: &zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1,
event: <zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1 as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
match event {
zcosmic_toplevel_info_v1::Event::Toplevel { toplevel } => {
match &mut state.inner {
WaylandStateInner::Cosmic(inner) => {
let window_id = uuid::Uuid::new_v4().to_string();

inner.uuid_to_obj_id.insert(window_id.clone(), toplevel.id());
inner.obj_id_to_uuid.insert(toplevel.id(), window_id.clone());
inner.toplevels.insert(toplevel.id(), toplevel);

send_event(&state.tokio_handle, &state.sender, JsWaylandApplicationEvent::WindowOpened {
window_id,
});
}
_ => {}
}
}
_ => {}
}
}

event_created_child!(WaylandState, zcosmic_toplevel_info_v1::ZcosmicToplevelInfoV1, [
zcosmic_toplevel_info_v1::EVT_TOPLEVEL_OPCODE => (zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, ()),
]);
}

impl Dispatch<zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, ()> for WaylandState {
fn event(
state: &mut Self,
proxy: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
event: <zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1 as Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
match event {
zcosmic_toplevel_handle_v1::Event::Title { title } => {
match &state.inner {
WaylandStateInner::Cosmic(inner) => {
match inner.obj_id_to_uuid.get(&proxy.id()) {
Some(window_id) => {
send_event(&state.tokio_handle, &state.sender, JsWaylandApplicationEvent::WindowTitleChanged {
window_id: window_id.clone(),
title,
});
}
None => {
tracing::warn!("Received event for cosmic wayland toplevel that doesn't exist in state");
}
}
}
_ => {}
}
}
zcosmic_toplevel_handle_v1::Event::AppId { app_id } => {
match &state.inner {
WaylandStateInner::Cosmic(inner) => {
match inner.obj_id_to_uuid.get(&proxy.id()) {
Some(window_id) => {
send_event(&state.tokio_handle, &state.sender, JsWaylandApplicationEvent::WindowAppIdChanged {
window_id: window_id.clone(),
app_id,
});
}
None => {
tracing::warn!("Received event for cosmic wayland toplevel that doesn't exist in state");
}
}
}
_ => {}
}
}
zcosmic_toplevel_handle_v1::Event::Closed => {
match &mut state.inner {
WaylandStateInner::Cosmic(inner) => {

inner.toplevels.remove(&proxy.id());
match inner.obj_id_to_uuid.remove(&proxy.id()) {
Some(window_id) => {
inner.uuid_to_obj_id.remove(&window_id);

send_event(&state.tokio_handle, &state.sender, JsWaylandApplicationEvent::WindowClosed {
window_id: window_id.clone(),
});
}
None => {
tracing::warn!("Received event for cosmic wayland toplevel that doesn't exist in state");
}
}
}
_ => {}
}
}
_ => {}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ use wayland_client::protocol::wl_registry;
use wayland_client::protocol::wl_seat::WlSeat;
use crate::plugins::applications::{linux, ApplicationContext, DesktopEnvironment};

pub mod wlr;
mod wlr;
mod cosmic;

pub struct WaylandDesktopEnvironment {
activate_sender: calloop::channel::Sender<String>,
Expand Down Expand Up @@ -101,7 +102,7 @@ impl WaylandState {

pub enum WaylandStateInner {
Wlr(wlr::WlrWaylandState),
Cosmic,
Cosmic(cosmic::CosmicWaylandState),
None
}

Expand Down Expand Up @@ -183,7 +184,11 @@ fn activation_handler(event: Event<String>, _metadata: &mut (), state: &mut Wayl
tracing::error!("Unable to focus wayland window: {:?}", err);
};
}
WaylandStateInner::Cosmic => {}
WaylandStateInner::Cosmic(cosmic) => {
if let Err(err) = cosmic.focus_window(window_uuid, &state.seat_state) {
tracing::error!("Unable to focus wayland window: {:?}", err);
};
}
WaylandStateInner::None => {
tracing::error!("Calling focus window when there is no supported wayland protocols available");
}
Expand Down
20 changes: 4 additions & 16 deletions rust/plugin_runtime/src/plugins/applications/linux/wayland/wlr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ impl Dispatch<zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1, ()
window_id,
});
}
WaylandStateInner::Cosmic => {
todo!()
}
WaylandStateInner::None => {}
_ => {}
}
}
_ => {}
Expand Down Expand Up @@ -116,10 +113,7 @@ impl Dispatch<zwlr_foreign_toplevel_handle_v1::ZwlrForeignToplevelHandleV1, ()>
}
}
}
WaylandStateInner::Cosmic => {
todo!()
}
WaylandStateInner::None => {}
_ => {}
}
}
zwlr_foreign_toplevel_handle_v1::Event::AppId { app_id } => {
Expand All @@ -137,10 +131,7 @@ impl Dispatch<zwlr_foreign_toplevel_handle_v1::ZwlrForeignToplevelHandleV1, ()>
}
}
}
WaylandStateInner::Cosmic => {
todo!()
}
WaylandStateInner::None => {}
_ => {}
}
}
zwlr_foreign_toplevel_handle_v1::Event::Closed => {
Expand All @@ -161,10 +152,7 @@ impl Dispatch<zwlr_foreign_toplevel_handle_v1::ZwlrForeignToplevelHandleV1, ()>
}
}
}
WaylandStateInner::Cosmic => {
todo!()
}
WaylandStateInner::None => {}
_ => {}
}
}
_ => {}
Expand Down

0 comments on commit 4f2add8

Please sign in to comment.