Side by Side keeps the scrolling choice for an unchanged partner; drop queued partner scroll on pairing changes

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
vangel76andClaude Sonnet 5.5 committed 2026-11-07 16:27:10 +01:00
1 parent 875a62043a
commit 9fd9ce54b7
3 files changed
+29 -6

No files matched your search

+8 -4
View File
@@ -262,10 +262,14 @@ fn side_by_side(s: &mut Session, v: &Value) -> CmdResult {
if let Some(old) = s.windows.side_by_side.filter(|old| *old != id) {
s.ui_requests.push(json!({"windows": "sideBySide", "off": old}));
}
s.windows.side_by_side = Some(id);
s.windows.sync_scroll = true;
s.ui_requests.push(json!({"windows": "sideBySide", "with": id}));
Ok(json!({"value": true, "window": id, "syncScroll": true}))
// The partner it already has keeps the user's Synchronous Scrolling choice and is not asked
// again; a new pairing starts with scrolling on.
if s.windows.side_by_side != Some(id) {
s.windows.side_by_side = Some(id);
s.windows.sync_scroll = true;
s.ui_requests.push(json!({"windows": "sideBySide", "with": id}));
}
Ok(json!({"value": true, "window": id, "syncScroll": s.windows.sync_scroll}))
}
/// The browser keeps full screen to itself (its own F11); the web app can't ask for it.
+4
View File
@@ -10490,6 +10490,10 @@ fn window_commands_need_the_desktop_and_name_a_window() {
run(&mut s, "view.syncScroll", json!({}));
assert!(!s.windows.sync_scroll);
assert_eq!(s.ui_requests.pop(), Some(json!({"windows": "syncScroll", "with": 7, "value": false})));
// Asking again for the partner it already has keeps scrolling off and pairs nothing anew.
let r = run(&mut s, "view.sideBySide", json!({"window": 7, "value": true}));
assert_eq!((r["syncScroll"].as_bool(), s.windows.sync_scroll), (Some(false), false));
assert!(s.ui_requests.is_empty());
// Another partner replaces the first; the bare button turns it off.
run(&mut s, "view.sideBySide", json!({"window": 9}));
assert_eq!(std::mem::take(&mut s.ui_requests), [json!({"windows": "sideBySide", "off": 7}), json!({"windows": "sideBySide", "with": 9})]);
+17 -2
View File
@@ -74,7 +74,10 @@ pub(crate) fn poll(app: &mut WordApp, _ctx: &egui::Context) {
w.others = others;
w.side_by_side = partner;
w.sync_scroll = sync;
if sync && waiting.is_finite() {
if !sync {
// Scrolling still queued for a partner that is gone, replaced or no longer synced.
app.canvas.sync_in = 0.0;
} else if waiting.is_finite() {
app.canvas.sync_in += waiting.clamp(-MAX_SCROLL, MAX_SCROLL);
}
}
@@ -97,6 +100,7 @@ pub(crate) fn request(app: &mut WordApp, req: &Value) {
let id = |k: &str| req.get(k).and_then(Value::as_u64);
match what {
"sideBySide" => {
app.canvas.sync_in = 0.0;
if id("off").is_some() {
app.windows.arranged.clear();
}
@@ -113,6 +117,7 @@ pub(crate) fn request(app: &mut WordApp, req: &Value) {
}
}
"syncScroll" => {
app.canvas.sync_in = 0.0;
if let Some(on) = req.get("value").and_then(Value::as_bool) {
app.windows.arranged.sync = on;
}
@@ -275,7 +280,15 @@ mod tests {
assert_eq!(app.canvas.sync_out, 0.0);
assert_eq!(app.windows.arranged.waiting.get(&other), Some(&40.0));
assert!(!app.windows.arranged.waiting.contains_key(&shown));
// Nothing is passed on once Synchronous Scrolling is off.
// Nothing is passed on once Synchronous Scrolling is off, and scrolling still queued for
// this window is dropped.
app.canvas.sync_in = 9.0;
app.windows.arranged.sync = false;
poll(&mut app, &ctx);
assert_eq!(app.canvas.sync_in, 0.0);
app.canvas.sync_in = 9.0;
request(&mut app, &json!({"windows": "syncScroll", "value": true}));
assert_eq!(app.canvas.sync_in, 0.0);
app.windows.arranged.sync = false;
app.canvas.sync_out = 5.0;
forward_scroll(&mut app, &ctx);
@@ -287,7 +300,9 @@ mod tests {
assert_eq!(app.windows.arranged.waiting.get(&other), Some(&MAX_SCROLL));
// The partner closing ends the pairing.
app.windows.open.retain(|w| w.key == shown);
app.canvas.sync_in = 3.0;
poll(&mut app, &ctx);
assert_eq!(app.canvas.sync_in, 0.0);
assert_eq!((app.session.windows.side_by_side, app.session.windows.sync_scroll), (None, false));
}
}