brewery
notashelf /
ce24da6bc13d95ff7f15b25d019e4c98fbe0250c

beer

public

A terminal worth pouring time into

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/beer.git

Commit ce24da6bc13d

tarball

NotAShelf <raf@notashelf.dev> · 2026-06-26 07:22 UTC

unverified2 files changed+29-7
wayland: attach clipboard devices for seats surfaced via capabilities

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I127da48080483de626931a1038f3c38d6a6a6964
diff --git a/src/wayland/handlers.rs b/src/wayland/handlers.rsindex 3877a48..7761442 100644--- a/src/wayland/handlers.rs+++ b/src/wayland/handlers.rs@@ -92,14 +92,8 @@ impl SeatHandler for App {      fn new_seat(&mut self, _: &Connection, qh: &QueueHandle<Self>, seat: wl_seat::WlSeat) {         // Clipboard/primary devices are seat-scoped, not capability-scoped.-        let data_device = Some(self.data_device_manager.get_data_device(qh, &seat));-        let primary_device = self-            .primary_manager-            .as_ref()-            .map(|m| m.get_selection_device(qh, &seat));         let i = self.seat_index(&seat);-        self.seats[i].data_device = data_device;-        self.seats[i].primary_device = primary_device;+        self.ensure_clipboard_devices(qh, &seat, i);     }      fn new_capability(@@ -110,6 +104,9 @@ impl SeatHandler for App {         capability: Capability,     ) {         let i = self.seat_index(&seat);+        // A pre-existing seat may reach us via its capabilities without a+        // `new_seat` call, so make sure the clipboard devices are attached.+        self.ensure_clipboard_devices(qh, &seat, i);         if capability == Capability::Keyboard && self.seats[i].keyboard.is_none() {             // get_keyboard_with_repeat drives key repeat off a calloop timer and             // delivers each repeat through the callback.diff --git a/src/wayland/mod.rs b/src/wayland/mod.rsindex 473ff0d..5e6301b 100644--- a/src/wayland/mod.rs+++ b/src/wayland/mod.rs@@ -1130,6 +1130,28 @@ impl App {         self.seats.get(self.active_seat)     } +    /// Attach the seat-scoped clipboard and primary-selection devices to seat+    /// `i` if not already present. Idempotent, so it can run from either+    /// `new_seat` or `new_capability` - some compositors surface a pre-existing+    /// seat's capabilities without ever firing `new_seat`.+    fn ensure_clipboard_devices(+        &mut self,+        qh: &QueueHandle<Self>,+        seat: &wl_seat::WlSeat,+        i: usize,+    ) {+        if self.seats[i].data_device.is_none() {+            let dd = self.data_device_manager.get_data_device(qh, seat);+            self.seats[i].data_device = Some(dd);+        }+        if self.seats[i].primary_device.is_none()+            && let Some(m) = self.primary_manager.as_ref()+        {+            let pd = m.get_selection_device(qh, seat);+            self.seats[i].primary_device = Some(pd);+        }+    }+     /// The active seat's clipboard device, if any.     fn data_device(&self) -> Option<&DataDevice> {         self.active().and_then(|s| s.data_device.as_ref())@@ -1509,9 +1531,11 @@ impl App {     /// Paste the CLIPBOARD selection into the shell (Ctrl+Shift+V).     fn paste_clipboard(&mut self) {         let Some(offer) = self.data_device().and_then(|d| d.data().selection_offer()) else {+            tracing::debug!("paste: no clipboard selection offer");             return;         };         let Some(mime) = offer.with_mime_types(pick_mime) else {+            tracing::debug!("paste: no acceptable text mime type offered");             return;         };         if let Ok(pipe) = offer.receive(mime) {@@ -1547,6 +1571,7 @@ impl App {                 let mut tmp = [0u8; 4096];                 match f.read(&mut tmp) {                     Ok(0) => {+                        tracing::debug!("paste: read {} bytes from clipboard", data.len());                         app.paste_bytes(&data);                         PostAction::Remove                     }