git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitb733a82127b5bf9b8ffd5b81f17aa52238fe01ae
parentdbe7bfc690
authorLucas Galante <[email protected]>
date2026-05-24 23:18
Fix IPC view/toggle/set-tag commands to trigger render and status updates, fix clearctl socket leak

 src/ipc.rs        | 10 ++++++++++
 src/ipc_server.rs |  4 +++-
 src/wayland.rs    | 15 ++++++++-------
 3 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/ipc.rs b/src/ipc.rs
index c65cfad..f332f6a 100644
--- a/src/ipc.rs
+++ b/src/ipc.rs
@@ -91,7 +91,9 @@ pub fn handle_ipc_command(cmd: &str, state: &mut WindowManager) {
                             .collect();
                         seat.focused_window_id = visible_ids.last().copied();
                     }
+                    state.needs_render = true;
                     state.needs_focus = true;
+                    state.needs_status_update = true;
                 }
             }
         }
@@ -124,6 +126,8 @@ pub fn handle_ipc_command(cmd: &str, state: &mut WindowManager) {
                         }
                         state.needs_focus = true;
                     }
+                    state.needs_render = true;
+                    state.needs_status_update = true;
                 }
             }
         }
@@ -400,6 +404,8 @@ fn handle_set_mode_command(rest: &str, state: &mut WindowManager) {
             let win_title = window.title.as_deref().unwrap_or("Window");
             crate::config::show_notification("clearwm", &format!("Tiling mode set to {} for: {}", mode.as_str(), win_title));
         }
+        state.needs_render = true;
+        state.needs_status_update = true;
     }
 }
 
@@ -475,6 +481,8 @@ fn handle_tag_layout_command(rest: &str, state: &mut WindowManager) {
             if state.notifications_enable {
                 crate::config::show_notification("clearwm", &format!("Tag {} layout set to {}", tag, mode.as_str()));
             }
+            state.needs_render = true;
+            state.needs_status_update = true;
         }
     }
 }
@@ -512,6 +520,8 @@ fn handle_set_tag_command(rest: &str, state: &mut WindowManager) {
                     }
                     state.needs_focus = true;
                 }
+                state.needs_render = true;
+                state.needs_status_update = true;
             }
         }
     }
diff --git a/src/ipc_server.rs b/src/ipc_server.rs
index 3969dc4..c88b819 100644
--- a/src/ipc_server.rs
+++ b/src/ipc_server.rs
@@ -1,4 +1,4 @@
-use std::io::Read;
+use std::io::{Read, Write};
 use std::os::unix::net::{UnixListener, UnixStream};
 use std::sync::mpsc;
 
@@ -78,6 +78,8 @@ fn ipc_server_main(tx: mpsc::Sender<String>, pipe_write: libc::c_int) {
                         }
                     }
                     if sent {
+                        let _ = stream.write_all(b"ok\n");
+                        dead.push(i);
                         unsafe {
                             libc::write(pipe_write, &1u8 as *const u8 as *const libc::c_void, 1);
                         }
diff --git a/src/wayland.rs b/src/wayland.rs
index 2b2eb7e..5422dd2 100644
--- a/src/wayland.rs
+++ b/src/wayland.rs
@@ -2596,6 +2596,7 @@ impl Dispatch<RiverLibinputConfigV1, ()> for AppState {
                     tap_finger_count: -1, // not yet received
                     tap_info_received: false,
                 });
+                state.wm.tap_config_applied = false;
             }
             river_libinput_config_v1::Event::Finished => {}
             _ => {}
@@ -2608,22 +2609,20 @@ impl Dispatch<RiverLibinputConfigV1, ()> for AppState {
 impl Dispatch<RiverLibinputDeviceV1, ()> for AppState {
     fn event(
         state: &mut Self,
-        _proxy: &RiverLibinputDeviceV1,
+        proxy: &RiverLibinputDeviceV1,
         event: river_libinput_device_v1::Event,
         _data: &(),
         _conn: &Connection,
-        _qhandle: &QueueHandle<Self>,
+        qhandle: &QueueHandle<Self>,
     ) {
         match event {
             river_libinput_device_v1::Event::TapSupport { finger_count } => {
-                if let Some(dev) = state.libinput_devices.last_mut() {
+                if let Some(dev) = state.libinput_devices.iter_mut().find(|d| d.device.id().protocol_id() == proxy.id().protocol_id()) {
                     dev.tap_finger_count = finger_count;
                     eprintln!("[libinput] tap support: {} fingers", finger_count);
                 }
-                // Don't apply tap config here — devices arrive one at a time.
-                // If we apply after the first device (which may not support tap),
-                // tap_config_applied gets set too early and we miss the touchpad.
-                // Instead, apply in RenderStart after all devices have been discovered.
+                // Apply tap config directly when info is received, in case we are waking up
+                crate::wayland::apply_tap_config(state, qhandle);
             }
             river_libinput_device_v1::Event::TapDefault { state: tap_state } => {
                 let _ = tap_state;
@@ -2635,6 +2634,8 @@ impl Dispatch<RiverLibinputDeviceV1, ()> for AppState {
             }
             river_libinput_device_v1::Event::Removed => {
                 eprintln!("[libinput] device removed");
+                state.libinput_devices.retain(|d| d.device.id().protocol_id() != proxy.id().protocol_id());
+                state.wm.tap_config_applied = false;
             }
             _ => {}
         }