Initial implementation for wlroots client (#345)

Co-authored-by: Alex Sinitsin <meowcoder@users.noreply.github.com>
pull/346/head
Alex Sinitsin 9 months ago committed by GitHub
parent 47d6932da0
commit 383e2a4a57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -25,6 +25,8 @@ serde_json = "1.0"
serde_with = { version = "3.3", features = ["chrono"] }
serde_yaml = "0.9"
swayipc = { version = "3.0.1", optional = true }
wayland-client = { version = "0.30", optional = true }
wayland-protocols-wlr = { version = "0.1", features = ["client"], optional = true }
x11rb = { version = "0.12.0", optional = true }
zbus = { version = "1.9.2", optional = true }
hyprland = { version = "0.3.4", optional = true }
@ -35,3 +37,4 @@ sway = ["swayipc"]
x11 = ["x11rb"]
hypr = ["hyprland"]
kde = ["zbus"]
wlroots = ["wayland-client", "wayland-protocols-wlr"]

@ -76,6 +76,13 @@ pub fn build_client() -> WMClient {
WMClient::new("X11", Box::new(x11_client::X11Client::new()))
}
#[cfg(feature = "wlroots")]
mod wlroots_client;
#[cfg(feature = "wlroots")]
pub fn build_client() -> WMClient {
WMClient::new("wlroots", Box::new(wlroots_client::WlRootsClient::new()))
}
#[cfg(not(any(
feature = "gnome",
feature = "sway",
@ -89,7 +96,8 @@ mod null_client;
feature = "sway",
feature = "x11",
feature = "hypr",
feature = "kde"
feature = "kde",
feature = "wlroots"
)))]
pub fn build_client() -> WMClient {
WMClient::new("none", Box::new(null_client::NullClient))

@ -0,0 +1,138 @@
use std::collections::HashMap;
use anyhow::{Context, Result};
use wayland_client::{
backend::ObjectId,
event_created_child,
globals::{registry_queue_init, GlobalListContents},
protocol::wl_registry,
Connection, Dispatch, EventQueue, Proxy, QueueHandle,
};
use wayland_protocols_wlr::foreign_toplevel::v1::client::{
zwlr_foreign_toplevel_handle_v1::{Event as HandleEvent, State as HandleState, ZwlrForeignToplevelHandleV1},
zwlr_foreign_toplevel_manager_v1::{Event as ManagerEvent, ZwlrForeignToplevelManagerV1},
};
use crate::client::Client;
#[derive(Default, Debug)]
struct State {
active_window: Option<ObjectId>,
windows: HashMap<ObjectId, String>,
}
#[derive(Default)]
pub struct WlRootsClient {
queue: Option<EventQueue<State>>,
state: State,
}
impl WlRootsClient {
pub fn new() -> Self {
Default::default()
}
fn connect(&mut self) -> Result<()> {
let connection = Connection::connect_to_env()?;
let (globals, mut queue) = registry_queue_init::<State>(&connection)?;
globals
.bind::<ZwlrForeignToplevelManagerV1, _, _>(&queue.handle(), 1..=3, ())
.context("wlr_foreign_toplevel_management_unstable_v1 protocol is not supported")?;
queue.roundtrip(&mut self.state)?;
self.queue = Some(queue);
Ok(())
}
}
impl Client for WlRootsClient {
fn supported(&mut self) -> bool {
match self.connect() {
Ok(_) => true,
Err(err) => {
eprintln!("{err}");
false
}
}
}
fn current_application(&mut self) -> Option<String> {
let queue = self.queue.as_mut()?;
if let Err(_) = queue.roundtrip(&mut self.state) {
// try to reconnect
if let Err(err) = self.connect() {
log::error!("{err}");
return None;
}
log::debug!("Reconnected to wayland");
}
let id = self.state.active_window.as_ref()?;
self.state.windows.get(id).cloned()
}
}
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for State {
fn event(
_state: &mut Self,
_registry: &wl_registry::WlRegistry,
event: wl_registry::Event,
_: &GlobalListContents,
_connection: &Connection,
_: &QueueHandle<State>,
) {
log::trace!("{event:?}");
}
}
impl Dispatch<ZwlrForeignToplevelManagerV1, ()> for State {
fn event(
state: &mut Self,
_: &ZwlrForeignToplevelManagerV1,
event: ManagerEvent,
_: &(),
_: &Connection,
_: &QueueHandle<State>,
) {
if let ManagerEvent::Toplevel { toplevel } = event {
state.windows.insert(toplevel.id(), "<unknown>".into());
}
}
event_created_child!(State, ZwlrForeignToplevelManagerV1, [
_ => (ZwlrForeignToplevelHandleV1, ())
]);
}
impl Dispatch<ZwlrForeignToplevelHandleV1, ()> for State {
fn event(
state: &mut Self,
handle: &ZwlrForeignToplevelHandleV1,
event: HandleEvent,
_: &(),
_: &Connection,
_: &QueueHandle<Self>,
) {
match event {
HandleEvent::AppId { app_id } => {
state.windows.insert(handle.id(), app_id);
}
HandleEvent::Closed => {
state.windows.remove(&handle.id());
}
HandleEvent::State { state: handle_state } => {
let activated = HandleState::Activated as u8;
if handle_state.contains(&activated) {
state.active_window = Some(handle.id());
}
}
_ => {}
}
}
}
Loading…
Cancel
Save