shell: intent wins the settle window, and a swap is a request for a keyboard
Two gaps in the owner-change handling, both found on device. The push at adopt time can lose a race. osk-switch sleeps 0.3s before its deliberate SetVisible(true), and stevia self-shows once it has finished coming up - both land after the shell has spoken. Measured: adopt+hide 07:37:51, Visible=true 07:37:52, leaving oskOpen=false with a keyboard on the screen. Re-assert when the settle window closes so the last speaker is not the winner. And the oskSwap gesture never recorded that a swap means the user wants a keyboard, so osk-switch's re-show and the shell's stale false were racing with nothing to arbitrate them. Declare the intent first.
This commit is contained in:
parent
d7a04f27d5
commit
3aea8398a9
2 changed files with 29 additions and 4 deletions
|
|
@ -140,7 +140,23 @@ Scope {
|
||||||
Timer {
|
Timer {
|
||||||
id: ownerSettleTimer
|
id: ownerSettleTimer
|
||||||
interval: root.ownerSettleMs
|
interval: root.ownerSettleMs
|
||||||
onTriggered: root.ownerSettling = false
|
onTriggered: {
|
||||||
|
root.ownerSettling = false;
|
||||||
|
// Push once more on the way out. The first push (at adopt time)
|
||||||
|
// can lose a race: osk-switch sleeps 0.3s and then deliberately
|
||||||
|
// SetVisible(true), and a keyboard that self-shows on startup
|
||||||
|
// does so after it has finished coming up — both land *after* we
|
||||||
|
// spoke. Measured 2026-08-05: adopt+hide at 07:37:51, stevia
|
||||||
|
// Visible=true at 07:37:52, leaving oskOpen=false while a
|
||||||
|
// keyboard sat on the screen. Whoever spoke last during the
|
||||||
|
// settle window does not get to be the winner; intent does.
|
||||||
|
root.assertIntent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertIntent(): void {
|
||||||
|
if (GlobalStates.oskOpen) root.showOsk();
|
||||||
|
else root.hideOsk();
|
||||||
}
|
}
|
||||||
|
|
||||||
function adoptOwner(owner: string): void {
|
function adoptOwner(owner: string): void {
|
||||||
|
|
@ -157,9 +173,9 @@ Scope {
|
||||||
+ (previous === "" ? "" : " (was " + previous + ")")
|
+ (previous === "" ? "" : " (was " + previous + ")")
|
||||||
+ "; re-asserting oskOpen=" + GlobalStates.oskOpen);
|
+ "; re-asserting oskOpen=" + GlobalStates.oskOpen);
|
||||||
// Push our intent, not theirs. A fresh keyboard claiming Visible=true
|
// Push our intent, not theirs. A fresh keyboard claiming Visible=true
|
||||||
// when nobody asked for one gets closed here.
|
// when nobody asked for one gets closed here — and again when the
|
||||||
if (GlobalStates.oskOpen) root.showOsk();
|
// settle window closes, in case it spoke after we did.
|
||||||
else root.hideOsk();
|
root.assertIntent();
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,15 @@ Singleton {
|
||||||
// feel the same as crossing the line.
|
// feel the same as crossing the line.
|
||||||
"oskSwap": () => {
|
"oskSwap": () => {
|
||||||
Haptics.confirm();
|
Haptics.confirm();
|
||||||
|
// Declare the intent before the swap, not after it. osk-switch
|
||||||
|
// deliberately re-shows the keyboard on the new daemon ("so the
|
||||||
|
// swap is visible immediately"), and OnScreenKeyboard re-asserts
|
||||||
|
// oskOpen at whoever takes the sm.puri.OSK0 name. If the shell
|
||||||
|
// did not record that a swap means "keyboard up", those two would
|
||||||
|
// fight: osk-switch shows it, the shell pushes its stale false,
|
||||||
|
// and which one the user gets is a race. A swap is a request for
|
||||||
|
// a keyboard.
|
||||||
|
GlobalStates.oskOpen = true;
|
||||||
Quickshell.execDetached(["osk-switch"]);
|
Quickshell.execDetached(["osk-switch"]);
|
||||||
},
|
},
|
||||||
"screenshot": () => {
|
"screenshot": () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue