Skip to content

Commit ea83d14

Browse files
committed
Add slideshow mode to 'show' command
1 parent ca24815 commit ea83d14

File tree

2 files changed

+136
-18
lines changed

2 files changed

+136
-18
lines changed

crates/kernel/scripts/run-usb.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse
66
-device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22" \
77
"$(dirname "$0")/run.sh"
88

9+
#QEMU_DISPLAY=${QEMU_DISPLAY-"default"} QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse" "$(dirname "$0")/run.sh"
10+
#QEMU_DISPLAY=${QEMU_DISPLAY-"default"} QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh"
911
# QEMU_DISPLAY=${QEMU_DISPLAY-"default"} QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev tap,id=net0,ifname=tap0,script=no,downscript=no -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh"
1012

1113
# QEMU_DISPLAY=${QEMU_DISPLAY-"default"} QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev bridge,id=net0,br=br0 -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh"

crates/show/src/main.rs

Lines changed: 134 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ extern crate display_client;
77
#[macro_use]
88
extern crate ulib;
99

10+
use alloc::borrow::ToOwned;
11+
use alloc::string::String;
12+
use alloc::vec::Vec;
1013
use display_client::proto;
1114

1215
use ulib::sys::FileDesc;
@@ -32,6 +35,76 @@ fn read_all(fd: FileDesc) -> alloc::vec::Vec<u8> {
3235
out
3336
}
3437

