fix(collab): defer queued actions until the gesture's capture closes

A pointer press opens the gesture's local-edit capture and queues the panel
action it hit, but the same press's frame drained that action immediately.
The session's document actor refuses to act while a capture is open, so every
in-panel admission approval failed with LocalEditAlreadyActive and surfaced as
a bogus rejection on both peers. Wait for the matching release, and let a
release that leaves an action pending schedule the frame that drains it.
This commit is contained in:
Kayshen-X 2026-08-03 21:04:22 +08:00
parent 54bb01309a
commit 2f7283d41e
3 changed files with 32 additions and 2 deletions

View file

@ -400,7 +400,18 @@ impl DesktopApp {
.apply_release_with_viewport(self.viewport_width, self.viewport_height);
self.collab_runtime.finish_local_edit(&mut self.host);
self.sync_native_ime();
if consumed {
// The redraw pass defers collaboration actions queued mid-gesture
// until the capture closes, so a release that leaves one pending must
// schedule the frame that drains it — even when the release itself
// changed nothing on screen.
let drain_pending = self
.host
.editor_state()
.editor_ui
.collab
.pending_action
.is_some();
if consumed || drain_pending {
self.request_redraw(true);
}
}

View file

@ -47,7 +47,16 @@ impl DesktopApp {
} else {
true
};
if collaboration_transition_ready && self.collab_runtime.drain_ui_action(&mut self.host) {
// A press that queues an action also opens the gesture's local-edit
// capture, and the session's document actor refuses to activate a
// peer (or run any other document transition) while that capture is
// open. Draining here would turn every in-panel approval into a
// spurious failure, so wait for the matching release — which finishes
// the capture and requests another frame.
if collaboration_transition_ready
&& !self.collab_runtime.local_edit_in_flight()
&& self.collab_runtime.drain_ui_action(&mut self.host)
{
self.redraw_dirty = true;
}
if self.collab_runtime.take_save_as_fork_request() {

View file

@ -10,6 +10,16 @@ use super::types::CollabRuntimeError;
use super::DesktopCollabRuntime;
impl DesktopCollabRuntime {
/// Whether a GUI edit capture is open right now.
///
/// A pointer gesture is one transaction: press opens the capture, release
/// closes it. Actions queued by that same press (approving an admission,
/// for example) must not be drained mid-gesture, because the session's
/// document actor refuses to act while a capture is in flight.
pub(crate) const fn local_edit_in_flight(&self) -> bool {
self.transaction_active
}
/// Start one GUI-owned edit capture; `false` means busy or no live session is bound.
pub(crate) fn begin_local_edit(&mut self, host: &mut WidgetHostNative) -> bool {
if self.transaction_active {