feat(display): windows: full-screen, F1 cycles, OS bar (names, front, user); canvas-only (display-owned buffers, 4 max, reused); launchers OPEN (pm per app, terminal own), window caps minted by display; FORGET on launcher death via init courier; raster crate (font, chunked text); F-keys in input; terminal+snake on canvas; REDRAW gone
This commit is contained in:
@@ -4,57 +4,40 @@
|
||||
|
||||
extern crate libkos;
|
||||
|
||||
use libkos::display::Canvas;
|
||||
use libkos::syscall;
|
||||
use port_framebuffer::Framebuffer;
|
||||
use snake::game::{Direction, GameState, Snake};
|
||||
use snake::renderer::{self, RenderCommand};
|
||||
use types::bounded::CapSlot;
|
||||
use types::display::{Color, Dimension, ScreenCoord};
|
||||
use types::time::Ticks;
|
||||
use libkos::syscall;
|
||||
use server_framework::Encode;
|
||||
use display_server::protocol::DisplayRequest;
|
||||
|
||||
/// Steps a second; QEMU virt's timebase is 10 MHz.
|
||||
const STEPS_PER_SECOND: u64 = 8;
|
||||
const TICK_DELAY: u64 = 10_000_000 / STEPS_PER_SECOND;
|
||||
const MAX_RENDER_CMDS: usize = 140;
|
||||
|
||||
/// The display server, which the shell hands over because snake's manifest
|
||||
/// asks for it. Input comes through it too, while snake has focus.
|
||||
fn display_ep() -> CapSlot {
|
||||
libkos::start::display().unwrap_or(CapSlot::const_new(0))
|
||||
}
|
||||
|
||||
fn display_send(req: &DisplayRequest) {
|
||||
let _ = syscall::request(display_ep(), req.encode());
|
||||
}
|
||||
|
||||
fn draw_rect(x: u16, y: u16, w: u16, h: u16, color: u32) {
|
||||
display_send(&DisplayRequest::DrawRect {
|
||||
x: ScreenCoord::new(x),
|
||||
y: ScreenCoord::new(y),
|
||||
w: Dimension::new(w),
|
||||
h: Dimension::new(h),
|
||||
color: Color::from_raw(color),
|
||||
});
|
||||
}
|
||||
|
||||
fn flush() {
|
||||
display_send(&DisplayRequest::Flush);
|
||||
fn draw_rect(canvas: &mut Canvas, x: u16, y: u16, w: u16, h: u16, color: u32) {
|
||||
canvas.fill_rect(ScreenCoord::new(x), ScreenCoord::new(y), Dimension::new(w), Dimension::new(h), Color::from_raw(color));
|
||||
}
|
||||
|
||||
libkos::entry!(main);
|
||||
|
||||
fn main() {
|
||||
if libkos::start::display().is_none() {
|
||||
libkos::println!("snake: needs the display (see /bin/snake.manifest)");
|
||||
// Its window, which the permission manager opened because snake's
|
||||
// manifest asks for the display. Input comes through it too.
|
||||
let Some(mut canvas) = libkos::start::display().and_then(Canvas::attach) else {
|
||||
libkos::println!("snake: needs the display (see its manifest)");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let Ok(alarm) = syscall::create_notification() else {
|
||||
libkos::println!("snake: no timer");
|
||||
return;
|
||||
};
|
||||
// Takes focus; keys are polled every tick, the signal only wakes it.
|
||||
let _ = libkos::display::subscribe(display_ep(), alarm, types::badge::Badge::new(1 << 1));
|
||||
let window = canvas.window();
|
||||
let _ = libkos::display::subscribe(window, alarm, types::badge::Badge::new(1 << 1));
|
||||
let mut clock = Clock::new(alarm);
|
||||
let mut snake = Snake::new();
|
||||
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_CMDS];
|
||||
@@ -62,24 +45,24 @@ fn main() {
|
||||
loop {
|
||||
let count = renderer::render(&snake, &mut commands);
|
||||
for cmd in &commands[..count] {
|
||||
draw_rect(cmd.x, cmd.y, cmd.w, cmd.h, cmd.color);
|
||||
draw_rect(&mut canvas, cmd.x, cmd.y, cmd.w, cmd.h, cmd.color);
|
||||
}
|
||||
flush();
|
||||
canvas.flush();
|
||||
|
||||
if snake.state() == GameState::GameOver {
|
||||
let gw = renderer::grid_pixel_width();
|
||||
let gh = renderer::grid_pixel_height();
|
||||
draw_rect(gw / 2 - 60, gh / 2 - 12, 120, 24, 0xFFCC0000);
|
||||
flush();
|
||||
draw_rect(&mut canvas, gw / 2 - 60, gh / 2 - 12, 120, 24, 0xFFCC0000);
|
||||
canvas.flush();
|
||||
// Any key leaves.
|
||||
while next_input() == Input::None {
|
||||
while next_input(window) == Input::None {
|
||||
clock.wait_tick();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
clock.wait_tick();
|
||||
if handle_input(&mut snake) == Input::Quit {
|
||||
if handle_input(window, &mut snake) == Input::Quit {
|
||||
return;
|
||||
}
|
||||
snake.tick();
|
||||
@@ -95,8 +78,8 @@ enum Input {
|
||||
}
|
||||
|
||||
/// The next key, if one is waiting: q or Escape quits.
|
||||
fn next_input() -> Input {
|
||||
let Ok([tag, kind, ch, _]) = syscall::request(display_ep(), [types::display::input::POLL, 0, 0, 0]) else {
|
||||
fn next_input(window: CapSlot) -> Input {
|
||||
let Ok([tag, kind, ch, _]) = syscall::request(window, [types::display::window::POLL, 0, 0, 0]) else {
|
||||
return Input::None;
|
||||
};
|
||||
if tag == 0 {
|
||||
@@ -117,9 +100,9 @@ fn next_input() -> Input {
|
||||
}
|
||||
|
||||
/// Drains the pending keys, applying each turn; reports a quit.
|
||||
fn handle_input(snake: &mut Snake) -> Input {
|
||||
fn handle_input(window: CapSlot, snake: &mut Snake) -> Input {
|
||||
loop {
|
||||
match next_input() {
|
||||
match next_input(window) {
|
||||
Input::None => return Input::None,
|
||||
Input::Quit => return Input::Quit,
|
||||
Input::Turn(d) => snake.set_direction(d),
|
||||
|
||||
Reference in New Issue
Block a user