38+
fn load_image(file: u32) -> (usize, usize, Vec<u32>) {
39+
let img = read_all(file);
40+
let (header, data) = gfx::format::qoi::read_qoi_header(&img).unwrap();
41+
let width = header.width as usize;
42+
let height = header.height as usize;
43+
let mut output = alloc::vec![0u32; width * height];
44+
gfx::format::qoi::decode_qoi(&header, data, &mut output, width);
45+
46+
(width, height, output)
47+
}
48+
49+
fn list_dir(dir: u32) -> Vec<String> {
50+
let mut cookie = 0;
51+
let mut data_backing = [0u64; 8192 / 8];
52+
let data = cast_slice(&mut data_backing);
53+
54+
fn cast_slice<'a>(s: &'a mut [u64]) -> &'a mut [u8] {
55+
unsafe {
56+
core::slice::from_raw_parts_mut(s.as_mut_ptr().cast::<u8>(), s.len() * size_of::<u64>())
57+
}
58+
}
59+
60+
#[repr(C)]
61+
#[derive(Copy, Clone, Debug)]
62+
pub struct DirEntry {
63+
pub inode: u64,
64+
pub next_entry_cookie: u64,
65+
pub rec_len: u16,
66+
pub name_len: u16,
67+
pub file_type: u8,
68+
pub name: [u8; 3],
69+
// Name is an arbitrary size array; the record is always padded with
70+
// 0 bytes such that rec_len is a multiple of 8 bytes.
71+
}
72+
73+
let mut filenames = Vec::new();
74+
75+
'outer: loop {
76+
match ulib::sys::pread(dir, data, cookie) {
77+
Err(e) => {
78+
println!("Error reading dir: {e}");
79+
ulib::sys::exit(1);
80+
}
81+
Ok(0) => break,
82+
Ok(len) => {
83+
let mut i = 0;
84+
while i < len as usize {
85+
let slice = &data[i..];
86+
assert!(slice.len() >= size_of::<DirEntry>());
87+
let entry = unsafe { *slice.as_ptr().cast::<DirEntry>() };
88+
89+
let name_off = core::mem::offset_of!(DirEntry, name);
90+
let name = &slice[name_off..][..entry.name_len as usize];
91+
92+
let name = core::str::from_utf8(name).unwrap();
93+
filenames.push(name.to_owned());
94+
95+
i += entry.rec_len as usize;
96+
cookie = entry.next_entry_cookie;
97+
}
98+
if cookie == 0 {
99+
break 'outer;
100+
}
101+
}
102+
}
103+
}
104+
105+
filenames
106+
}
107+
35108
#[no_mangle]
36109
fn main(argc: usize, argv: *const *const u8) {
37110
let argv_array = unsafe { core::slice::from_raw_parts(argv, argc) };
@@ -44,26 +117,35 @@ fn main(argc: usize, argv: *const *const u8) {
44117

45118
let file = args[1];
46119

47-
let img_data;
48-
let img_width;
49-
let img_height;
120+
let mut dir_fd = 3;
121+
let mut idx = 0;
122+
let mut files = Vec::new();
123+
124+
let mut img_data;
125+
let mut img_width;
126+
let mut img_height;
127+
128+
let mut last_idx = idx;
50129

51130
if file.ends_with("qoi") {
131+
files.push(file.to_owned());
52132
let Ok(file) = ulib::sys::openat(3, file.as_bytes(), 0, 0) else {
53133
println!("Error opening file {}", file);
54134
ulib::sys::exit(1);
55135
};
56-
57-
let img = read_all(file);
58-
let (header, data) = gfx::format::qoi::read_qoi_header(&img).unwrap();
59-
let width = header.width as usize;
60-
let height = header.height as usize;
61-
let mut output = alloc::vec![0u32; width * height];
62-
gfx::format::qoi::decode_qoi(&header, data, &mut output, width);
63-
64-
img_width = width;
65-
img_height = height;
66-
img_data = output;
136+
(img_width, img_height, img_data) = load_image(file);
137+
} else if let Ok(dir) = ulib::sys::openat(3, alloc::format!("{file}/").as_bytes(), 0, 0) {
138+
files = list_dir(dir);
139+
files.retain(|f| f.ends_with("qoi"));
140+
files.sort();
141+
println!("Loaded files: {:?}", files);
142+
dir_fd = dir;
143+
144+
let Ok(file) = ulib::sys::openat(dir_fd, files[0].as_bytes(), 0, 0) else {
145+
println!("Error opening file {}", file);
146+
ulib::sys::exit(1);
147+
};
148+
(img_width, img_height, img_data) = load_image(file);
67149
} else {
68150
println!("Unknown file format, exiting.");
69151
ulib::sys::exit(1);
@@ -84,11 +166,29 @@ fn main(argc: usize, argv: *const *const u8) {
84166
proto::EventKind::INPUT => {
85167
use proto::EventData;
86168
let data = proto::InputEvent::parse(&ev).expect("TODO");
87-
if data.kind == proto::InputEvent::KIND_KEY {
169+
if data.kind == proto::InputEvent::KIND_KEY && data.data1 == 1 {
88170
match proto::ScanCode(data.data2) {
89171
proto::ScanCode::ESCAPE | proto::ScanCode::Q => {
90172
break 'outer;
91173
}
174+
proto::ScanCode::RIGHT => {
175+
idx = (idx + 1) % files.len();
176+
}
177+
proto::ScanCode::LEFT => {
178+
idx = (idx + files.len() - 1) % files.len();
179+
}
180+
_ => (),
181+
}
182+
} else if data.kind == proto::InputEvent::KIND_MOUSE && data.data1 == 2 {
183+
match data.data4 {
184+
1 => {
185+
// Mouse1 down
186+
idx = (idx + 1) % files.len();
187+
}
188+
2 => {
189+
// Mouse2 down
190+
idx = (idx + files.len() - 1) % files.len();
191+
}
92192
_ => (),
93193
}
94194
}
@@ -100,9 +200,27 @@ fn main(argc: usize, argv: *const *const u8) {
100200
}
101201
}
102202

203+
idx = idx % files.len();
204+
if idx != last_idx {
205+
let start = unsafe { ulib::sys::sys_get_time_ms() };
206+
if let Ok(file) = ulib::sys::openat(dir_fd, files[idx].as_bytes(), 0, 0) {
207+
drop(img_data);
208+
(img_width, img_height, img_data) = load_image(file);
209+
let end = unsafe { ulib::sys::sys_get_time_ms() };
210+
println!("Loading image took {}ms", end - start);
211+
last_idx = idx;
212+
} else {
213+
println!("Error opening file {}", file);
214+
idx = last_idx;
215+
}
216+
}
217+
218+
let x = width.saturating_sub(img_width) / 2;
219+
let y = height.saturating_sub(img_height) / 2;
220+
103221
let fb = buf.video_mem();
104222
gfx::blit_buffer(
105-
fb, width, height, row_stride, 0, 0, &img_data, img_width, img_height, img_width,
223+
fb, width, height, row_stride, x, y, &img_data, img_width, img_height, img_width,
106224
);
107225

108226
buf.client_to_server_queue()
@@ -114,8 +232,6 @@ fn main(argc: usize, argv: *const *const u8) {
114232

115233
// signal(video)? for sync
116234
ulib::sys::sem_down(buf.get_sem_fd(buf.present_sem)).unwrap();
117-
118-
unsafe { ulib::sys::sys_sleep_ms(1000) };
119235
}
120236

121237
buf.client_to_server_queue()

0 commit comments

Comments
 (0)