Skip to content

Commit bcec836

Browse files
committed
Allow apps to set window titles
1 parent 1af3246 commit bcec836

6 files changed

Lines changed: 78 additions & 3 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/display-proto/src/lib.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ impl EventKind {
217217
pub const PRESENT: EventKind = EventKind(1);
218218
pub const INPUT: EventKind = EventKind(2);
219219
pub const DISCONNECT: EventKind = EventKind(3);
220+
pub const TITLE: EventKind = EventKind(4);
220221
pub const REQUEST_CLOSE: EventKind = EventKind(5);
221222
}
222223

@@ -281,6 +282,29 @@ impl EventData for InputEvent {
281282
}
282283
}
283284

285+
#[derive(Copy, Clone)]
286+
#[repr(C)]
287+
pub struct TitleEvent {
288+
pub len: u8,
289+
pub data: [u8; 7 * 8 - 1],
290+
}
291+
unsafe impl bytemuck::Zeroable for TitleEvent {}
292+
unsafe impl bytemuck::AnyBitPattern for TitleEvent {}
293+
impl EventData for TitleEvent {
294+
const KIND: EventKind = EventKind::TITLE;
295+
fn parse_data(data: &[u64; 7]) -> Option<Self> {
296+
const _ASSERT: () = assert!(size_of::<TitleEvent>() <= size_of::<[u64; 7]>());
297+
let bytes = &bytemuck::bytes_of(data)[..size_of::<Self>()];
298+
Some(*bytemuck::from_bytes(bytes))
299+
}
300+
fn serialize_data(&self) -> [u64; 7] {
301+
let mut out = [0u64; 7];
302+
let data: [u8; size_of::<Self>()] = unsafe { core::mem::transmute(*self) };
303+
bytemuck::cast_slice_mut(&mut out)[..size_of::<Self>()].copy_from_slice(&data);
304+
out
305+
}
306+
}
307+
284308
#[derive(Copy, Clone)]
285309
#[repr(C)]
286310
pub struct RequestCloseEvent;

crates/display-proto/src/local.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,16 @@ impl BufferHandle {
7474
pub fn get_sem_fd(&self, sem: SemDescriptor) -> u32 {
7575
self.fds[sem.0 as usize]
7676
}
77+
78+
pub fn set_title(&mut self, title: &[u8]) {
79+
let truncated_len = title.len().min(7 * 8 - 1);
80+
let mut title_event = super::TitleEvent {
81+
len: truncated_len as u8,
82+
data: [0; 7 * 8 - 1],
83+
};
84+
title_event.data[..truncated_len].copy_from_slice(&title[..truncated_len]);
85+
self.client_to_server_queue()
86+
.try_send_data(title_event)
87+
.ok();
88+
}
7789
}

crates/display-server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ thunderdome = { version = "0.6", default-features = false }
1212
display-proto = { path = "../display-proto" }
1313
ulib = { path = "../ulib", features = ["heap-impl"] }
1414
gfx = { path = "../gfx" }
15+
lz4 = { path = "../lz4" }
1516

1617
[dev-dependencies]
1718
ulib = { path = "../ulib", features = ["test"] }

crates/display-server/src/main.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ extern crate display_proto as proto;
77
#[macro_use]
88
extern crate ulib;
99

