Skip to content

Commit ce47166

Browse files
committed
Add slideshow mode to 'show' command
1 parent d40d27d commit ce47166

2 files changed

Lines changed: 138 additions & 20 deletions

File tree

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: 136 additions & 20 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) };
@@ -42,26 +115,35 @@ fn main(argc: usize, argv: *const *const u8) {
42115

43116
let file = args[1];
44117

45-
let img_data;
46-
let img_width;
47-
let img_height;
118+
let mut dir_fd = 3;
119+
let mut idx = 0;
120+
let mut files = Vec::new();
121+
122+
let mut img_data;
123+
let mut img_width;
124+
let mut img_height;
125+
126+
let mut last_idx = idx;
48127

49128
if file.ends_with("qoi") {
129+
files.push(file.to_owned());
50130
let Ok(file) = ulib::sys::openat(3, file.as_bytes(), 0, 0) else {
51131
println!("Error opening file {}", file);
52132
ulib::sys::exit(1);
53133
};
54-
55-
let img = read_all(file);
56-
let (header, data) = gfx::format::qoi::read_qoi_header(&img).unwrap();
57-
let width = header.width as usize;
58-
let height = header.height as usize;
59-
let mut output = alloc::vec![0u32; width * height];
60-
gfx::format::qoi::decode_qoi(&header, data, &mut output, width);
61-
62-
img_width = width;
63-
img_height = height;
64-
img_data = output;
134+
(img_width, img_height, img_data) = load_image(file);
135+
} else if let Ok(dir) = ulib::sys::openat(3, alloc::format!("{file}/").as_bytes(), 0, 0) {
136+
files = list_dir(dir);
137+
files.retain(|f| f.ends_with("qoi"));
138+
files.sort();
139+
println!("Loaded files: {:?}", files);
140+
dir_fd = dir;
141+
142+
let Ok(file) = ulib::sys::openat(dir_fd, files[0].as_bytes(), 0, 0) else {
143+
println!("Error opening file {}", file);
144+
ulib::sys::exit(1);
145+
};
146+
(img_width, img_height, img_data) = load_image(file);
65147
} else {
66148
println!("Unknown file format, exiting.");
67149
ulib::sys::exit(1);
@@ -82,30 +164,66 @@ fn main(argc: usize, argv: *const *const u8) {
82164
proto::EventKind::INPUT => {
83165
use proto::EventData;
84166
let data = proto::InputEvent::parse(&ev).expect("TODO");
85-
if data.kind == proto::InputEvent::KIND_KEY {
167+
if data.kind == proto::InputEvent::KIND_KEY && data.data1 == 1 {
86168
match proto::ScanCode(data.data2) {
87169
proto::ScanCode::ESCAPE | proto::ScanCode::Q => {
88170
break 'outer;
89171
},
172+
proto::ScanCode::RIGHT => {
173+
idx = (idx + 1) % files.len();
174+
},
175+
proto::ScanCode::LEFT => {
176+
idx = (idx + files.len() - 1) % files.len();
177+
},
90178
_ => (),
91179
}
180+
} else if data.kind == proto::InputEvent::KIND_MOUSE && data.data1 == 2 {
181+
match data.data4 {
182+
1 => {
183+
// Mouse1 down
184+
idx = (idx + 1) % files.len();
185+
},
186+
2 => {
187+
// Mouse2 down
188+
idx = (idx + files.len() - 1) % files.len();
189+
},
190+
_ => (),
191+
}
192+
}
92193
}
93-
}
94194
proto::EventKind::REQUEST_CLOSE => {
95195
break 'outer;
96196
}
97197
_ => (),
98198
}
99199
}
100200

201+
idx = idx % files.len();
202+
if idx != last_idx {
203+
let start = unsafe { ulib::sys::sys_get_time_ms() };
204+
if let Ok(file) = ulib::sys::openat(dir_fd, files[idx].as_bytes(), 0, 0) {
205+
drop(img_data);
206+
(img_width, img_height, img_data) = load_image(file);
207+
let end = unsafe { ulib::sys::sys_get_time_ms() };
208+
println!("Loading image took {}ms", end - start);
209+
last_idx = idx;
210+
} else {
211+
println!("Error opening file {}", file);
212+
idx = last_idx;
213+
}
214+
}
215+
216+
let x = width.saturating_sub(img_width) / 2;
217+
let y = height.saturating_sub(img_height) / 2;
218+
101219
let fb = buf.video_mem();
102220
gfx::blit_buffer(
103221
fb,
104222
width,
105223
height,
106224
row_stride,
107-
0,
108-
0,
225+
x,
226+
y,
109227
&img_data,
110228
img_width,
111229
img_height,
@@ -121,8 +239,6 @@ fn main(argc: usize, argv: *const *const u8) {
121239

122240
// signal(video)? for sync
123241
ulib::sys::sem_down(buf.get_sem_fd(buf.present_sem)).unwrap();
124-
125-
unsafe { ulib::sys::sys_sleep_ms(1000) };
126242
}
127243

128244
buf.client_to_server_queue()

0 commit comments

Comments
 (0)