extern crate syscall;
use std::{env, mem, slice, thread};
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, RawFd};
use color::Color;
use event::{Event, EVENT_RESIZE};
use renderer::Renderer;
use WindowFlag;
pub fn get_display_size() -> Result<(u32, u32), String> {
let display_path = try!(env::var("DISPLAY").or(Err("DISPLAY not set")));
match File::open(&display_path) {
Ok(display) => {
let mut buf: [u8; 4096] = [0; 4096];
let count = syscall::fpath(display.as_raw_fd() as usize, &mut buf).map_err(|err| format!("{}", err))?;
let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
let res = path.split(":").nth(1).unwrap_or("");
let width = res.split("/").nth(1).unwrap_or("").parse::<u32>().unwrap_or(0);
let height = res.split("/").nth(2).unwrap_or("").parse::<u32>().unwrap_or(0);
Ok((width, height))
},
Err(err) => Err(format!("{}", err))
}
}
pub struct Window {
x: i32,
y: i32,
w: u32,
h: u32,
t: String,
async: bool,
resizable: bool,
file: File,
data: &'static mut [Color],
}
impl Renderer for Window {
fn width(&self) -> u32 {
self.w
}
fn height(&self) -> u32 {
self.h
}
fn data(&self) -> &[Color] {
&self.data
}
fn data_mut(&mut self) -> &mut [Color] {
&mut self.data
}
fn sync(&mut self) -> bool {
self.file.sync_data().is_ok()
}
}
impl Window {
pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Self> {
Window::new_flags(x, y, w, h, title, &[])
}
pub fn new_flags(x: i32, y: i32, w: u32, h: u32, title: &str, flags: &[WindowFlag]) -> Option<Self> {
let mut async = false;
let mut resizable = false;
let mut unclosable = false;
for &flag in flags.iter() {
match flag {
WindowFlag::Async => async = true,
WindowFlag::Resizable => resizable = true,
WindowFlag::Unclosable => unclosable = true
}
}
if let Ok(file) = File::open(&format!(
"orbital:{}{}{}/{}/{}/{}/{}/{}",
if async { "a" } else { "" },
if resizable { "r" } else { "" },
if unclosable { "u" } else { "" },
x, y, w, h, title
)) {
if let Ok(address) = unsafe { syscall::fmap(file.as_raw_fd(), 0, (w * h * 4) as usize) } {
Some(Window {
x: x,
y: y,
w: w,
h: h,
t: title.to_string(),
async: async,
resizable: resizable,
file: file,
data: unsafe { slice::from_raw_parts_mut(address as *mut Color, (w * h) as usize) },
})
} else {
None
}
} else {
None
}
}
pub fn sync_path(&mut self) {
let mut buf: [u8; 4096] = [0; 4096];
if let Ok(count) = syscall::fpath(self.file.as_raw_fd() as usize, &mut buf) {
let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) };
let mut parts = path.split('/').skip(1);
if let Some(x) = parts.next() {
self.x = x.parse::<i32>().unwrap_or(0);
}
if let Some(y) = parts.next() {
self.y = y.parse::<i32>().unwrap_or(0);
}
if let Some(w) = parts.next() {
self.w = w.parse::<u32>().unwrap_or(0);
}
if let Some(h) = parts.next() {
self.h = h.parse::<u32>().unwrap_or(0);
}
}
}
pub fn x(&self) -> i32 {
self.x
}
pub fn y(&self) -> i32 {
self.y
}
pub fn title(&self) -> String {
self.t.clone()
}
pub fn set_pos(&mut self, x: i32, y: i32) {
let _ = self.file.write(&format!("P,{},{}", x, y).as_bytes());
self.sync_path();
}
pub fn set_size(&mut self, width: u32, height: u32) {
unsafe {
syscall::funmap(self.data.as_ptr() as usize).expect("orbclient: failed to unmap memory in resize");
}
let _ = self.file.write(&format!("S,{},{}", width, height).as_bytes());
self.sync_path();
unsafe {
let address = syscall::fmap(self.file.as_raw_fd(), 0, (self.w * self.h * 4) as usize).expect("orbclient: failed to map memory in resize");
self.data = slice::from_raw_parts_mut(address as *mut Color, (self.w * self.h) as usize);
}
}
pub fn set_title(&mut self, title: &str) {
let _ = self.file.write(&format!("T,{}", title).as_bytes());
self.sync_path();
}
pub fn events(&mut self) -> EventIter {
let mut iter = EventIter {
events: [Event::new(); 128],
i: 0,
count: 0,
};
'blocking: loop {
match self.file.read(unsafe {
slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
}){
Ok(0) => if ! self.async {
thread::yield_now();
} else {
break 'blocking;
},
Ok(count) => {
iter.count = count/mem::size_of::<Event>();
if self.resizable {
let mut resize = None;
for i in 0..iter.count {
let event = &iter.events[i];
if event.code == EVENT_RESIZE {
resize = Some((event.a as u32, event.b as u32));
}
}
if let Some((w, h)) = resize {
self.set_size(w, h);
}
}
break 'blocking;
},
Err(_) => break 'blocking,
}
}
iter
}
}
impl Drop for Window {
fn drop(&mut self) {
let _ = unsafe { syscall::funmap(self.data.as_ptr() as usize) };
}
}
impl AsRawFd for Window {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
pub struct EventIter {
events: [Event; 128],
i: usize,
count: usize,
}
impl Iterator for EventIter {
type Item = Event;
fn next(&mut self) -> Option<Event> {
if self.i < self.count {
if let Some(event) = self.events.get(self.i) {
self.i += 1;
Some(*event)
} else {
None
}
} else {
None
}
}
}