cloud storage client
git clone https://git.lucas.co/cce-cloud.git
feat: new popup connection preempts the currently open popup
The daemon serves one popup per accepted connection, so a second popup
request used to queue invisibly until the first popup closed. Within
one bar process CloudPopupTracker SIGTERMs its own client before
spawning the next popup, but the bar modules are separate processes
that can't see each other's popups — opening the window picker while a
tray menu was up just left both stuck.
Poll the listener (nonblocking) each frame while a popup is open; a new
connection ends the current service iteration and is served next,
giving global single-popup semantics regardless of which process owns
which popup.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/main.rs | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/src/main.rs b/src/main.rs
index 2f43fd1..53448ba 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2666,10 +2666,17 @@ fn run_daemon(socket_path: &str) {
let loop_handle = event_loop.handle();
WaylandSource::new(conn, event_queue).insert(loop_handle.clone()).unwrap();
- for stream in listener.incoming() {
- let mut stream = match stream {
- Ok(s) => s,
- Err(_) => continue,
+ let mut pending: Option<std::os::unix::net::UnixStream> = None;
+ loop {
+ let mut stream = match pending.take() {
+ Some(s) => s,
+ None => {
+ let _ = listener.set_nonblocking(false);
+ match listener.accept() {
+ Ok((s, _)) => s,
+ Err(_) => continue,
+ }
+ }
};
let (stdin_sender, stdin_channel) = calloop::channel::channel::<()>();
@@ -2928,6 +2935,9 @@ fn run_daemon(socket_path: &str) {
// so fire one signal to make the channel handler ingest them.
let _ = stdin_sender.send(());
+ // Watch for preempting connections while the popup is open.
+ let _ = listener.set_nonblocking(true);
+
let mut last_tick = std::time::Instant::now();
while !app.exit {
if app.fade_out {
@@ -2953,6 +2963,14 @@ fn run_daemon(socket_path: &str) {
break;
}
+ // A new client preempts the current popup: global single-popup
+ // semantics, even when the two popups are owned by different
+ // bar module processes that can't see each other's state.
+ if let Ok((s, _)) = listener.accept() {
+ pending = Some(s);
+ break;
+ }
+
let now = std::time::Instant::now();
let mut dt = now.duration_since(last_tick).as_secs_f32();
last_tick = now;