summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-17 19:08:47 +0200
committersalmonik <salmonik@tuta.io>2026-08-17 19:08:47 +0200
commitf4fab5a2b06c37df08d2d315bcb44d15af1786a4 (patch)
tree725fbdefb64fdd987ead8ea2240269c1ba29bcfc
parentwm: title-bar drag-to-move; stop delivering title-bar gestures to apps (diff)
downloadrs-dos-f4fab5a2b06c37df08d2d315bcb44d15af1786a4.tar.gz
rs-dos-f4fab5a2b06c37df08d2d315bcb44d15af1786a4.zip
wm: keep windows in place when the console scrolls beneath them
The console's batched scroll (gop::shift_up_n) shifts the whole shared shadow, which dragged any composited window pixels up with it. Add a scroll hook so the window manager re-composites every visible window after a console scroll, restoring them at their fixed positions.
-rw-r--r--rsnix/src/gop.rs19
-rw-r--r--rsnix/src/vt.rs9
-rw-r--r--rsnix/src/wm.rs16
3 files changed, 37 insertions, 7 deletions
diff --git a/rsnix/src/gop.rs b/rsnix/src/gop.rs
index deff226..cddad22 100644
--- a/rsnix/src/gop.rs
+++ b/rsnix/src/gop.rs
@@ -104,6 +104,25 @@ pub fn qr_locked() -> bool {
104 QR_LOCKED.load(Ordering::Relaxed) 104 QR_LOCKED.load(Ordering::Relaxed)
105} 105}
106 106
107/// Hook invoked after the console scrolls, so the window manager can
108/// re-composite GUI windows (which sit above the console layer in the
109/// shadow and must not scroll with it).
110fn scroll_hook_noop() {}
111
112static mut SCROLL_HOOK: fn() = scroll_hook_noop;
113
114pub fn set_scroll_hook(f: fn()) {
115 unsafe {
116 SCROLL_HOOK = f;
117 }
118}
119
120pub(crate) fn call_scroll_hook() {
121 unsafe {
122 SCROLL_HOOK();
123 }
124}
125
107#[inline] 126#[inline]
108fn stall_display() { 127fn stall_display() {
109 let n = DISPLAY_STALL.load(Ordering::Relaxed); 128 let n = DISPLAY_STALL.load(Ordering::Relaxed);
diff --git a/rsnix/src/vt.rs b/rsnix/src/vt.rs
index c5fc5fd..4ef568d 100644
--- a/rsnix/src/vt.rs
+++ b/rsnix/src/vt.rs
@@ -458,13 +458,7 @@ fn put_byte(b: u8) {
458} 458}
459 459
460fn param(i: usize, default: usize) -> usize { 460fn param(i: usize, default: usize) -> usize {
461 unsafe { 461 unsafe { if i < NPARAMS { PARAMS[i] } else { default } }
462 if i < NPARAMS {
463 PARAMS[i]
464 } else {
465 default
466 }
467 }
468} 462}
469 463
470/// Place a printable glyph at the cursor and advance (wrapping/scrolling). 464/// Place a printable glyph at the cursor and advance (wrapping/scrolling).
@@ -694,6 +688,7 @@ pub fn sync_scroll() {
694 PENDING_SCROLLS = 0; 688 PENDING_SCROLLS = 0;
695 LAST_SYNC_TICK = crate::interrupts::TICKS.load(core::sync::atomic::Ordering::Relaxed); 689 LAST_SYNC_TICK = crate::interrupts::TICKS.load(core::sync::atomic::Ordering::Relaxed);
696 flush(); 690 flush();
691 gop::call_scroll_hook();
697 } 692 }
698} 693}
699 694
diff --git a/rsnix/src/wm.rs b/rsnix/src/wm.rs
index be74f9a..1326696 100644
--- a/rsnix/src/wm.rs
+++ b/rsnix/src/wm.rs
@@ -90,6 +90,8 @@ pub fn init() {
90 CASCADE_Y = 0; 90 CASCADE_Y = 0;
91 } 91 }
92 FOCUSED.store(CONSOLE, Ordering::Relaxed); 92 FOCUSED.store(CONSOLE, Ordering::Relaxed);
93 // When the console scrolls, re-composite windows so they stay put.
94 gop::set_scroll_hook(redraw_windows);
93} 95}
94 96
95/// The focused window, or `None` if the console has focus. 97/// The focused window, or `None` if the console has focus.
@@ -661,6 +663,20 @@ pub fn spawn_input_pump() -> Option<usize> {
661 crate::sched::spawn(pump_main, "wm-input") 663 crate::sched::spawn(pump_main, "wm-input")
662} 664}
663 665
666/// Re-composite every visible window. Called after the console scrolls so
667/// windows stay in place while the text layer beneath them shifts.
668pub fn redraw_windows() {
669 unsafe {
670 for i in 0..ZLEN {
671 let id = ZORDER[i];
672 let w = WINDOWS[id];
673 if w.used && w.state == WinState::Visible {
674 composite_rect(w.x, w.y, w.w, w.h + TITLE_BAR_H);
675 }
676 }
677 }
678}
679
664fn pump_main() { 680fn pump_main() {
665 loop { 681 loop {
666 if focused().is_some() { 682 if focused().is_some() {