diff options
Diffstat (limited to '')
| -rw-r--r-- | rsnix/src/vt.rs | 96 |
1 files changed, 81 insertions, 15 deletions
diff --git a/rsnix/src/vt.rs b/rsnix/src/vt.rs index 12e2cdc..0d7cf9b 100644 --- a/rsnix/src/vt.rs +++ b/rsnix/src/vt.rs | |||
| @@ -82,6 +82,7 @@ pub struct Terminal { | |||
| 82 | last_sync_tick: u64, | 82 | last_sync_tick: u64, |
| 83 | dirty_all: bool, | 83 | dirty_all: bool, |
| 84 | buffer: Vec<u32>, | 84 | buffer: Vec<u32>, |
| 85 | ext_buf: Option<*mut u32>, | ||
| 85 | w: usize, | 86 | w: usize, |
| 86 | h: usize, | 87 | h: usize, |
| 87 | window_id: Option<usize>, | 88 | window_id: Option<usize>, |
| @@ -131,20 +132,63 @@ impl Terminal { | |||
| 131 | last_sync_tick: 0, | 132 | last_sync_tick: 0, |
| 132 | dirty_all: true, | 133 | dirty_all: true, |
| 133 | buffer: vec![0; w * h], | 134 | buffer: vec![0; w * h], |
| 135 | ext_buf: None, | ||
| 134 | w, | 136 | w, |
| 135 | h, | 137 | h, |
| 136 | window_id: None, | 138 | window_id: None, |
| 137 | } | 139 | } |
| 138 | } | 140 | } |
| 139 | 141 | ||
| 142 | /// Build a terminal that renders into an externally-owned pixel buffer | ||
| 143 | /// (e.g. one allocated by the window manager). The caller must free | ||
| 144 | /// the buffer when the window is destroyed. | ||
| 145 | pub fn from_buffer(buf: *mut u32, w: usize, h: usize) -> Terminal { | ||
| 146 | let cols = w / 8; | ||
| 147 | let rows = h / 16; | ||
| 148 | Terminal { | ||
| 149 | cells: vec![BLANK; rows * cols], | ||
| 150 | rendered: vec![BLANK; rows * cols], | ||
| 151 | rows, | ||
| 152 | cols, | ||
| 153 | cursor_r: 1, | ||
| 154 | cursor_c: 0, | ||
| 155 | last_cursor: (1, 0), | ||
| 156 | cursor_visible: true, | ||
| 157 | sgr_fg: 7, | ||
| 158 | sgr_bg: 0, | ||
| 159 | parser: Parser::Ground, | ||
| 160 | private: false, | ||
| 161 | params: [0; 4], | ||
| 162 | nparams: 0, | ||
| 163 | cur: 0, | ||
| 164 | pending_scrolls: 0, | ||
| 165 | last_sync_tick: 0, | ||
| 166 | dirty_all: true, | ||
| 167 | buffer: Vec::new(), | ||
| 168 | ext_buf: Some(buf), | ||
| 169 | w, | ||
| 170 | h, | ||
| 171 | window_id: None, | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | /// Raw pointer to the pixel buffer (owned or external). | ||
| 176 | fn buf_ptr(&mut self) -> *mut u32 { | ||
| 177 | if let Some(p) = self.ext_buf { | ||
| 178 | p | ||
| 179 | } else { | ||
| 180 | self.buffer.as_mut_ptr() | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 140 | /// Attach this terminal to a WM window (so `flush` composites it). | 184 | /// Attach this terminal to a WM window (so `flush` composites it). |
| 141 | pub fn set_window(&mut self, id: usize) { | 185 | pub fn set_window(&mut self, id: usize) { |
| 142 | self.window_id = Some(id); | 186 | self.window_id = Some(id); |
| 143 | } | 187 | } |
| 144 | 188 | ||
| 145 | /// Buffer pointer and pixel dimensions (for the WM to composite). | 189 | /// Buffer pointer and pixel dimensions (for the WM to composite). |
| 146 | pub fn window_params(&self) -> (*const u32, usize, usize) { | 190 | pub fn window_params(&mut self) -> (*const u32, usize, usize) { |
| 147 | (self.buffer.as_ptr(), self.w, self.h) | 191 | (self.buf_ptr() as *const u32, self.w, self.h) |
| 148 | } | 192 | } |
| 149 | 193 | ||
| 150 | pub fn ready(&self) -> bool { | 194 | pub fn ready(&self) -> bool { |
| @@ -191,7 +235,7 @@ impl Terminal { | |||
| 191 | } | 235 | } |
| 192 | let rows = self.rows; | 236 | let rows = self.rows; |
| 193 | let cols = self.cols; | 237 | let cols = self.cols; |
| 194 | gop::buffer_shift_up(self.buffer.as_mut_ptr(), self.w, self.h, n * 16); | 238 | gop::buffer_shift_up(self.buf_ptr(), self.w, self.h, n * 16); |
| 195 | // Mirror the pushed content in RENDERED (it describes the buffer). | 239 | // Mirror the pushed content in RENDERED (it describes the buffer). |
| 196 | let total = rows * cols; | 240 | let total = rows * cols; |
| 197 | self.rendered.copy_within(n * cols..total, 0); | 241 | self.rendered.copy_within(n * cols..total, 0); |
| @@ -206,8 +250,8 @@ impl Terminal { | |||
| 206 | 250 | ||
| 207 | /// Re-blit a region of this terminal's buffer into the shadow (used by | 251 | /// Re-blit a region of this terminal's buffer into the shadow (used by |
| 208 | /// the window manager to restore the console layer beneath a window). | 252 | /// the window manager to restore the console layer beneath a window). |
| 209 | pub fn repaint_region(&self, x: usize, y: usize, w: usize, h: usize) { | 253 | pub fn repaint_region(&mut self, x: usize, y: usize, w: usize, h: usize) { |
| 210 | let src = unsafe { self.buffer.as_ptr().add(y * self.w + x) }; | 254 | let src = unsafe { self.buf_ptr().add(y * self.w + x) }; |
| 211 | gop::shadow_blit(x, y, w, h, src, self.w); | 255 | gop::shadow_blit(x, y, w, h, src, self.w); |
| 212 | } | 256 | } |
| 213 | 257 | ||
| @@ -537,7 +581,7 @@ impl Terminal { | |||
| 537 | let fg = PALETTE[c.fg as usize]; | 581 | let fg = PALETTE[c.fg as usize]; |
| 538 | let bg = PALETTE[c.bg as usize]; | 582 | let bg = PALETTE[c.bg as usize]; |
| 539 | gop::buffer_glyph_px( | 583 | gop::buffer_glyph_px( |
| 540 | self.buffer.as_mut_ptr(), | 584 | self.buf_ptr(), |
| 541 | self.w, | 585 | self.w, |
| 542 | self.h, | 586 | self.h, |
| 543 | col * 8, | 587 | col * 8, |
| @@ -560,7 +604,7 @@ impl Terminal { | |||
| 560 | let fg = PALETTE[c.fg as usize]; | 604 | let fg = PALETTE[c.fg as usize]; |
| 561 | let bg = PALETTE[c.bg as usize]; | 605 | let bg = PALETTE[c.bg as usize]; |
| 562 | gop::buffer_glyph_px( | 606 | gop::buffer_glyph_px( |
| 563 | self.buffer.as_mut_ptr(), | 607 | self.buf_ptr(), |
| 564 | self.w, | 608 | self.w, |
| 565 | self.h, | 609 | self.h, |
| 566 | lc * 8, | 610 | lc * 8, |
| @@ -578,7 +622,7 @@ impl Terminal { | |||
| 578 | let fg = PALETTE[c.bg as usize]; | 622 | let fg = PALETTE[c.bg as usize]; |
| 579 | let bg = PALETTE[c.fg as usize]; | 623 | let bg = PALETTE[c.fg as usize]; |
| 580 | gop::buffer_glyph_px( | 624 | gop::buffer_glyph_px( |
| 581 | self.buffer.as_mut_ptr(), | 625 | self.buf_ptr(), |
| 582 | self.w, | 626 | self.w, |
| 583 | self.h, | 627 | self.h, |
| 584 | cc * 8, | 628 | cc * 8, |
| @@ -602,7 +646,7 @@ impl Terminal { | |||
| 602 | Some(id) => crate::wm::flush(id), | 646 | Some(id) => crate::wm::flush(id), |
| 603 | None => { | 647 | None => { |
| 604 | if let Some((x, y, w, h)) = dirty { | 648 | if let Some((x, y, w, h)) = dirty { |
| 605 | let src = unsafe { self.buffer.as_ptr().add(y * self.w + x) }; | 649 | let src = unsafe { self.buf_ptr().add(y * self.w + x) }; |
| 606 | gop::shadow_blit(x, y, w, h, src, self.w); | 650 | gop::shadow_blit(x, y, w, h, src, self.w); |
| 607 | gop::push_rect(x, y, w, h); | 651 | gop::push_rect(x, y, w, h); |
| 608 | } | 652 | } |
| @@ -616,6 +660,20 @@ impl Terminal { | |||
| 616 | // --------------------------------------------------------------------------- | 660 | // --------------------------------------------------------------------------- |
| 617 | 661 | ||
| 618 | static mut HOME: Option<Terminal> = None; | 662 | static mut HOME: Option<Terminal> = None; |
| 663 | /// When set, all vt output goes here instead of HOME. Used by windowed | ||
| 664 | /// shells so that gop_print!/put_char/write_str write to the active | ||
| 665 | /// terminal's pixel buffer. | ||
| 666 | static mut ACTIVE: *mut Terminal = core::ptr::null_mut(); | ||
| 667 | |||
| 668 | fn active() -> &'static mut Terminal { | ||
| 669 | unsafe { | ||
| 670 | if !ACTIVE.is_null() { | ||
| 671 | &mut *ACTIVE | ||
| 672 | } else { | ||
| 673 | home() | ||
| 674 | } | ||
| 675 | } | ||
| 676 | } | ||
| 619 | 677 | ||
| 620 | fn home() -> &'static mut Terminal { | 678 | fn home() -> &'static mut Terminal { |
| 621 | unsafe { | 679 | unsafe { |
| @@ -624,6 +682,14 @@ fn home() -> &'static mut Terminal { | |||
| 624 | } | 682 | } |
| 625 | } | 683 | } |
| 626 | 684 | ||
| 685 | /// Set the active terminal for output (pass null to restore the home | ||
| 686 | /// terminal). | ||
| 687 | pub fn set_active(term: *mut Terminal) { | ||
| 688 | unsafe { | ||
| 689 | ACTIVE = term; | ||
| 690 | } | ||
| 691 | } | ||
| 692 | |||
| 627 | /// Initialise the home terminal over a full-screen pixel buffer. Call once | 693 | /// Initialise the home terminal over a full-screen pixel buffer. Call once |
| 628 | /// after `gop::init()`. | 694 | /// after `gop::init()`. |
| 629 | pub fn init() { | 695 | pub fn init() { |
| @@ -675,27 +741,27 @@ pub fn set_cursor_visible(v: bool) { | |||
| 675 | } | 741 | } |
| 676 | 742 | ||
| 677 | pub fn sync_scroll() { | 743 | pub fn sync_scroll() { |
| 678 | home().sync_scroll(); | 744 | active().sync_scroll(); |
| 679 | } | 745 | } |
| 680 | 746 | ||
| 681 | pub fn repaint_region(x: usize, y: usize, w: usize, h: usize) { | 747 | pub fn repaint_region(x: usize, y: usize, w: usize, h: usize) { |
| 682 | home().repaint_region(x, y, w, h); | 748 | active().repaint_region(x, y, w, h); |
| 683 | } | 749 | } |
| 684 | 750 | ||
| 685 | pub fn write_bytes(b: &[u8]) { | 751 | pub fn write_bytes(b: &[u8]) { |
| 686 | home().write_bytes(b); | 752 | active().write_bytes(b); |
| 687 | } | 753 | } |
| 688 | 754 | ||
| 689 | pub fn write_str(s: &str) { | 755 | pub fn write_str(s: &str) { |
| 690 | home().write_str(s); | 756 | active().write_str(s); |
| 691 | } | 757 | } |
| 692 | 758 | ||
| 693 | pub fn put_char(b: u8) { | 759 | pub fn put_char(b: u8) { |
| 694 | home().put_char(b); | 760 | active().put_char(b); |
| 695 | } | 761 | } |
| 696 | 762 | ||
| 697 | pub fn clear_all() { | 763 | pub fn clear_all() { |
| 698 | home().clear_all(); | 764 | active().clear_all(); |
| 699 | } | 765 | } |
| 700 | 766 | ||
| 701 | // --------------------------------------------------------------------------- | 767 | // --------------------------------------------------------------------------- |
