diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-01 19:52:05 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-01 19:52:05 +0200 |
| commit | 819778f292ee4e1294603b98662e083e49e23463 (patch) | |
| tree | 8df31b678432d2a89cac8e0d50f271a75a3882b5 /rsnix/src/fs.rs | |
| parent | rsnix v0.4.0: GUI input foundation — PS/2 mouse + scheduler message queues (diff) | |
| download | rs-dos-819778f292ee4e1294603b98662e083e49e23463.tar.gz rs-dos-819778f292ee4e1294603b98662e083e49e23463.zip | |
rsnix v0.5.0: graphics layer + cursor compositor
The first visible GUI surface: real rect primitives, a single
shadow→display push path, and an on-screen mouse cursor that can
never race the text surface.
gop:
- fill_rect + push_rect(x,y,w,h): every raster op rasterises into the
RAM shadow, then push_rect copies the rect to the display (write-only,
still never read) and composites the cursor on top. blit_glyph and
scroll shifts now route through it.
- cursor overlay: 12x16 pointer (const-fn built from column lists) drawn
white with a black offset outline; position in one AtomicU64 (x:high
32, y:low 32) — unpack masks the low word (a bare 'as usize' cast is
a no-op on 64-bit). The cursor never enters the shadow, so erasing is
just a shadow push of the old rect.
- cursor_redraw after scroll shifts and once at spawn (the vt diff never
re-blits idle cells).
cursor task (task 2, spawned at boot when a mouse is present):
- owns the PS/2 ring; polls every 10 ms, moves the cursor (clamped),
tracks buttons, and forwards every event to a task's queue when
'mouse <id>' armed it (the window-manager input path).
- /dev/mouse is now a position device (x/y/buttons snapshot); 'mouse'
watches the cursor live (prints on change); 'cursor' prints one-shot
state; 'gfx' draws a status-bar demo; 'gfx check' is an in-kernel
pixel self-test (shadow readback, display readback, cursor overlay
purity) — PASS/FAIL per stage.
Tests (headless QEMU + monitor injection):
- make test-gfx (new): all four compositor checks PASS.
- make test-mouse (rewritten): cursor tracks mouse_move deltas, buttons
ride along, /dev/mouse snapshot, live watch, real-event queue routing.
- make test-msg: task numbering shifted (cursor is task 2; msgrecv is
task 3) — updated, still PASS.
- make test-disk regression re-passes. 0 build warnings.
Diffstat (limited to 'rsnix/src/fs.rs')
| -rw-r--r-- | rsnix/src/fs.rs | 37 |
1 files changed, 13 insertions, 24 deletions
diff --git a/rsnix/src/fs.rs b/rsnix/src/fs.rs index 0b7a772..5fc6d7a 100644 --- a/rsnix/src/fs.rs +++ b/rsnix/src/fs.rs | |||
| @@ -713,34 +713,23 @@ fn dev_text(dev: CharDevice, _pos: u64) -> String { | |||
| 713 | } | 713 | } |
| 714 | } | 714 | } |
| 715 | 715 | ||
| 716 | /// Render `/dev/mouse`: drain every pending PS/2 event (up to 32) into one | 716 | /// Render `/dev/mouse`: the current cursor state (position + buttons). |
| 717 | /// line each, so `cat /dev/mouse` shows the movement that happened since | 717 | /// The cursor task owns the PS/2 ring, so this is a position device — |
| 718 | /// the last read. Falls back to a clear message when there is no device or | 718 | /// the GUI-correct semantic — rather than an event drain. |
| 719 | /// nothing pending. | ||
| 720 | fn mouse_text() -> String { | 719 | fn mouse_text() -> String { |
| 721 | if !crate::ps2::mouse_present() { | 720 | if !crate::ps2::mouse_present() { |
| 722 | return String::from("mouse: no PS/2 mouse\n"); | 721 | return String::from("mouse: no PS/2 mouse\n"); |
| 723 | } | 722 | } |
| 724 | let mut s = String::new(); | 723 | let (x, y) = crate::gop::cursor_pos(); |
| 725 | for _ in 0..32 { | 724 | let b = crate::gop::cursor_buttons(); |
| 726 | let Some(ev) = crate::ps2::try_poll_mouse() else { | 725 | alloc::format!( |
| 727 | break; | 726 | "x={} y={} buttons={}{}{}\n", |
| 728 | }; | 727 | x, |
| 729 | let mut b = String::new(); | 728 | y, |
| 730 | b.push(if ev.left { 'L' } else { '-' }); | 729 | if b & 1 != 0 { 'L' } else { '-' }, |
| 731 | b.push(if ev.right { 'R' } else { '-' }); | 730 | if b & 2 != 0 { 'R' } else { '-' }, |
| 732 | b.push(if ev.middle { 'M' } else { '-' }); | 731 | if b & 4 != 0 { 'M' } else { '-' } |
| 733 | s.push_str(&alloc::format!( | 732 | ) |
| 734 | "dx={:+} dy={:+} buttons={}\n", | ||
| 735 | ev.dx, | ||
| 736 | ev.dy, | ||
| 737 | b | ||
| 738 | )); | ||
| 739 | } | ||
| 740 | if s.is_empty() { | ||
| 741 | s.push_str("mouse: no events\n"); | ||
| 742 | } | ||
| 743 | s | ||
| 744 | } | 733 | } |
| 745 | 734 | ||
| 746 | // --- self-test ------------------------------------------------------------ | 735 | // --- self-test ------------------------------------------------------------ |