10+
use alloc::string::String;
1011
use alloc::vec::Vec;
1112
use proto::BufferHandle;
1213
use thunderdome::{Arena, Index};
@@ -23,6 +24,7 @@ struct BufferInfo {
2324

2425
struct Client {
2526
handle: BufferHandle,
27+
title: String,
2628
present_ready: bool,
2729
}
2830

@@ -76,6 +78,7 @@ fn handle_incoming(
7678
let client = Client {
7779
handle,
7880
present_ready: false,
81+
title: String::new(),
7982
};
8083
(window, client)
8184
}
@@ -321,6 +324,16 @@ fn handle_conns(mut fb: framebuffer::Framebuffer, server_socket: FileDesc) {
321324
load_image(include_bytes!("../assets/close-pressed.qoi"));
322325
assert!(close_height == close2_height && close_width == close2_width);
323326

327+
let compressed_font = include_bytes_align!(u32, "../../console/ctrld-fixed-10r.pcf.lz4");
328+
let size = lz4::frame::read_frame(compressed_font)
329+
.unwrap()
330+
.0
331+
.content_size()
332+
.unwrap();
333+
let mut font_data = alloc::vec![0; size as usize];
334+
let font_data = lz4::decode_into(compressed_font, &mut font_data).unwrap();
335+
let font = gfx::format::pcf::load_pcf(font_data).unwrap();
336+
324337
let mut to_remove = Vec::<Index>::new();
325338

326339
let mut intermediate_fb = alloc::vec![0u128; fb.data.len()];
@@ -447,6 +460,7 @@ fn handle_conns(mut fb: framebuffer::Framebuffer, server_socket: FileDesc) {
447460
}
448461

449462
for (i, client) in clients.iter_mut() {
463+
use proto::EventData;
450464
let mut ev_limit = 10;
451465
while let Some(msg) = client.handle.client_to_server_queue().try_recv() {
452466
if ev_limit == 0 {
@@ -455,15 +469,21 @@ fn handle_conns(mut fb: framebuffer::Framebuffer, server_socket: FileDesc) {
455469
ev_limit -= 1;
456470
match msg.kind {
457471
proto::EventKind::PRESENT => {
458-
// HACK: treat newest window as active
459-
use proto::EventData;
460472
let proto::PresentEvent = proto::PresentEvent::parse(&msg).unwrap();
461473
client.present_ready = true;
462474
any_updated = true;
463475
}
476+
proto::EventKind::TITLE => {
477+
let proto::TitleEvent { len, data } =
478+
proto::TitleEvent::parse(&msg).unwrap();
479+
let buf = &data[..(len as usize).min(data.len())];
480+
client.title = alloc::string::String::from_utf8_lossy(buf).into_owned();
481+
println!("Updated title: {:?}", client.title);
482+
any_updated = true;
483+
}
464484
proto::EventKind::DISCONNECT => {
465485
// TODO: auto-disconnect on process exit?
466-
println!("Client {:?} disconnected.", i);
486+
println!("[disp] client {:?} disconnected.", i);
467487
to_remove.push(i);
468488
break;
469489
}
@@ -475,6 +495,7 @@ fn handle_conns(mut fb: framebuffer::Framebuffer, server_socket: FileDesc) {
475495
}
476496

477497
let title_height = 12;
498+
let title_fg_color = 0xFF000000;
478499
let title_bg_color_active = 0xFFFFFFFF;
479500
let title_bg_color_inactive = 0xFFCCCCCC;
480501

@@ -529,6 +550,19 @@ fn handle_conns(mut fb: framebuffer::Framebuffer, server_socket: FileDesc) {
529550
}
530551

531552
let out = bytemuck::cast_slice_mut::<_, u32>(&mut intermediate_fb);
553+
let buf = &mut out
554+
[window_y * fb.stride..(window_y + title_height).min(fb.height) * fb.stride];
555+
let title_start = (fb.stride * 2) + window_x + 2;
556+
font.draw_string(
557+
&client.title,
558+
buf,
559+
title_start,
560+
Some(effective_width.saturating_sub(2)),
561+
fb.stride,
562+
1,
563+
title_fg_color,
564+
);
565+
532566
// Draw close button
533567

534568
let close_pressed = match hovered {

crates/gfx/src/format/pcf.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,9 @@ impl<'a> BitmapData<'a> {
566566
// TODO: caching and performance improvements
567567
if scan == 1 {
568568
let rows = height;
569+
let max_rows = (buffer.len().saturating_sub(start)) / buf_row_stride;
570+
let rows = rows.min((max_rows / scale) * scale);
571+
569572
let row_size = width.div_ceil(8);
570573
let row_stride = row_size.next_multiple_of(row_pad);
571574
// let safety_margin = (scale - 1) * buf_row_stride + (scale - 1);

0 commit comments

Comments
 (0)