Bound every wait before the overlay is interactive
Running wl-pick twice left the second instance hung with no window at all and no way to end it but kill. The hang was in the capture phase, not the overlay. sway answers a capture request for a toplevel that another client is already capturing with silence: no frame, no failed, no stopped. captures_settled() waits for every tile to reach one of those three, so it waited forever, holding its buffers, having never created a layer surface. Any concurrent capture client will do this, not just a second wl-pick. So the phases before the overlay is interactive now have a deadline. pump_for polls the connection with one, and a tile that never arrives is drawn as a bare label, exactly as an outright capture failure already was. report_unsettled names those tiles on stderr, which is the diagnostic whose absence made this hard to find. The first instance had a second problem: sway hands the keyboard to the new overlay and sends the old one wl_keyboard.leave, but the dispatcher only handled Key, so the loser sat on screen holding a grab it no longer had, deaf to every key. That is the process that stays around. Losing the grab for good now ends the run, so a second wl-pick started from the same keybinding replaces the first rather than stranding it. For good, because sway also sends leave followed immediately by enter on the same surface -- microseconds apart -- as a focus refresh when the pointer crosses the overlay. Treating a bare leave as terminal made a lone instance quit itself after less than a second. Focus is tracked in the dispatcher and the main loop only gives up once it has failed to come back. pump had no callers left after that: every wait is now either budgeted or focus-aware.
This commit is contained in:
+10
-3
@@ -376,8 +376,8 @@ impl Dispatch<WlKeyboard, ()> for App {
|
||||
_: &Connection,
|
||||
qh: &QueueHandle<Self>,
|
||||
) {
|
||||
if let wl_keyboard::Event::Key { key, state, .. } = event {
|
||||
match state {
|
||||
match event {
|
||||
wl_keyboard::Event::Key { key, state, .. } => match state {
|
||||
WEnum::Value(wl_keyboard::KeyState::Pressed) => app.key(key, qh),
|
||||
WEnum::Value(wl_keyboard::KeyState::Released)
|
||||
if key == KEY_LEFTSHIFT || key == KEY_RIGHTSHIFT =>
|
||||
@@ -385,7 +385,14 @@ impl Dispatch<WlKeyboard, ()> for App {
|
||||
app.shift = false
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
// Focus is only tracked here. sway sends leave immediately
|
||||
// followed by enter on the same surface when the pointer crosses
|
||||
// it, so whether the grab is really gone is decided by the main
|
||||
// loop, once the event batch has been dispatched.
|
||||
wl_keyboard::Event::Enter { .. } => app.focused = true,
|
||||
wl_keyboard::Event::Leave { .. } => app.focused = false,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user