From 963a450ff524b1ebfb06a9ab0425719e4365f1f7 Mon Sep 17 00:00:00 2001 From: Jake Stanger Date: Mon, 21 Apr 2025 20:11:47 +0100 Subject: [PATCH] fix(wayland): panicking on compositors without protocol support This allows Ironbar to run on a wider range of compositors, where support for the `wlr_foreign_toplevel` protocol used by focused/launcher, and the `wlr_data_control_device` protocol used by clipboard is missing --- src/clients/wayland/mod.rs | 30 ++++++++++++++++----- src/clients/wayland/wl_seat.rs | 8 ++++-- src/clients/wayland/wlr_data_control/mod.rs | 8 ++++-- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/clients/wayland/mod.rs b/src/clients/wayland/mod.rs index abeeac8..70b0638 100644 --- a/src/clients/wayland/mod.rs +++ b/src/clients/wayland/mod.rs @@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex}; use calloop_channel::Event::Msg; use cfg_if::cfg_if; -use color_eyre::Report; +use color_eyre::{Help, Report}; use smithay_client_toolkit::output::OutputState; use smithay_client_toolkit::reexports::calloop::EventLoop; use smithay_client_toolkit::reexports::calloop::channel as calloop_channel; @@ -204,7 +204,7 @@ pub struct Environment { // -- clipboard -- #[cfg(feature = "clipboard")] - data_control_device_manager_state: DataControlDeviceManagerState, + data_control_device_manager_state: Option, #[cfg(feature = "clipboard")] data_control_devices: Vec, @@ -263,12 +263,30 @@ impl Environment { let output_state = OutputState::new(&globals, &qh); let seat_state = SeatState::new(&globals, &qh); #[cfg(any(feature = "focused", feature = "launcher"))] - ToplevelManagerState::bind(&globals, &qh) - .expect("to bind to wlr_foreign_toplevel_manager global"); + if let Err(err) = ToplevelManagerState::bind(&globals, &qh) { + error!("{:?}", + Report::new(err) + .wrap_err("Failed to bind to wlr_foreign_toplevel_manager global") + .note("This is likely a due to the current compositor not supporting the required protocol") + .note("launcher and focused modules will not work") + ); + } #[cfg(feature = "clipboard")] - let data_control_device_manager_state = DataControlDeviceManagerState::bind(&globals, &qh) - .expect("to bind to wlr_data_control_device_manager global"); + let data_control_device_manager_state = match DataControlDeviceManagerState::bind( + &globals, &qh, + ) { + Ok(state) => Some(state), + Err(err) => { + error!("{:?}", + Report::new(err) + .wrap_err("Failed to bind to wlr_data_control_device global") + .note("This is likely a due to the current compositor not supporting the required protocol") + .note("clipboard module will not work") + ); + None + } + }; let mut env = Self { registry_state, diff --git a/src/clients/wayland/wl_seat.rs b/src/clients/wayland/wl_seat.rs index abd401d..1571638 100644 --- a/src/clients/wayland/wl_seat.rs +++ b/src/clients/wayland/wl_seat.rs @@ -1,6 +1,6 @@ use super::Environment; use smithay_client_toolkit::seat::{Capability, SeatHandler, SeatState}; -use tracing::debug; +use tracing::{debug, error}; use wayland_client::protocol::wl_seat::WlSeat; use wayland_client::{Connection, QueueHandle}; @@ -37,7 +37,11 @@ impl SeatHandler for Environment { { debug!("Adding new data control device"); // create the data device here for this seat - let data_control_device_manager = &self.data_control_device_manager_state; + let Some(data_control_device_manager) = &self.data_control_device_manager_state else { + error!("data_control_device_manager not available, cannot copy"); + return; + }; + let data_control_device = data_control_device_manager.get_data_device(qh, &seat); self.data_control_devices .push(super::DataControlDeviceEntry { diff --git a/src/clients/wayland/wlr_data_control/mod.rs b/src/clients/wayland/wlr_data_control/mod.rs index 877a9bc..8d239af 100644 --- a/src/clients/wayland/wlr_data_control/mod.rs +++ b/src/clients/wayland/wlr_data_control/mod.rs @@ -147,6 +147,11 @@ impl Environment { pub fn copy_to_clipboard(&mut self, item: ClipboardItem) { debug!("Copying item to clipboard: {item:?}"); + let Some(data_control_device_manager) = &self.data_control_device_manager_state else { + error!("data_control_device_manager not available, cannot copy"); + return; + }; + let seat = self.default_seat(); let Some(device) = self .data_control_devices @@ -156,8 +161,7 @@ impl Environment { return; }; - let source = self - .data_control_device_manager_state + let source = data_control_device_manager .create_copy_paste_source(&self.queue_handle, [&item.mime_type, INTERNAL_MIME_TYPE]); source.set_selection(&device.device);