Merge branch 'graphics_rework' into 'master'

Move text console handling from vesad to a new fbcond daemon

See merge request redox-os/drivers!128
This commit is contained in:
Jeremy Soller
2024-01-15 02:00:50 +00:00
21 changed files with 1131 additions and 895 deletions
Generated
+44 -61
View File
@@ -11,7 +11,7 @@ dependencies = [
"log",
"redox-daemon",
"redox-log",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
"spin",
]
@@ -59,7 +59,7 @@ dependencies = [
"common",
"netutils",
"redox-daemon",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
]
@@ -120,15 +120,6 @@ name = "arg_parser"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#1c434b55f3e1a0375ebcca85b3e88db7378e82fa"
[[package]]
name = "arrayvec"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
dependencies = [
"nodrop",
]
[[package]]
name = "arrayvec"
version = "0.5.2"
@@ -386,7 +377,7 @@ dependencies = [
"common",
"netutils",
"redox-daemon",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
]
@@ -396,6 +387,18 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fbcond"
version = "0.1.0"
dependencies = [
"inputd",
"orbclient",
"ransid",
"redox-daemon",
"redox_event 0.2.1",
"redox_syscall 0.4.1",
]
[[package]]
name = "fdt"
version = "0.1.5"
@@ -608,7 +611,7 @@ dependencies = [
"pcid",
"redox-daemon",
"redox-log",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
"spin",
]
@@ -659,7 +662,7 @@ dependencies = [
"common",
"netutils",
"redox-daemon",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
]
@@ -685,10 +688,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
name = "libredox"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [
"bitflags 2.4.0",
"libc",
"redox_syscall 0.4.1",
]
[[package]]
name = "lived"
@@ -755,19 +763,13 @@ dependencies = [
"ntpclient",
"pbr",
"redox-daemon",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.3.5",
"redox_termios",
"termion",
"url",
]
[[package]]
name = "nodrop"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "ntpclient"
version = "0.0.1"
@@ -807,7 +809,7 @@ checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
name = "nvmed"
version = "0.1.0"
dependencies = [
"arrayvec 0.5.2",
"arrayvec",
"bitflags 1.3.2",
"block-io-wrapper",
"common",
@@ -1138,6 +1140,17 @@ dependencies = [
"redox_syscall 0.4.1",
]
[[package]]
name = "redox_event"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "475e252d7add4825405d2248d530d33e22364ac5477eab816b56efbeec1e2712"
dependencies = [
"bitflags 2.4.0",
"libredox",
"redox_syscall 0.4.1",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
@@ -1185,7 +1198,7 @@ dependencies = [
"pcid",
"redox-daemon",
"redox-log",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
]
@@ -1200,7 +1213,7 @@ dependencies = [
"pcid",
"redox-daemon",
"redox-log",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
]
@@ -1210,17 +1223,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rusttype"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a"
dependencies = [
"arrayvec 0.4.12",
"linked-hash-map",
"stb_truetype 0.2.8",
]
[[package]]
name = "ryu"
version = "1.0.15"
@@ -1236,7 +1238,7 @@ dependencies = [
"log",
"redox-daemon",
"redox-log",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
"spin",
]
@@ -1387,24 +1389,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "stb_truetype"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d"
dependencies = [
"stb_truetype 0.3.1",
]
[[package]]
name = "stb_truetype"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51"
dependencies = [
"byteorder 1.4.3",
]
[[package]]
name = "strsim"
version = "0.8.0"
@@ -1679,7 +1663,7 @@ dependencies = [
"common",
"orbclient",
"redox-daemon",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
]
@@ -1711,7 +1695,6 @@ dependencies = [
"ransid",
"redox-daemon",
"redox_syscall 0.4.1",
"rusttype",
]
[[package]]
@@ -1745,7 +1728,7 @@ dependencies = [
"log",
"pcid",
"redox-log",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
"static_assertions",
"thiserror",
@@ -1981,7 +1964,7 @@ dependencies = [
"plain",
"redox-daemon",
"redox-log",
"redox_event",
"redox_event 0.1.0",
"redox_syscall 0.4.1",
"serde",
"serde_json",
+1
View File
@@ -8,6 +8,7 @@ members = [
"block-io-wrapper",
"common",
"e1000d",
"fbcond",
"ided",
"ihdad",
"ixgbed",
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "fbcond"
version = "0.1.0"
edition = "2021"
[dependencies]
orbclient = "0.3.27"
ransid = "0.4"
redox_event = "0.2"
redox_syscall = "0.4"
redox-daemon = "0.1"
inputd = { path = "../inputd" }
[features]
default = []
+159
View File
@@ -0,0 +1,159 @@
use std::fs::OpenOptions;
use std::mem;
use std::os::unix::fs::OpenOptionsExt;
use std::{
fs::File,
io,
os::fd::RawFd,
os::unix::io::{AsRawFd, FromRawFd},
slice,
};
use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR};
// Keep synced with vesad
#[derive(Clone, Copy)]
#[repr(packed)]
pub struct SyncRect {
pub x: i32,
pub y: i32,
pub w: i32,
pub h: i32,
}
fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> {
unsafe {
let display_ptr = syscall::fmap(
display_fd,
&syscall::Map {
offset: 0,
size: (width * height * 4),
flags: syscall::PROT_READ | syscall::PROT_WRITE | syscall::MAP_SHARED,
address: 0,
},
)?;
let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height);
Ok(display_slice)
}
}
unsafe fn display_fd_unmap(image: *mut [u32], size: usize) {
// FIXME use image.len() instead of size once it is stable.
let _ = syscall::funmap(image as *mut u32 as usize, size * 4);
}
pub struct Display {
pub input_handle: File,
pub display_file: File,
pub offscreen: *mut [u32],
pub width: usize,
pub height: usize,
}
impl Display {
pub fn open_vt(vt: usize) -> io::Result<Self> {
let mut buffer = [0; 1024];
let input_handle = OpenOptions::new()
.read(true)
.custom_flags(O_NONBLOCK as i32)
.open(format!("input:consumer/{vt}"))?;
let fd = input_handle.as_raw_fd();
let written = syscall::fpath(fd as usize, &mut buffer)
.expect("init: failed to get the path to the display device");
assert!(written <= buffer.len());
let display_path =
std::str::from_utf8(&buffer[..written]).expect("init: display path UTF-8 check failed");
let display_file = syscall::open(display_path, O_CLOEXEC | O_NONBLOCK | O_RDWR)
.map(|socket| unsafe { File::from_raw_fd(socket as RawFd) })
.unwrap_or_else(|err| {
panic!("failed to open display {}: {}", display_path, err);
});
let mut buf: [u8; 4096] = [0; 4096];
let count =
syscall::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| {
panic!("Could not read display path with fpath(): {e}");
});
let url =
String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String");
let path = Self::url_parts(&url)?;
let (width, height) = Self::parse_display_path(path);
let offscreen_buffer = display_fd_map(width, height, display_file.as_raw_fd() as usize)
.unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}"));
Ok(Self {
input_handle,
display_file,
offscreen: offscreen_buffer,
width,
height,
})
}
fn url_parts(url: &str) -> io::Result<&str> {
let mut url_parts = url.split(':');
url_parts
.next()
.expect("Could not get scheme name from url");
let path = url_parts.next().expect("Could not get path from url");
Ok(path)
}
fn parse_display_path(path: &str) -> (usize, usize) {
let mut path_parts = path.split('/').skip(1);
let width = path_parts
.next()
.unwrap_or("")
.parse::<usize>()
.unwrap_or(0);
let height = path_parts
.next()
.unwrap_or("")
.parse::<usize>()
.unwrap_or(0);
(width, height)
}
pub fn resize(&mut self, width: usize, height: usize) {
match display_fd_map(width, height, self.display_file.as_raw_fd() as usize) {
Ok(ok) => {
unsafe {
display_fd_unmap(self.offscreen, (self.width * self.height) as usize);
}
self.offscreen = ok;
self.width = width;
self.height = height;
}
Err(err) => {
eprintln!("failed to resize display to {}x{}: {}", width, height, err);
}
}
}
pub fn sync_rect(&mut self, sync_rect: SyncRect) -> syscall::Result<()> {
unsafe {
syscall::write(
self.display_file.as_raw_fd().as_raw_fd() as usize,
slice::from_raw_parts(
&sync_rect as *const SyncRect as *const u8,
mem::size_of::<SyncRect>(),
),
)?;
Ok(())
}
}
}
impl Drop for Display {
fn drop(&mut self) {
unsafe {
display_fd_unmap(self.offscreen, self.width * self.height);
}
}
}
+197
View File
@@ -0,0 +1,197 @@
use event::EventQueue;
use orbclient::Event;
use std::fs::{File, OpenOptions};
use std::io::{ErrorKind, Read, Write};
use std::os::fd::AsRawFd;
use std::os::unix::fs::OpenOptionsExt;
use std::{env, io, mem, slice};
use syscall::{Packet, SchemeMut, EVENT_READ, O_NONBLOCK};
use crate::scheme::{FbconScheme, VtIndex};
mod display;
mod scheme;
mod text;
fn read_to_slice<R: Read, T: Copy>(mut r: R, buf: &mut [T]) -> io::Result<usize> {
unsafe {
r.read(slice::from_raw_parts_mut(
buf.as_mut_ptr() as *mut u8,
buf.len() * mem::size_of::<T>(),
))
.map(|count| count / mem::size_of::<T>())
}
}
fn main() {
let vt_ids = env::args()
.skip(1)
.map(|arg| arg.parse().expect("invalid vt number"))
.collect::<Vec<_>>();
redox_daemon::Daemon::new(|daemon| inner(daemon, &vt_ids)).expect("failed to create daemon");
}
fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! {
let mut event_queue = EventQueue::new().expect("fbcond: failed to create event queue");
// FIXME listen for resize events from inputd and handle them
let mut socket = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.custom_flags(O_NONBLOCK as i32)
.open(":fbcon")
.expect("fbcond: failed to create fbcon scheme");
event_queue
.subscribe(
socket.as_raw_fd().as_raw_fd() as usize,
VtIndex::SCHEMA_SENTINEL,
event::EventFlags::READ,
)
.expect("fbcond: failed to subscribe to scheme events");
let mut scheme = FbconScheme::new(vt_ids, &mut event_queue);
syscall::setrens(0, 0).expect("fbcond: failed to enter null namespace");
daemon.ready().expect("failed to notify parent");
scheme
.inputd_handle
.activate(1, inputd::VtMode::Default)
.unwrap();
let mut blocked = Vec::new();
// Handle all events that could have happened before registering with the event queue.
handle_event(
&mut socket,
&mut scheme,
&mut blocked,
VtIndex::SCHEMA_SENTINEL,
);
for vt_i in scheme.vts.keys().copied().collect::<Vec<_>>() {
handle_event(&mut socket, &mut scheme, &mut blocked, vt_i);
}
for event in event_queue {
let event = event.expect("fbcond: failed to read event from event queue");
handle_event(&mut socket, &mut scheme, &mut blocked, event.user_data);
}
std::process::exit(0);
}
fn handle_event(
socket: &mut File,
scheme: &mut FbconScheme,
blocked: &mut Vec<Packet>,
event: VtIndex,
) {
match event {
VtIndex::SCHEMA_SENTINEL => {
loop {
let mut packet = Packet::default();
match socket.read(&mut packet) {
Ok(0) => break,
Err(err) if err.kind() == ErrorKind::WouldBlock => {
break;
}
Ok(_) => {}
Err(err) => {
panic!("fbcond: failed to read display scheme: {err}");
}
}
// If it is a read packet, and there is no data, block it. Otherwise, handle packet
if packet.a == syscall::number::SYS_READ
&& packet.d > 0
&& scheme.can_read(packet.b).is_none()
{
blocked.push(packet);
} else {
scheme.handle(&mut packet);
socket
.write(&packet)
.expect("fbcond: failed to write display scheme");
}
}
}
vt_i => {
let vt = scheme.vts.get_mut(&vt_i).unwrap();
let mut events = [Event::new(); 16];
loop {
match read_to_slice(&mut vt.display.input_handle, &mut events) {
Ok(0) => break,
Err(err) if err.kind() == ErrorKind::WouldBlock => {
break;
}
Ok(count) => {
let events = &mut events[..count];
for event in events.iter_mut() {
vt.input(event)
}
}
Err(err) => {
panic!("fbcond: Error while reading events: {err}");
}
}
}
}
}
// If there are blocked readers, and data is available, handle them
{
let mut i = 0;
while i < blocked.len() {
if scheme.can_read(blocked[i].b).is_some() {
let mut packet = blocked.remove(i);
scheme.handle(&mut packet);
socket
.write(&packet)
.expect("fbcond: failed to write display scheme");
} else {
i += 1;
}
}
}
for (handle_id, handle) in scheme.handles.iter_mut() {
if !handle.events.contains(EVENT_READ) {
continue;
}
// Can't use scheme.can_read() because we borrow handles as mutable.
// (and because it'd treat O_NONBLOCK sockets differently)
let count = scheme
.vts
.get(&handle.vt_i)
.and_then(|console| console.can_read())
.unwrap_or(0);
if count > 0 {
if !handle.notified_read {
handle.notified_read = true;
let event_packet = Packet {
id: 0,
pid: 0,
uid: 0,
gid: 0,
a: syscall::number::SYS_FEVENT,
b: *handle_id,
c: EVENT_READ.bits(),
d: count,
};
socket
.write(&event_packet)
.expect("fbcond: failed to write display event");
}
} else {
handle.notified_read = false;
}
}
}
+186
View File
@@ -0,0 +1,186 @@
use std::collections::BTreeMap;
use std::os::fd::AsRawFd;
use event::{EventQueue, UserData};
use syscall::{Error, EventFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK};
use crate::display::Display;
use crate::text::TextScreen;
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)]
pub struct VtIndex(usize);
impl VtIndex {
pub const SCHEMA_SENTINEL: VtIndex = VtIndex(usize::MAX);
}
impl UserData for VtIndex {
fn into_user_data(self) -> usize {
self.0
}
fn from_user_data(user_data: usize) -> Self {
VtIndex(user_data)
}
}
#[derive(Clone)]
pub struct Handle {
pub vt_i: VtIndex,
pub flags: usize,
pub events: EventFlags,
pub notified_read: bool,
}
pub struct FbconScheme {
pub vts: BTreeMap<VtIndex, TextScreen>,
next_id: usize,
pub handles: BTreeMap<usize, Handle>,
pub inputd_handle: inputd::Handle,
}
impl FbconScheme {
pub fn new(vt_ids: &[usize], event_queue: &mut EventQueue<VtIndex>) -> FbconScheme {
let inputd_handle = inputd::Handle::new("vesa").unwrap();
let mut vts = BTreeMap::new();
for &vt_i in vt_ids {
let display = Display::open_vt(vt_i).expect("Failed to open display for vt");
event_queue.subscribe(
display.input_handle.as_raw_fd().as_raw_fd() as usize,
VtIndex(vt_i),
event::EventFlags::READ,
).expect("Failed to subscribe to input events for vt");
vts.insert(VtIndex(vt_i), TextScreen::new(display));
}
FbconScheme {
vts,
next_id: 0,
handles: BTreeMap::new(),
inputd_handle,
}
}
pub fn can_read(&self, id: usize) -> Option<usize> {
if let Some(handle) = self.handles.get(&id) {
if let Some(console) = self.vts.get(&handle.vt_i) {
console
.can_read()
.or(if handle.flags & O_NONBLOCK == O_NONBLOCK {
Some(0)
} else {
None
});
}
}
Some(0)
}
fn resize(&mut self, width: usize, height: usize, stride: usize) {
for console in self.vts.values_mut() {
console.resize(width, height);
}
}
}
impl SchemeMut for FbconScheme {
fn open(&mut self, path_str: &str, flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
let vt_i = VtIndex(path_str.parse::<usize>().map_err(|_| Error::new(ENOENT))?);
if let Some(_console) = self.vts.get_mut(&vt_i) {
let id = self.next_id;
self.next_id += 1;
self.handles.insert(
id,
Handle {
vt_i,
flags,
events: EventFlags::empty(),
notified_read: false,
},
);
Ok(id)
} else {
Err(Error::new(ENOENT))
}
}
fn dup(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
if !buf.is_empty() {
return Err(Error::new(EINVAL));
}
let handle = self
.handles
.get(&id)
.map(|handle| handle.clone())
.ok_or(Error::new(EBADF))?;
let new_id = self.next_id;
self.next_id += 1;
self.handles.insert(new_id, handle);
Ok(new_id)
}
fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result<syscall::EventFlags> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
handle.notified_read = false;
handle.events = flags;
Ok(syscall::EventFlags::empty())
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_str = format!("fbcon:{}", handle.vt_i.0);
let path = path_str.as_bytes();
let mut i = 0;
while i < buf.len() && i < path.len() {
buf[i] = path[i];
i += 1;
}
Ok(i)
}
fn fsync(&mut self, id: usize) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
return Ok(0);
}
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let Some(screen) = self.vts.get_mut(&handle.vt_i) {
return screen.read(buf);
}
Err(Error::new(EBADF))
}
fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let Some(console) = self.vts.get_mut(&handle.vt_i) {
console.write(buf)
} else {
Err(Error::new(EBADF))
}
}
fn close(&mut self, id: usize) -> Result<usize> {
self.handles.remove(&id).ok_or(Error::new(EBADF))?;
Ok(0)
}
}
+327
View File
@@ -0,0 +1,327 @@
extern crate ransid;
use std::collections::{BTreeSet, VecDeque};
use std::convert::{TryFrom, TryInto};
use std::os::fd::AsRawFd;
use std::{cmp, ptr};
use orbclient::{Event, EventOption, FONT};
use syscall::error::*;
use crate::display::{Display, SyncRect};
pub struct TextScreen {
console: ransid::Console,
pub display: Display,
changed: BTreeSet<usize>,
ctrl: bool,
input: VecDeque<u8>,
}
impl TextScreen {
pub fn new(display: Display) -> TextScreen {
TextScreen {
console: ransid::Console::new(display.width / 8, display.height / 16),
display,
changed: BTreeSet::new(),
ctrl: false,
input: VecDeque::new(),
}
}
/// Draw a rectangle
fn rect(display: &mut Display, x: usize, y: usize, w: usize, h: usize, color: u32) {
let start_y = cmp::min(display.height, y);
let end_y = cmp::min(display.height, y + h);
let start_x = cmp::min(display.width, x);
let len = cmp::min(display.width, x + w) - start_x;
let mut offscreen_ptr = display.offscreen as *mut u8 as usize;
let stride = display.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
for i in 0..len {
unsafe {
*(offscreen_ptr as *mut u32).add(i) = color;
}
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Invert a rectangle
fn invert(display: &mut Display, x: usize, y: usize, w: usize, h: usize) {
let start_y = cmp::min(display.height, y);
let end_y = cmp::min(display.height, y + h);
let start_x = cmp::min(display.width, x);
let len = cmp::min(display.width, x + w) - start_x;
let mut offscreen_ptr = display.offscreen as *mut u8 as usize;
let stride = display.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
let mut row_ptr = offscreen_ptr;
let mut cols = len;
while cols > 0 {
unsafe {
let color = *(row_ptr as *mut u32);
*(row_ptr as *mut u32) = !color;
}
row_ptr += 4;
cols -= 1;
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Draw a character
fn char(
display: &mut Display,
x: usize,
y: usize,
character: char,
color: u32,
_bold: bool,
_italic: bool,
) {
if x + 8 <= display.width && y + 16 <= display.height {
let mut dst = display.offscreen as *mut u8 as usize + (y * display.width + x) * 4;
let font_i = 16 * (character as usize);
if font_i + 16 <= FONT.len() {
for row in 0..16 {
let row_data = FONT[font_i + row];
for col in 0..8 {
if (row_data >> (7 - col)) & 1 == 1 {
unsafe {
*((dst + col * 4) as *mut u32) = color;
}
}
}
dst += display.width * 4;
}
}
}
}
pub fn resize(&mut self, width: usize, height: usize) {
self.display
.resize(width.try_into().unwrap(), height.try_into().unwrap());
self.console.state.w = width / 8;
self.console.state.h = height / 16;
}
pub fn input(&mut self, event: &Event) {
let mut buf = vec![];
match event.to_option() {
EventOption::Key(key_event) => {
if key_event.scancode == 0x1D {
self.ctrl = key_event.pressed;
} else if key_event.pressed {
match key_event.scancode {
0x0E => {
// Backspace
buf.extend_from_slice(b"\x7F");
}
0x47 => {
// Home
buf.extend_from_slice(b"\x1B[H");
}
0x48 => {
// Up
buf.extend_from_slice(b"\x1B[A");
}
0x49 => {
// Page up
buf.extend_from_slice(b"\x1B[5~");
}
0x4B => {
// Left
buf.extend_from_slice(b"\x1B[D");
}
0x4D => {
// Right
buf.extend_from_slice(b"\x1B[C");
}
0x4F => {
// End
buf.extend_from_slice(b"\x1B[F");
}
0x50 => {
// Down
buf.extend_from_slice(b"\x1B[B");
}
0x51 => {
// Page down
buf.extend_from_slice(b"\x1B[6~");
}
0x52 => {
// Insert
buf.extend_from_slice(b"\x1B[2~");
}
0x53 => {
// Delete
buf.extend_from_slice(b"\x1B[3~");
}
_ => {
let c = match key_event.character {
c @ 'A'..='Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
c @ 'a'..='z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
c => c,
};
if c != '\0' {
let mut b = [0; 4];
buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes());
}
}
}
}
}
_ => (), //TODO: Mouse in terminal
}
for &b in buf.iter() {
self.input.push_back(b);
}
}
pub fn can_read(&self) -> Option<usize> {
if self.input.is_empty() {
None
} else {
Some(self.input.len())
}
}
}
impl TextScreen {
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut i = 0;
while i < buf.len() && !self.input.is_empty() {
buf[i] = self.input.pop_front().unwrap();
i += 1;
}
Ok(i)
}
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
if self.console.state.cursor
&& self.console.state.x < self.console.state.w
&& self.console.state.y < self.console.state.h
{
let x = self.console.state.x;
let y = self.console.state.y;
Self::invert(&mut self.display, x * 8, y * 16, 8, 16);
self.changed.insert(y);
}
{
let display = &mut self.display;
let changed = &mut self.changed;
let input = &mut self.input;
self.console.write(buf, |event| match event {
ransid::Event::Char {
x,
y,
c,
color,
bold,
..
} => {
Self::char(display, x * 8, y * 16, c, color.as_rgb(), bold, false);
changed.insert(y);
}
ransid::Event::Input { data } => {
input.extend(data);
}
ransid::Event::Rect { x, y, w, h, color } => {
Self::rect(display, x * 8, y * 16, w * 8, h * 16, color.as_rgb());
for y2 in y..y + h {
changed.insert(y2);
}
}
ransid::Event::ScreenBuffer { .. } => (),
ransid::Event::Move {
from_x,
from_y,
to_x,
to_y,
w,
h,
} => {
let width = display.width;
let pixels = unsafe { &mut *display.offscreen };
for raw_y in 0..h {
let y = if from_y > to_y { raw_y } else { h - raw_y - 1 };
for pixel_y in 0..16 {
{
let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8;
let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8;
let len = w * 8;
if off_from + len <= pixels.len() && off_to + len <= pixels.len() {
unsafe {
let data_ptr = pixels.as_mut_ptr() as *mut u32;
ptr::copy(
data_ptr.offset(off_from as isize),
data_ptr.offset(off_to as isize),
len,
);
}
}
}
}
changed.insert(to_y + y);
}
}
ransid::Event::Resize { .. } => (),
ransid::Event::Title { .. } => (),
});
}
if self.console.state.cursor
&& self.console.state.x < self.console.state.w
&& self.console.state.y < self.console.state.h
{
let x = self.console.state.x;
let y = self.console.state.y;
Self::invert(&mut self.display, x * 8, y * 16, 8, 16);
self.changed.insert(y);
}
let width = self.display.width.try_into().unwrap();
for &change in self.changed.iter() {
self.display.sync_rect(SyncRect {
x: 0,
y: i32::try_from(change).unwrap() * 16,
w: width,
h: 16,
})?;
}
self.changed.clear();
syscall::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?;
Ok(buf.len())
}
}
-1
View File
@@ -10,7 +10,6 @@ unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(usize)]
pub enum VtMode {
Text = 0,
Graphic = 1,
Default = 2,
}
-1
View File
@@ -6,7 +6,6 @@ edition = "2018"
[dependencies]
orbclient = "0.3.27"
ransid = "0.4"
rusttype = { version = "0.2", optional = true }
redox_syscall = "0.4"
redox-daemon = "0.1"
-97
View File
@@ -1,97 +0,0 @@
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
Bitstream Vera Fonts Copyright
------------------------------
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute the
Font Software, including without limitation the rights to use, copy, merge,
publish, distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to the
following conditions:
The above copyright and trademark notices and this permission notice shall
be included in all copies of one or more of the Font Software typefaces.
The Font Software may be modified, altered, or added to, and in particular
the designs of glyphs or characters in the Fonts may be modified and
additional glyphs or characters may be added to the Fonts, only if the fonts
are renamed to names not containing either the words "Bitstream" or the word
"Vera".
This License becomes null and void to the extent applicable to Fonts or Font
Software that has been modified and is distributed under the "Bitstream
Vera" names.
The Font Software may be sold as part of a larger software package but no
copy of one or more of the Font Software typefaces may be sold by itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font Software
without prior written authorization from the Gnome Foundation or Bitstream
Inc., respectively. For further information, contact: fonts at gnome dot
org.
Arev Fonts Copyright
------------------------------
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and
associated documentation files (the "Font Software"), to reproduce
and distribute the modifications to the Bitstream Vera Font Software,
including without limitation the rights to use, copy, merge, publish,
distribute, and/or sell copies of the Font Software, and to permit
persons to whom the Font Software is furnished to do so, subject to
the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Tavmjong Bah" or the word "Arev".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Tavmjong Bah Arev" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the name of Tavmjong Bah shall not
be used in advertising or otherwise to promote the sale, use or other
dealings in this Font Software without prior written authorization
from Tavmjong Bah. For further information, contact: tavmjong @ free
. fr.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -274
View File
@@ -1,25 +1,7 @@
#[cfg(feature="rusttype")]
extern crate rusttype;
use std::alloc::{self, Layout};
use std::{cmp, ptr};
use std::ptr;
use std::ptr::NonNull;
#[cfg(feature="rusttype")]
use self::rusttype::{Font, FontCollection, Scale, point};
#[cfg(not(feature="rusttype"))]
use orbclient::FONT;
#[cfg(feature="rusttype")]
static FONT: &'static [u8] = include_bytes!("../res/DejaVuSansMono.ttf");
#[cfg(feature="rusttype")]
static FONT_BOLD: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Bold.ttf");
#[cfg(feature="rusttype")]
static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-BoldOblique.ttf");
#[cfg(feature="rusttype")]
static FONT_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Oblique.ttf");
pub struct OffscreenBuffer {
ptr: NonNull<[u32]>,
}
@@ -32,7 +14,7 @@ impl OffscreenBuffer {
}
#[inline]
fn new(len: usize) -> Self {
pub fn new(len: usize) -> Self {
let layout = Self::layout(len);
let ptr = unsafe { alloc::alloc_zeroed(layout) };
let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len);
@@ -57,257 +39,3 @@ impl std::ops::DerefMut for OffscreenBuffer {
unsafe { self.ptr.as_mut() }
}
}
/// A display
pub struct Display {
pub width: usize,
pub height: usize,
pub offscreen: OffscreenBuffer,
#[cfg(feature="rusttype")]
pub font: Font<'static>,
#[cfg(feature="rusttype")]
pub font_bold: Font<'static>,
#[cfg(feature="rusttype")]
pub font_bold_italic: Font<'static>,
#[cfg(feature="rusttype")]
pub font_italic: Font<'static>
}
impl Display {
#[cfg(not(feature="rusttype"))]
pub fn new(width: usize, height: usize) -> Display {
let size = width * height;
let offscreen = OffscreenBuffer::new(size);
Display {
width,
height,
offscreen,
}
}
#[cfg(feature="rusttype")]
pub fn new(width: usize, height: usize) -> Display {
let size = width * height;
let offscreen = OffscreenBuffer::new(size);
Display {
width,
height,
offscreen,
font: FontCollection::from_bytes(FONT).into_font().unwrap(),
font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(),
font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(),
font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap()
}
}
pub fn resize(&mut self, width: usize, height: usize) {
if width != self.width || height != self.height {
println!("Resize display to {}, {}", width, height);
let size = width * height;
let mut offscreen = OffscreenBuffer::new(size);
{
let mut old_ptr = self.offscreen.as_ptr();
let mut new_ptr = offscreen.as_mut_ptr();
for _y in 0..cmp::min(height, self.height) {
unsafe {
ptr::copy(
old_ptr as *const u8,
new_ptr as *mut u8,
cmp::min(width, self.width) * 4
);
if width > self.width {
ptr::write_bytes(
new_ptr.offset(self.width as isize),
0,
width - self.width
);
}
old_ptr = old_ptr.offset(self.width as isize);
new_ptr = new_ptr.offset(width as isize);
}
}
if height > self.height {
for _y in self.height..height {
unsafe {
ptr::write_bytes(new_ptr, 0, width);
new_ptr = new_ptr.offset(width as isize);
}
}
}
}
self.width = width;
self.height = height;
self.offscreen = offscreen;
} else {
println!("Display is already {}, {}", width, height);
}
}
/// Draw a rectangle
pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) {
let start_y = cmp::min(self.height, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width, x);
let len = cmp::min(self.width, x + w) - start_x;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
for i in 0..len {
unsafe {
*(offscreen_ptr as *mut u32).add(i) = color;
}
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Invert a rectangle
pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) {
let start_y = cmp::min(self.height, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width, x);
let len = cmp::min(self.width, x + w) - start_x;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let stride = self.width * 4;
let offset = y * stride + start_x * 4;
offscreen_ptr += offset;
let mut rows = end_y - start_y;
while rows > 0 {
let mut row_ptr = offscreen_ptr;
let mut cols = len;
while cols > 0 {
unsafe {
let color = *(row_ptr as *mut u32);
*(row_ptr as *mut u32) = !color;
}
row_ptr += 4;
cols -= 1;
}
offscreen_ptr += stride;
rows -= 1;
}
}
/// Draw a character
#[cfg(not(feature="rusttype"))]
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) {
if x + 8 <= self.width && y + 16 <= self.height {
let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4;
let font_i = 16 * (character as usize);
if font_i + 16 <= FONT.len() {
for row in 0..16 {
let row_data = FONT[font_i + row];
for col in 0..8 {
if (row_data >> (7 - col)) & 1 == 1 {
unsafe { *((dst + col * 4) as *mut u32) = color; }
}
}
dst += self.width * 4;
}
}
}
}
/// Draw a character
#[cfg(feature="rusttype")]
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, bold: bool, italic: bool) {
let width = self.width;
let height = self.height;
let offscreen = self.offscreen.as_mut_ptr() as usize;
let font = if bold && italic {
&self.font_bold_italic
} else if bold {
&self.font_bold
} else if italic {
&self.font_italic
} else {
&self.font
};
if let Some(glyph) = font.glyph(character){
let scale = Scale::uniform(16.0);
let v_metrics = font.v_metrics(scale);
let point = point(0.0, v_metrics.ascent);
let glyph = glyph.scaled(scale).positioned(point);
if let Some(bb) = glyph.pixel_bounding_box() {
glyph.draw(|off_x, off_y, v| {
let off_x = x + (off_x as i32 + bb.min.x) as usize;
let off_y = y + (off_y as i32 + bb.min.y) as usize;
// There's still a possibility that the glyph clips the boundaries of the bitmap
if off_x < width && off_y < height {
if v > 0.0 {
let f_a = (v * 255.0) as u32;
let f_r = (((color >> 16) & 0xFF) * f_a)/255;
let f_g = (((color >> 8) & 0xFF) * f_a)/255;
let f_b = ((color & 0xFF) * f_a)/255;
let offscreen_ptr = (offscreen + (off_y * width + off_x) * 4) as *mut u32;
let bg = unsafe { *offscreen_ptr };
let b_a = 255 - f_a;
let b_r = (((bg >> 16) & 0xFF) * b_a)/255;
let b_g = (((bg >> 8) & 0xFF) * b_a)/255;
let b_b = ((bg & 0xFF) * b_a)/255;
let c = ((f_r + b_r) << 16) | ((f_g + b_g) << 8) | (f_b + b_b);
unsafe { *offscreen_ptr = c; }
}
}
});
}
}
}
/// Copy from offscreen to onscreen
pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize, onscreen: &mut [u32], stride: usize) {
let start_y = cmp::min(self.height, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width, x);
let len = (cmp::min(self.width, x + w) - start_x) * 4;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = onscreen.as_mut_ptr() as usize;
offscreen_ptr += (y * self.width + start_x) * 4;
onscreen_ptr += (y * stride + start_x) * 4;
let mut rows = end_y - start_y;
while rows > 0 {
unsafe {
ptr::copy(
offscreen_ptr as *const u8,
onscreen_ptr as *mut u8,
len
);
}
offscreen_ptr += self.width * 4;
onscreen_ptr += stride * 4;
rows -= 1;
}
}
}
+7 -13
View File
@@ -12,22 +12,16 @@ use crate::{
scheme::{DisplayScheme, HandleKind}
};
pub mod display;
pub mod framebuffer;
pub mod scheme;
pub mod screen;
mod display;
mod framebuffer;
mod scheme;
mod screen;
fn main() {
let mut spec = Vec::new();
for arg in env::args().skip(1) {
if arg == "T" {
spec.push(false);
} else if arg == "G" {
spec.push(true);
} else {
eprintln!("vesad: unknown screen type: {}", arg);
}
for _ in env::args().skip(1) {
spec.push(());
}
let width = usize::from_str_radix(
@@ -89,7 +83,7 @@ fn main() {
redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)).expect("failed to create daemon");
}
fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>, spec: &[bool]) -> ! {
fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>, spec: &[()]) -> ! {
let mut socket = File::create(":display.vesa").expect("vesad: failed to create display scheme");
let mut scheme = DisplayScheme::new(framebuffers, &spec);
+22 -67
View File
@@ -1,14 +1,9 @@
use std::collections::BTreeMap;
use std::{mem, ptr, slice, str};
use orbclient::{Event, EventOption};
use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, Packet, KSMSG_MMAP_PREP, KSMSG_MMAP, MapFlags, ESKMSG, SKMSG_PROVIDE_MMAP};
use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, MapFlags};
use crate::{
display::Display,
framebuffer::FrameBuffer,
screen::{Screen, GraphicScreen, TextScreen},
};
use crate::{framebuffer::FrameBuffer, screen::GraphicScreen};
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)]
pub struct VtIndex(usize);
@@ -34,7 +29,7 @@ pub struct DisplayScheme {
framebuffers: Vec<FrameBuffer>,
onscreens: Vec<&'static mut [u32]>,
active: VtIndex,
pub vts: BTreeMap<VtIndex, BTreeMap<ScreenIndex, Box<dyn Screen>>>,
pub vts: BTreeMap<VtIndex, BTreeMap<ScreenIndex, GraphicScreen>>,
next_id: usize,
pub handles: BTreeMap<usize, Handle>,
pub inputd_handle: inputd::Handle,
@@ -42,7 +37,7 @@ pub struct DisplayScheme {
}
impl DisplayScheme {
pub fn new(mut framebuffers: Vec<FrameBuffer>, spec: &[bool]) -> DisplayScheme {
pub fn new(mut framebuffers: Vec<FrameBuffer>, spec: &[()]) -> DisplayScheme {
let mut inputd_handle = inputd::Handle::new("vesa").unwrap();
let mut onscreens = Vec::new();
@@ -52,17 +47,13 @@ impl DisplayScheme {
});
}
let mut vts = BTreeMap::<VtIndex, BTreeMap<ScreenIndex, Box<dyn Screen>>>::new();
let mut vts = BTreeMap::<VtIndex, BTreeMap<ScreenIndex, GraphicScreen>>::new();
for &vt_type in spec.iter() {
let mut screens = BTreeMap::<ScreenIndex, Box<dyn Screen>>::new();
for &() in spec.iter() {
let mut screens = BTreeMap::<ScreenIndex, GraphicScreen>::new();
for fb_i in 0..framebuffers.len() {
let fb = &framebuffers[fb_i];
screens.insert(ScreenIndex(fb_i), if vt_type {
Box::new(GraphicScreen::new(Display::new(fb.width, fb.height)))
} else {
Box::new(TextScreen::new(Display::new(fb.width, fb.height)))
});
screens.insert(ScreenIndex(fb_i), GraphicScreen::new(fb.width, fb.height));
}
vts.insert(VtIndex(inputd_handle.register().unwrap()), screens);
}
@@ -166,7 +157,7 @@ impl SchemeMut for DisplayScheme {
vt_screen.next().unwrap_or("").parse::<usize>().unwrap_or(0)
);
if let Some(screens) = self.vts.get_mut(&vt_i) {
if let Some(screen) = screens.get_mut(&screen_i) {
if screens.get_mut(&screen_i).is_some() {
let id = self.next_id;
self.next_id += 1;
@@ -214,22 +205,6 @@ impl SchemeMut for DisplayScheme {
}
}
/*
fn fmap(&mut self, id: usize, map: &Map) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let HandleKind::Screen(vt_i, screen_i) = handle.kind {
if let Some(screens) = self.vts.get(&vt_i) {
if let Some(screen) = screens.get(&screen_i) {
return screen.map(map.offset, map.size);
}
}
}
Err(Error::new(EBADF))
}
*/
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
@@ -240,7 +215,7 @@ impl SchemeMut for DisplayScheme {
},
HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get(&vt_i) {
if let Some(screen) = screens.get(&screen_i) {
format!("display:{}.{}/{}/{}", vt_i.0, screen_i.0, screen.width(), screen.height())
format!("display:{}.{}/{}/{}", vt_i.0, screen_i.0, screen.width, screen.height)
} else {
return Err(Error::new(EBADF));
}
@@ -299,30 +274,20 @@ impl SchemeMut for DisplayScheme {
match handle.kind {
HandleKind::Input => {
use inputd::{Cmd as DisplayCommand, VtMode};
use inputd::Cmd as DisplayCommand;
let command = inputd::parse_command(buf).unwrap();
match command {
DisplayCommand::Activate { vt, mode } => {
DisplayCommand::Activate { vt, mode: _ } => {
let vt_i = VtIndex(vt);
if let Some(screens) = self.vts.get_mut(&vt_i) {
for (screen_i, screen) in screens.iter_mut() {
match mode {
VtMode::Graphic => {
*screen = Box::new(GraphicScreen::new(Display::new(screen.width(), screen.height())));
}
VtMode::Default => {
screen.redraw(
self.onscreens[screen_i.0],
self.framebuffers[screen_i.0].stride
);
}
VtMode::Text => todo!()
}
screen.redraw(
self.onscreens[screen_i.0],
self.framebuffers[screen_i.0].stride
);
}
}
@@ -359,20 +324,6 @@ impl SchemeMut for DisplayScheme {
}
}
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result<isize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let HandleKind::Screen(vt_i, screen_i) = handle.kind {
if let Some(screens) = self.vts.get_mut(&vt_i) {
if let Some(screen) = screens.get_mut(&screen_i) {
return screen.seek(pos, whence).map(|pos| pos as isize);
}
}
}
Err(Error::new(EBADF))
}
fn close(&mut self, id: usize) -> Result<usize> {
self.handles.remove(&id).ok_or(Error::new(EBADF))?;
Ok(0)
@@ -383,7 +334,11 @@ impl SchemeMut for DisplayScheme {
if let HandleKind::Screen(vt_i, screen_i) = handle.kind {
if let Some(screens) = self.vts.get(&vt_i) {
if let Some(screen) = screens.get(&screen_i) {
return screen.map(off as usize, size);
if off as usize + size <= screen.offscreen.len() * 4 {
return Ok(screen.offscreen.as_ptr() as usize + off as usize);
} else {
return Err(Error::new(EINVAL));
}
}
}
}
+170
View File
@@ -0,0 +1,170 @@
use std::collections::VecDeque;
use std::convert::TryInto;
use std::{mem, slice, cmp, ptr};
use orbclient::{Event, ResizeEvent};
use syscall::error::*;
use crate::display::OffscreenBuffer;
// Keep synced with orbital
#[derive(Clone, Copy)]
#[repr(packed)]
pub struct SyncRect {
pub x: i32,
pub y: i32,
pub w: i32,
pub h: i32,
}
pub struct GraphicScreen {
pub width: usize,
pub height: usize,
pub offscreen: OffscreenBuffer,
pub input: VecDeque<Event>,
pub sync_rects: Vec<SyncRect>,
}
impl GraphicScreen {
pub fn new(width: usize, height: usize) -> GraphicScreen {
GraphicScreen {
width,
height,
offscreen: OffscreenBuffer::new(width * height),
input: VecDeque::new(),
sync_rects: Vec::new(),
}
}
}
impl GraphicScreen {
pub fn resize(&mut self, width: usize, height: usize) {
//TODO: Fix issue with mapped screens
if width != self.width || height != self.height {
println!("Resize display to {}, {}", width, height);
let size = width * height;
let mut offscreen = OffscreenBuffer::new(size);
let mut old_ptr = self.offscreen.as_ptr();
let mut new_ptr = offscreen.as_mut_ptr();
for _y in 0..cmp::min(height, self.height) {
unsafe {
ptr::copy(
old_ptr as *const u8,
new_ptr as *mut u8,
cmp::min(width, self.width) * 4
);
if width > self.width {
ptr::write_bytes(
new_ptr.offset(self.width as isize),
0,
width - self.width
);
}
old_ptr = old_ptr.offset(self.width as isize);
new_ptr = new_ptr.offset(width as isize);
}
}
if height > self.height {
for _y in self.height..height {
unsafe {
ptr::write_bytes(new_ptr, 0, width);
new_ptr = new_ptr.offset(width as isize);
}
}
}
self.width = width;
self.height = height;
self.offscreen = offscreen;
} else {
println!("Display is already {}, {}", width, height);
};
self.input.push_back(ResizeEvent {
width: width as u32,
height: height as u32,
}.to_event());
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut i = 0;
let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::<Event>()) };
while i < event_buf.len() && ! self.input.is_empty() {
event_buf[i] = self.input.pop_front().unwrap();
i += 1;
}
Ok(i * mem::size_of::<Event>())
}
pub fn can_read(&self) -> Option<usize> {
if self.input.is_empty() {
None
} else {
Some(self.input.len() * mem::size_of::<Event>())
}
}
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
let sync_rects = unsafe {
slice::from_raw_parts(
buf.as_ptr() as *const SyncRect,
buf.len() / mem::size_of::<SyncRect>()
)
};
self.sync_rects.extend_from_slice(sync_rects);
Ok(sync_rects.len() * mem::size_of::<SyncRect>())
}
pub fn sync(&mut self, onscreen: &mut [u32], stride: usize) {
for sync_rect in self.sync_rects.drain(..) {
let x = sync_rect.x.try_into().unwrap_or(0);
let y = sync_rect.y.try_into().unwrap_or(0);
let w = sync_rect.w.try_into().unwrap_or(0);
let h = sync_rect.h.try_into().unwrap_or(0);
let start_y = cmp::min(self.height, y);
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width, x);
let len = (cmp::min(self.width, x + w) - start_x) * 4;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = onscreen.as_mut_ptr() as usize;
offscreen_ptr += (y * self.width + start_x) * 4;
onscreen_ptr += (y * stride + start_x) * 4;
let mut rows = end_y - start_y;
while rows > 0 {
unsafe {
ptr::copy(
offscreen_ptr as *const u8,
onscreen_ptr as *mut u8,
len
);
}
offscreen_ptr += self.width * 4;
onscreen_ptr += stride * 4;
rows -= 1;
};
}
}
pub fn redraw(&mut self, onscreen: &mut [u32], stride: usize) {
let width = self.width.try_into().unwrap();
let height = self.height.try_into().unwrap();
self.sync_rects.push(SyncRect { x: 0, y: 0, w: width, h: height });
self.sync(onscreen, stride);
}
}
-123
View File
@@ -1,123 +0,0 @@
use std::collections::VecDeque;
use std::convert::TryInto;
use std::{mem, slice};
use orbclient::{Event, ResizeEvent};
use syscall::error::*;
use crate::display::Display;
use crate::screen::Screen;
// Keep synced with orbital
#[derive(Clone, Copy)]
#[repr(packed)]
struct SyncRect {
x: i32,
y: i32,
w: i32,
h: i32,
}
pub struct GraphicScreen {
pub display: Display,
pub input: VecDeque<Event>,
sync_rects: Vec<SyncRect>,
}
impl GraphicScreen {
pub fn new(display: Display) -> GraphicScreen {
GraphicScreen {
display,
input: VecDeque::new(),
sync_rects: Vec::new(),
}
}
}
impl Screen for GraphicScreen {
fn width(&self) -> usize {
self.display.width
}
fn height(&self) -> usize {
self.display.height
}
fn resize(&mut self, width: usize, height: usize) {
//TODO: Fix issue with mapped screens
self.display.resize(width, height);
self.input.push_back(ResizeEvent {
width: width as u32,
height: height as u32,
}.to_event());
}
fn map(&self, offset: usize, size: usize) -> Result<usize> {
if offset + size <= self.display.offscreen.len() * 4 {
Ok(self.display.offscreen.as_ptr() as usize + offset)
} else {
Err(Error::new(EINVAL))
}
}
fn input(&mut self, event: &Event) {
self.input.push_back(*event);
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut i = 0;
let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::<Event>()) };
while i < event_buf.len() && ! self.input.is_empty() {
event_buf[i] = self.input.pop_front().unwrap();
i += 1;
}
Ok(i * mem::size_of::<Event>())
}
fn can_read(&self) -> Option<usize> {
if self.input.is_empty() {
None
} else {
Some(self.input.len() * mem::size_of::<Event>())
}
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let sync_rects = unsafe {
slice::from_raw_parts(
buf.as_ptr() as *const SyncRect,
buf.len() / mem::size_of::<SyncRect>()
)
};
self.sync_rects.extend_from_slice(sync_rects);
Ok(sync_rects.len() * mem::size_of::<SyncRect>())
}
fn seek(&mut self, _pos: isize, _whence: usize) -> Result<usize> {
Ok(0)
}
fn sync(&mut self, onscreen: &mut [u32], stride: usize) {
for sync_rect in self.sync_rects.drain(..) {
self.display.sync(
sync_rect.x.try_into().unwrap_or(0),
sync_rect.y.try_into().unwrap_or(0),
sync_rect.w.try_into().unwrap_or(0),
sync_rect.h.try_into().unwrap_or(0),
onscreen,
stride,
);
}
}
fn redraw(&mut self, onscreen: &mut [u32], stride: usize) {
let width = self.display.width;
let height = self.display.height;
self.display.sync(0, 0, width, height, onscreen, stride);
}
}
-32
View File
@@ -1,32 +0,0 @@
pub use self::graphic::GraphicScreen;
pub use self::text::TextScreen;
use orbclient::Event;
use syscall::Result;
mod graphic;
mod text;
pub trait Screen {
fn width(&self) -> usize;
fn height(&self) -> usize;
fn resize(&mut self, width: usize, height: usize);
fn map(&self, offset: usize, size: usize) -> Result<usize>;
fn input(&mut self, event: &Event);
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
fn can_read(&self) -> Option<usize>;
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn seek(&mut self, pos: isize, whence: usize) -> Result<usize>;
fn sync(&mut self, onscreen: &mut [u32], stride: usize);
fn redraw(&mut self, onscreen: &mut [u32], stride: usize);
}
-226
View File
@@ -1,226 +0,0 @@
extern crate ransid;
use std::collections::{BTreeSet, VecDeque};
use std::ptr;
use orbclient::{Event, EventOption};
use syscall::error::*;
use crate::display::Display;
use crate::screen::Screen;
pub struct TextScreen {
pub console: ransid::Console,
pub display: Display,
pub changed: BTreeSet<usize>,
pub ctrl: bool,
pub input: VecDeque<u8>,
}
impl TextScreen {
pub fn new(display: Display) -> TextScreen {
TextScreen {
console: ransid::Console::new(display.width/8, display.height/16),
display: display,
changed: BTreeSet::new(),
ctrl: false,
input: VecDeque::new(),
}
}
}
impl Screen for TextScreen {
fn width(&self) -> usize {
self.console.state.w
}
fn height(&self) -> usize {
self.console.state.h
}
fn resize(&mut self, width: usize, height: usize) {
self.display.resize(width, height);
self.console.state.w = width / 8;
self.console.state.h = height / 16;
}
fn map(&self, _offset: usize, _size: usize) -> Result<usize> {
Err(Error::new(EBADF))
}
fn input(&mut self, event: &Event) {
let mut buf = vec![];
match event.to_option() {
EventOption::Key(key_event) => {
if key_event.scancode == 0x1D {
self.ctrl = key_event.pressed;
} else if key_event.pressed {
match key_event.scancode {
0x0E => { // Backspace
buf.extend_from_slice(b"\x7F");
},
0x47 => { // Home
buf.extend_from_slice(b"\x1B[H");
},
0x48 => { // Up
buf.extend_from_slice(b"\x1B[A");
},
0x49 => { // Page up
buf.extend_from_slice(b"\x1B[5~");
},
0x4B => { // Left
buf.extend_from_slice(b"\x1B[D");
},
0x4D => { // Right
buf.extend_from_slice(b"\x1B[C");
},
0x4F => { // End
buf.extend_from_slice(b"\x1B[F");
},
0x50 => { // Down
buf.extend_from_slice(b"\x1B[B");
},
0x51 => { // Page down
buf.extend_from_slice(b"\x1B[6~");
},
0x52 => { // Insert
buf.extend_from_slice(b"\x1B[2~");
},
0x53 => { // Delete
buf.extend_from_slice(b"\x1B[3~");
},
_ => {
let c = match key_event.character {
c @ 'A' ..= 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
c @ 'a' ..= 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
c => c
};
if c != '\0' {
let mut b = [0; 4];
buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes());
}
}
}
}
},
_ => () //TODO: Mouse in terminal
}
for &b in buf.iter() {
self.input.push_back(b);
}
}
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut i = 0;
while i < buf.len() && ! self.input.is_empty() {
buf[i] = self.input.pop_front().unwrap();
i += 1;
}
Ok(i)
}
fn can_read(&self) -> Option<usize> {
if self.input.is_empty() {
None
} else {
Some(self.input.len())
}
}
fn write(&mut self, buf: &[u8]) -> Result<usize> {
if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h {
let x = self.console.state.x;
let y = self.console.state.y;
self.display.invert(x * 8, y * 16, 8, 16);
self.changed.insert(y);
}
{
let display = &mut self.display;
let changed = &mut self.changed;
let input = &mut self.input;
self.console.write(buf, |event| {
match event {
ransid::Event::Char { x, y, c, color, bold, .. } => {
display.char(x * 8, y * 16, c, color.as_rgb(), bold, false);
changed.insert(y);
},
ransid::Event::Input { data } => {
input.extend(data);
},
ransid::Event::Rect { x, y, w, h, color } => {
display.rect(x * 8, y * 16, w * 8, h * 16, color.as_rgb());
for y2 in y..y + h {
changed.insert(y2);
}
},
ransid::Event::ScreenBuffer { .. } => (),
ransid::Event::Move {from_x, from_y, to_x, to_y, w, h } => {
let width = display.width;
let pixels = &mut display.offscreen;
for raw_y in 0..h {
let y = if from_y > to_y {
raw_y
} else {
h - raw_y - 1
};
for pixel_y in 0..16 {
{
let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8;
let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8;
let len = w * 8;
if off_from + len <= pixels.len() && off_to + len <= pixels.len() {
unsafe {
let data_ptr = pixels.as_mut_ptr() as *mut u32;
ptr::copy(data_ptr.offset(off_from as isize), data_ptr.offset(off_to as isize), len);
}
}
}
}
changed.insert(to_y + y);
}
},
ransid::Event::Resize { .. } => (),
ransid::Event::Title { .. } => ()
}
});
}
if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h {
let x = self.console.state.x;
let y = self.console.state.y;
self.display.invert(x * 8, y * 16, 8, 16);
self.changed.insert(y);
}
Ok(buf.len())
}
fn seek(&mut self, _pos: isize, _whence: usize) -> Result<usize> {
Ok(0)
}
fn sync(&mut self, onscreen: &mut [u32], stride: usize) {
let width = self.display.width;
for change in self.changed.iter() {
self.display.sync(0, change * 16, width, 16, onscreen, stride);
}
self.changed.clear();
}
fn redraw(&mut self, onscreen: &mut [u32], stride: usize) {
let width = self.display.width;
let height = self.display.height;
self.display.sync(0, 0, width, height, onscreen, stride);
self.changed.clear();
}
}