From f0ee584c87d434a083d6b9ffa249a825a7a0e8f8 Mon Sep 17 00:00:00 2001 From: FantasyPvP <80643031+FantasyPvP@users.noreply.github.com> Date: Sun, 1 Oct 2023 03:18:57 +0100 Subject: [PATCH] changed backspace functionality backspace will now skip to the last real character on a line and skip over null characters --- src/old_code/render.rs | 290 +++++++++++++++++++++ src/system/kernel/mod.rs | 2 +- src/system/kernel/render.rs | 376 +++++++++++++++------------- src/system/kernel/render2.rs | 298 ---------------------- src/system/kernel/tasks/keyboard.rs | 2 +- src/system/std/io.rs | 7 +- src/user/lib/libgui/libgui_core.rs | 2 +- 7 files changed, 502 insertions(+), 475 deletions(-) create mode 100644 src/old_code/render.rs delete mode 100644 src/system/kernel/render2.rs diff --git a/src/old_code/render.rs b/src/old_code/render.rs new file mode 100644 index 0000000..f96380c --- /dev/null +++ b/src/old_code/render.rs @@ -0,0 +1,290 @@ +use core::fmt; +use lazy_static::lazy_static; +use spin::Mutex; +use volatile::Volatile; + +use alloc::borrow::ToOwned; +use alloc::vec; +use alloc::vec::Vec; + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +pub enum Color { + Black = 0, + Blue = 1, + Green = 2, + Cyan = 3, + Red = 4, + Magenta = 5, + Brown = 6, + LightGray = 7, + DarkGray = 8, + LightBlue = 9, + LightGreen = 10, + LightCyan = 11, + LightRed = 12, + Pink = 13, + Yellow = 14, + White = 15, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(transparent)] +pub struct ColorCode(u8); + +impl ColorCode { + pub fn new(foreground: Color, background: Color) -> ColorCode { + ColorCode((background as u8) << 5 | (foreground as u8)) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(C)] +struct ScreenChar { + character: u8, + colour: ColorCode, +} + +pub const BUFFER_HEIGHT: usize = 25; +pub const BUFFER_WIDTH: usize = 80; + +#[repr(transparent)] +struct Buffer { + chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], +} + +struct BufferSwap { + chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], +} +struct CharGrid { + chars: Vec<[ScreenChar; BUFFER_WIDTH]>, +} + +pub struct Renderer { + col_pos: usize, + pub col_code: ColorCode, + buffer: &'static mut Buffer, + userspace: BufferSwap, + upwards: CharGrid, + downwards: CharGrid, + pub sandbox: bool, +} + + + + +lazy_static! { + pub static ref RENDERER: Mutex = Mutex::new(Renderer { + col_pos: 0, + col_code: ColorCode::new(Color::White, Color::Black), + buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, + userspace: BufferSwap { + chars: [[ScreenChar { + character: 178u8, + colour: ColorCode::new(Color::White, Color::Black), + }; BUFFER_WIDTH]; BUFFER_HEIGHT] + }, + upwards: CharGrid { + chars: vec![ + [ScreenChar { + character: 32u8, + colour: ColorCode::new(Color::White, Color::Black), + }; 80] + ] + }, + downwards: CharGrid { + chars: vec![ + [ScreenChar { + character: 32u8, + colour: ColorCode::new(Color::White, Color::Black), + }; 80] + ] + }, + sandbox: false, + }); +} + +impl Renderer { + pub fn text_mode(&mut self) -> Result<(), ()> { + if !self.sandbox { + return Err(()); + }; + self.buffer_swap().unwrap(); + self.sandbox = false; + Ok(()) + } + + pub fn sandbox_mode(&mut self) -> Result<(), ()> { + if self.sandbox { + return Err(()); + }; + self.buffer_swap().unwrap(); + self.sandbox = true; + Ok(()) + } + + fn buffer_swap(&mut self) -> Result<(), ()> { + for (i, _) in self.userspace.chars.clone().iter().enumerate() { + let tmp = self.buffer.chars[i].clone(); + + for (j, col) in self.userspace.chars[i].clone().iter().enumerate() { + self.buffer.chars[i][j].write(col.to_owned()) + } + + for (j, _) in tmp.iter().enumerate() { + self.userspace.chars[i][j] = tmp[j].read().to_owned() + } + } + + Ok(()) + } + + pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { + for (i, row) in frame.iter().enumerate() { + for (j, col) in row.iter().enumerate() { + if let Some(c) = self.fancy_char(*col) { + self.buffer.chars[i][j].write(ScreenChar { + character: c, + colour: self.col_code, + }); + } else { + self.buffer.chars[i][j].write(ScreenChar { + character: *col as u8, + colour: self.col_code, + }); + } + } + } + } + + pub fn write_string(&mut self, string: &str) { + for ch in string.chars() { + if let Some(x) = self.fancy_char(ch) { + self.write_byte(x) + } else { + match ch as u8 { + 0x20..=0xff | b'\n' => self.write_byte(ch as u8), + _ => self.write_byte(0xfe), + } + } + } + } + + fn fancy_char(&self, ch: char) -> Option { + let res: u8 = match ch { + '│' => 179, + '─' => 196, + '┴' => 193, + '┤' => 180, + '═' => 205, + '║' => 186, + '╗' => 187, + '╝' => 188, + '╚' => 200, + '╔' => 201, + '»' => 175, + '┐' => 191, + '└' => 192, + '┘' => 217, + '┌' => 218, + '┼' => 197, + '░' => 176, + '▓' => 178, + '«' => 174, + '»' => 175, + _ => { + return None; + } + }; + Some(res) + } + + pub fn backspace(&mut self) -> Result<(), ()> { + if self.col_pos == 0 { + self.undonewline(); + } + self.col_pos -= 1; + let row = BUFFER_HEIGHT - 1; + let col = self.col_pos; + + let blank = ScreenChar { + character: b' ', + colour: self.col_code, + }; + self.buffer.chars[row][col].write(blank); + Ok(()) + } + + pub fn write_byte(&mut self, byte: u8) { + match byte { + b'\n' => self.newline(), + byte => { + if self.col_pos >= BUFFER_WIDTH { + self.newline(); + } + let row = BUFFER_HEIGHT - 1; + let col = self.col_pos; + let col_code = self.col_code; + self.buffer.chars[row][col].write(ScreenChar { + character: byte, + colour: col_code, + }); + self.col_pos += 1 + } + } + } + fn newline(&mut self) { + for row in 1..BUFFER_HEIGHT { + for col in 0..BUFFER_WIDTH { + let character = self.buffer.chars[row][col].read(); + self.buffer.chars[row - 1][col].write(character); + } + } + self.clear_row(BUFFER_HEIGHT - 1); + self.col_pos = 0; + } + + pub fn undonewline(&mut self) { + for row in (0..BUFFER_HEIGHT - 1).rev() { + for col in 0..BUFFER_WIDTH { + let character = self.buffer.chars[row][col].read(); + self.buffer.chars[row + 1][col].write(character); + } + } + self.clear_row(0); + self.col_pos = BUFFER_WIDTH; + } + pub fn clear(&mut self) { + for row in (0..BUFFER_HEIGHT - 1).rev() { + self.clear_row(row); + } + } + + fn clear_row(&mut self, row: usize) { + let blank = ScreenChar { + character: b' ', + colour: self.col_code, + }; + for col in 0..BUFFER_WIDTH { + self.buffer.chars[row][col].write(blank); + } + } +} + +impl fmt::Write for Renderer { + fn write_str(&mut self, string: &str) -> fmt::Result { + self.write_string(string); + Ok(()) + } +} + +pub fn write(args: fmt::Arguments, cols: (Color, Color)) { + use core::fmt::Write; + use x86_64::instructions::interrupts; + interrupts::without_interrupts(|| { + let mut writer = RENDERER.lock(); + writer.col_code = ColorCode::new(cols.0, cols.1); + writer.write_fmt(args).unwrap() + }) +} diff --git a/src/system/kernel/mod.rs b/src/system/kernel/mod.rs index 2855aaf..4ebd509 100644 --- a/src/system/kernel/mod.rs +++ b/src/system/kernel/mod.rs @@ -8,4 +8,4 @@ pub mod serial; pub mod tasks; pub mod sysinit; pub mod authenticator; -pub mod render2; \ No newline at end of file +pub mod render; \ No newline at end of file diff --git a/src/system/kernel/render.rs b/src/system/kernel/render.rs index f96380c..49ecc03 100644 --- a/src/system/kernel/render.rs +++ b/src/system/kernel/render.rs @@ -6,6 +6,7 @@ use volatile::Volatile; use alloc::borrow::ToOwned; use alloc::vec; use alloc::vec::Vec; +use crate::std::io::Screen; #[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -46,132 +47,232 @@ struct ScreenChar { colour: ColorCode, } +impl ScreenChar { + fn null() -> ScreenChar { + ScreenChar { + character: 0u8, + colour: ColorCode::new(Color::White, Color::Black), + } + } + fn white(character: u8) -> ScreenChar { + ScreenChar { + character, + colour: ColorCode::new(Color::White, Color::Black), + } + } +} + pub const BUFFER_HEIGHT: usize = 25; pub const BUFFER_WIDTH: usize = 80; #[repr(transparent)] -struct Buffer { +struct VGAOutput { chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], } -struct BufferSwap { - chars: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], -} -struct CharGrid { - chars: Vec<[ScreenChar; BUFFER_WIDTH]>, -} - pub struct Renderer { col_pos: usize, - pub col_code: ColorCode, - buffer: &'static mut Buffer, - userspace: BufferSwap, - upwards: CharGrid, - downwards: CharGrid, - pub sandbox: bool, + screen_ref: &'static mut VGAOutput, // this should not be accessed unless the screen is rendering a new frame + term_buffer: Vec<[ScreenChar; BUFFER_WIDTH]>, // this is the standard terminal output view + app_buffer: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], // this is where applications render their frames to + application_mode: bool, // if false: term mode; if true: app mode + temp_colour: Option, } - - - lazy_static! { pub static ref RENDERER: Mutex = Mutex::new(Renderer { col_pos: 0, - col_code: ColorCode::new(Color::White, Color::Black), - buffer: unsafe { &mut *(0xb8000 as *mut Buffer) }, - userspace: BufferSwap { - chars: [[ScreenChar { - character: 178u8, - colour: ColorCode::new(Color::White, Color::Black), - }; BUFFER_WIDTH]; BUFFER_HEIGHT] - }, - upwards: CharGrid { - chars: vec![ - [ScreenChar { - character: 32u8, - colour: ColorCode::new(Color::White, Color::Black), - }; 80] - ] - }, - downwards: CharGrid { - chars: vec![ - [ScreenChar { - character: 32u8, - colour: ColorCode::new(Color::White, Color::Black), - }; 80] - ] - }, - sandbox: false, + screen_ref: unsafe { &mut *(0xb8000 as *mut VGAOutput) }, + term_buffer: vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT], + app_buffer: [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT], + application_mode: false, + temp_colour: None, }); } impl Renderer { - pub fn text_mode(&mut self) -> Result<(), ()> { - if !self.sandbox { - return Err(()); - }; - self.buffer_swap().unwrap(); - self.sandbox = false; - Ok(()) - } + // EXTERNAL API : for use by standard library and other parts of the kernel + pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer + let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; - pub fn sandbox_mode(&mut self) -> Result<(), ()> { - if self.sandbox { - return Err(()); - }; - self.buffer_swap().unwrap(); - self.sandbox = true; - Ok(()) - } - - fn buffer_swap(&mut self) -> Result<(), ()> { - for (i, _) in self.userspace.chars.clone().iter().enumerate() { - let tmp = self.buffer.chars[i].clone(); - - for (j, col) in self.userspace.chars[i].clone().iter().enumerate() { - self.buffer.chars[i][j].write(col.to_owned()) - } - - for (j, _) in tmp.iter().enumerate() { - self.userspace.chars[i][j] = tmp[j].read().to_owned() - } - } - - Ok(()) - } - - pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { for (i, row) in frame.iter().enumerate() { for (j, col) in row.iter().enumerate() { - if let Some(c) = self.fancy_char(*col) { - self.buffer.chars[i][j].write(ScreenChar { - character: c, - colour: self.col_code, - }); - } else { - self.buffer.chars[i][j].write(ScreenChar { - character: *col as u8, - colour: self.col_code, - }); - } + processed_frame[i][j] = match self.special_char(*col) { + Some(c) => ScreenChar::white(c as u8), + None => ScreenChar::white(*col as u8) + }; } } + + self.app_buffer = processed_frame; + } + + pub fn application_mode(&mut self) -> Result<(), ()> { + if self.application_mode { + return Err(()); + } else { + self.application_mode = true; + self.internal_render(); + Ok(()) + } } - pub fn write_string(&mut self, string: &str) { + pub fn terminal_mode(&mut self) -> Result<(), ()> { + if !self.application_mode { + return Err(()); + } else { + self.application_mode = false; + self.internal_render(); + Ok(()) + } + } + + pub fn mode_is_app(&self) -> bool { + self.application_mode + } + + pub fn write_char(&mut self, ch: u8, col: Option) { // default colour if no colour is selected for character + self.write_byte(ch, col); + self.internal_render(); + } + + pub fn write_string(&mut self, string: &str, col: Option) { for ch in string.chars() { - if let Some(x) = self.fancy_char(ch) { - self.write_byte(x) - } else { - match ch as u8 { - 0x20..=0xff | b'\n' => self.write_byte(ch as u8), - _ => self.write_byte(0xfe), + match self.special_char(ch) { + Some(c) => self.write_byte(c, col), + None => match ch as u8 { + 0x20..=0xff | b'\n' => self.write_byte(ch as u8, col), + _ => self.write_byte(0xfe, col), } } } + self.internal_render(); + } + + pub fn backspace(&mut self) -> Result<(), ()> { + + loop { + if self.internal_backspace()? { + break; + } + } + + self.internal_render(); + Ok(()) + } + + pub fn clear(&mut self) { // clears the screen and all scroll-back + if self.application_mode { return; }; + self.term_buffer = vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; + self.internal_render(); + } + + pub fn with_colour(&mut self, cols: ColorCode) { + self.temp_colour = Some(cols); + } + pub fn reset_colour(&mut self) { + self.temp_colour = None; + } + + // INTERNAL API ONLY + + fn set_cursor_position(&mut self, row: usize, col: usize) { + use x86_64::instructions::port::Port; + let cursor_position: u16 = (row as u16) * 80 + (col as u16); + + unsafe {// Write the high byte of the cursor position to register 14 + let mut control_port = Port::::new(0x3D4); + control_port.write(14); + // Write the high byte of the cursor position to register 15 + let mut data_port = Port::::new(0x3D5); + data_port.write((cursor_position >> 8) as u8); + // Write the low byte of the cursor position to register 14 + control_port.write(15); + // Write the low byte of the cursor position to register 15 + data_port.write((cursor_position & 0xFF) as u8); + } + } + + fn internal_backspace(&mut self) -> Result { + let mut should_break = false; + + if self.col_pos == 0 { + self.internal_lastline(); + } + self.col_pos -= 1; + let col = self.col_pos; + + let buff_len = self.term_buffer.len(); + + if self.term_buffer[buff_len - 1][col].character != 0 { + should_break = true + } + + self.term_buffer[buff_len - 1][col] = ScreenChar::null(); + Ok(should_break) + } + + fn internal_newline(&mut self) { // moves all content one line up the screen and creates new line + if self.application_mode { return; }; // only in terminal mode + self.term_buffer.push([ScreenChar::null(); BUFFER_WIDTH]); + self.col_pos = 0; + } + + fn internal_lastline(&mut self) { // goes back to previous line and shifts all lines down + if self.application_mode { return; }; + self.term_buffer.pop(); + self.col_pos = BUFFER_WIDTH; + } + + fn write_screen_char(&mut self, ch: ScreenChar) { // TODO: optimise so that screen is not fully re-rendered for every string written. + match ch.character as u8 { + b'\n' => self.internal_newline(), + _ => { + if self.col_pos >= BUFFER_WIDTH { + self.internal_newline(); + } + let row = BUFFER_HEIGHT - 1; + let col = self.col_pos; + + let buff_len = self.term_buffer.len(); + self.term_buffer[buff_len - 1][col] = ch; + self.col_pos += 1; + } + } } - fn fancy_char(&self, ch: char) -> Option { + fn write_byte(&mut self, byte: u8, col: Option) { // default colour if no colour is selected for character + self.write_screen_char(ScreenChar { + character: byte, + colour: match col { + Some(c) => c, + None => match self.temp_colour { + Some(c) => c, + None => ColorCode::new(Color::White, Color::Black), + } + }, + }); + } + + fn internal_render(&mut self) { // private function that can only be used from within this struct. + if self.application_mode { + for (i, row) in self.app_buffer.iter().enumerate() { + for (j, col) in row.iter().enumerate() { + self.screen_ref.chars[i][j].write(*col); + } + } + } else { + let buff_len = self.term_buffer.len(); + for (i, row) in self.term_buffer[buff_len - BUFFER_HEIGHT..buff_len].iter().enumerate() { + for (j, col) in row.iter().enumerate() { + self.screen_ref.chars[i][j].write(*col); + } + } + } + self.set_cursor_position(BUFFER_HEIGHT - 1, self.col_pos); + } + + fn special_char(&self, ch: char) -> Option { let res: u8 = match ch { '│' => 179, '─' => 196, @@ -192,89 +293,17 @@ impl Renderer { '░' => 176, '▓' => 178, '«' => 174, - '»' => 175, _ => { return None; } }; Some(res) } - - pub fn backspace(&mut self) -> Result<(), ()> { - if self.col_pos == 0 { - self.undonewline(); - } - self.col_pos -= 1; - let row = BUFFER_HEIGHT - 1; - let col = self.col_pos; - - let blank = ScreenChar { - character: b' ', - colour: self.col_code, - }; - self.buffer.chars[row][col].write(blank); - Ok(()) - } - - pub fn write_byte(&mut self, byte: u8) { - match byte { - b'\n' => self.newline(), - byte => { - if self.col_pos >= BUFFER_WIDTH { - self.newline(); - } - let row = BUFFER_HEIGHT - 1; - let col = self.col_pos; - let col_code = self.col_code; - self.buffer.chars[row][col].write(ScreenChar { - character: byte, - colour: col_code, - }); - self.col_pos += 1 - } - } - } - fn newline(&mut self) { - for row in 1..BUFFER_HEIGHT { - for col in 0..BUFFER_WIDTH { - let character = self.buffer.chars[row][col].read(); - self.buffer.chars[row - 1][col].write(character); - } - } - self.clear_row(BUFFER_HEIGHT - 1); - self.col_pos = 0; - } - - pub fn undonewline(&mut self) { - for row in (0..BUFFER_HEIGHT - 1).rev() { - for col in 0..BUFFER_WIDTH { - let character = self.buffer.chars[row][col].read(); - self.buffer.chars[row + 1][col].write(character); - } - } - self.clear_row(0); - self.col_pos = BUFFER_WIDTH; - } - pub fn clear(&mut self) { - for row in (0..BUFFER_HEIGHT - 1).rev() { - self.clear_row(row); - } - } - - fn clear_row(&mut self, row: usize) { - let blank = ScreenChar { - character: b' ', - colour: self.col_code, - }; - for col in 0..BUFFER_WIDTH { - self.buffer.chars[row][col].write(blank); - } - } } impl fmt::Write for Renderer { fn write_str(&mut self, string: &str) -> fmt::Result { - self.write_string(string); + self.write_string(string, None); Ok(()) } } @@ -282,9 +311,14 @@ impl fmt::Write for Renderer { pub fn write(args: fmt::Arguments, cols: (Color, Color)) { use core::fmt::Write; use x86_64::instructions::interrupts; + + let colour_code = ColorCode::new(cols.0, cols.1); + interrupts::without_interrupts(|| { let mut writer = RENDERER.lock(); - writer.col_code = ColorCode::new(cols.0, cols.1); - writer.write_fmt(args).unwrap() + + writer.with_colour(colour_code); + writer.write_fmt(args).unwrap(); + writer.reset_colour(); }) -} +} \ No newline at end of file diff --git a/src/system/kernel/render2.rs b/src/system/kernel/render2.rs deleted file mode 100644 index 149ffaf..0000000 --- a/src/system/kernel/render2.rs +++ /dev/null @@ -1,298 +0,0 @@ -use core::fmt; -use lazy_static::lazy_static; -use spin::Mutex; -use volatile::Volatile; - -use alloc::borrow::ToOwned; -use alloc::vec; -use alloc::vec::Vec; -use crate::std::io::Screen; - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum Color { - Black = 0, - Blue = 1, - Green = 2, - Cyan = 3, - Red = 4, - Magenta = 5, - Brown = 6, - LightGray = 7, - DarkGray = 8, - LightBlue = 9, - LightGreen = 10, - LightCyan = 11, - LightRed = 12, - Pink = 13, - Yellow = 14, - White = 15, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(transparent)] -pub struct ColorCode(u8); - -impl ColorCode { - pub fn new(foreground: Color, background: Color) -> ColorCode { - ColorCode((background as u8) << 5 | (foreground as u8)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(C)] -struct ScreenChar { - character: u8, - colour: ColorCode, -} - -impl ScreenChar { - fn null() -> ScreenChar { - ScreenChar { - character: 0u8, - colour: ColorCode::new(Color::White, Color::Black), - } - } - fn white(character: u8) -> ScreenChar { - ScreenChar { - character, - colour: ColorCode::new(Color::White, Color::Black), - } - } -} - -pub const BUFFER_HEIGHT: usize = 25; -pub const BUFFER_WIDTH: usize = 80; - -#[repr(transparent)] -struct VGAOutput { - chars: [[Volatile; BUFFER_WIDTH]; BUFFER_HEIGHT], -} - -pub struct Renderer { - col_pos: usize, - //col_code: ColorCode, // TODO: fully replace this with a colour code used in the fmt::Write function - screen_ref: &'static mut VGAOutput, // this should not be accessed unless the screen is rendering a new frame - term_buffer: Vec<[ScreenChar; BUFFER_WIDTH]>, // this is the standard terminal output view - app_buffer: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], // this is where applications render their frames to - application_mode: bool, // if false: term mode; if true: app mode -} - -lazy_static! { - pub static ref RENDERER: Mutex = Mutex::new(Renderer { - col_pos: 0, - screen_ref: unsafe { &mut *(0xb8000 as *mut VGAOutput) }, - term_buffer: vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT], - app_buffer: [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT], - application_mode: false, - }); -} - -impl Renderer { - // EXTERNAL API : for use by standard library and other parts of the kernel - pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer - let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; - - for (i, row) in frame.iter().enumerate() { - for (j, col) in row.iter().enumerate() { - processed_frame[i][j] = match self.special_char(*col) { - Some(c) => ScreenChar::white(c as u8), - None => ScreenChar::white(*col as u8) - }; - } - } - - self.app_buffer = processed_frame; - } - - // TODO: change standard library for alternative to these functions - pub fn application_mode(&mut self) -> Result<(), ()> { - if self.application_mode { - return Err(()); - } else { - self.application_mode = true; - self.internal_render(); - Ok(()) - } - } - - pub fn terminal_mode(&mut self) -> Result<(), ()> { - if !self.application_mode { - return Err(()); - } else { - self.application_mode = false; - self.internal_render(); - Ok(()) - } - } - - pub fn mode_is_app(&self) -> bool { - self.application_mode - } - - pub fn write_char(&mut self, ch: u8, col: Option) { // default colour if no colour is selected for character - self.write_byte(ch, col); - self.internal_render(); - } - - pub fn write_string(&mut self, string: &str, col: Option) { - for ch in string.chars() { - match self.special_char(ch) { - Some(c) => self.write_byte(c, col), - None => match ch as u8 { - 0x20..=0xff | b'\n' => self.write_byte(ch as u8, col), - _ => self.write_byte(0xfe, col), - } - } - } - self.internal_render(); - } - - pub fn backspace(&mut self) -> Result<(), ()> { - self.internal_backspace()?; - self.internal_render(); - Ok(()) - } - - pub fn clear(&mut self) { // clears the screen and all scroll-back - if self.application_mode { return; }; - self.term_buffer = vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT]; - self.internal_render(); - } - - // INTERNAL API ONLY - - fn set_cursor_position(&mut self, row: usize, col: usize) { - use x86_64::instructions::port::Port; - let cursor_position: u16 = (row as u16) * 80 + (col as u16); - - unsafe {// Write the high byte of the cursor position to register 14 - let mut control_port = Port::::new(0x3D4); - control_port.write(14); - - // Write the high byte of the cursor position to register 15 - let mut data_port = Port::::new(0x3D5); - data_port.write((cursor_position >> 8) as u8); - - // Write the low byte of the cursor position to register 14 - control_port.write(15); - - // Write the low byte of the cursor position to register 15 - data_port.write((cursor_position & 0xFF) as u8); - } - } - - fn internal_backspace(&mut self) -> Result<(), ()> { - if self.col_pos == 0 { - self.internal_lastline(); - } - self.col_pos -= 1; - let col = self.col_pos; - - let buff_len = self.term_buffer.len(); - self.term_buffer[buff_len - 1][col] = ScreenChar::null(); - Ok(()) - } - - fn internal_newline(&mut self) { // moves all content one line up the screen and creates new line - if self.application_mode { return; }; // only in terminal mode - self.term_buffer.push([ScreenChar::null(); BUFFER_WIDTH]); - self.col_pos = 0; - } - - fn internal_lastline(&mut self) { // goes back to previous line and shifts all lines down - if self.application_mode { return; }; - self.term_buffer.pop(); - self.col_pos = BUFFER_WIDTH; - } - - fn write_screen_char(&mut self, ch: ScreenChar) { // TODO: optimise so that screen is not fully re-rendered for every string written. - match ch.character as u8 { - b'\n' => self.internal_newline(), - _ => { - if self.col_pos >= BUFFER_WIDTH { - self.internal_newline(); - } - let row = BUFFER_HEIGHT - 1; - let col = self.col_pos; - - let buff_len = self.term_buffer.len(); - self.term_buffer[buff_len - 1][col] = ch; - self.col_pos += 1; - } - } - } - - fn write_byte(&mut self, byte: u8, col: Option) { // default colour if no colour is selected for character - self.write_screen_char(ScreenChar { - character: byte, - colour: match col { - Some(c) => c, - None => ColorCode::new(Color::White, Color::Black), - }, - }); - } - - fn internal_render(&mut self) { // private function that can only be used from within this struct. - if self.application_mode { - for (i, row) in self.app_buffer.iter().enumerate() { - for (j, col) in row.iter().enumerate() { - self.screen_ref.chars[i][j].write(*col); - } - } - } else { - let buff_len = self.term_buffer.len(); - for (i, row) in self.term_buffer[buff_len - BUFFER_HEIGHT..buff_len].iter().enumerate() { - for (j, col) in row.iter().enumerate() { - self.screen_ref.chars[i][j].write(*col); - } - } - } - self.set_cursor_position(BUFFER_HEIGHT - 1, self.col_pos); - } - - fn special_char(&self, ch: char) -> Option { - let res: u8 = match ch { - '│' => 179, - '─' => 196, - '┴' => 193, - '┤' => 180, - '═' => 205, - '║' => 186, - '╗' => 187, - '╝' => 188, - '╚' => 200, - '╔' => 201, - '»' => 175, - '┐' => 191, - '└' => 192, - '┘' => 217, - '┌' => 218, - '┼' => 197, - '░' => 176, - '▓' => 178, - '«' => 174, - _ => { - return None; - } - }; - Some(res) - } -} - -impl fmt::Write for Renderer { - fn write_str(&mut self, string: &str) -> fmt::Result { - self.write_string(string, None); - Ok(()) - } -} - -pub fn write(args: fmt::Arguments, cols: (Color, Color)) { - use core::fmt::Write; - use x86_64::instructions::interrupts; - interrupts::without_interrupts(|| { - let mut writer = RENDERER.lock(); - writer.write_fmt(args).unwrap() - }) -} \ No newline at end of file diff --git a/src/system/kernel/tasks/keyboard.rs b/src/system/kernel/tasks/keyboard.rs index a4920d7..a0d36a2 100644 --- a/src/system/kernel/tasks/keyboard.rs +++ b/src/system/kernel/tasks/keyboard.rs @@ -13,7 +13,7 @@ use futures_util::task::AtomicWaker; use futures_util::stream::StreamExt; use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; use crate::print; -use crate::kernel::render2::RENDERER; +use crate::kernel::render::RENDERER; use alloc::{string::String}; static WAKER: AtomicWaker = AtomicWaker::new(); diff --git a/src/system/std/io.rs b/src/system/std/io.rs index c92043c..c4d541a 100644 --- a/src/system/std/io.rs +++ b/src/system/std/io.rs @@ -1,11 +1,12 @@ use crate::{ - kernel::render2::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode}, + kernel::render::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode}, kernel::tasks::keyboard::KEYBOARD, }; use alloc::{boxed::Box, string::{String, ToString}, vec::Vec}; pub use crate::{print, println, serial_print, serial_println}; +pub use crate::kernel::render::Color; use lazy_static::lazy_static; use spin::Mutex; @@ -201,10 +202,10 @@ pub fn _log(args: core::fmt::Arguments) { }); } -pub use crate::kernel::render2::Color; + pub fn write(args: core::fmt::Arguments, cols: (Color, Color)) { - crate::kernel::render2::write(args, cols); + crate::kernel::render::write(args, cols); } pub fn mkfs() { diff --git a/src/user/lib/libgui/libgui_core.rs b/src/user/lib/libgui/libgui_core.rs index 01fbc0e..cf9b45b 100644 --- a/src/user/lib/libgui/libgui_core.rs +++ b/src/user/lib/libgui/libgui_core.rs @@ -1,4 +1,4 @@ -use crate::kernel::render2::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER}; +use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER}; use crate::std::io::Frame; use crate::{print, println}; use alloc::{