Skip to content

Commit 1ea4fdc

Browse files
author
T. Andrew Davis
committed
Refactor network handling and appearance management
- Update `NetObsChamber` to prevent clobbering in-progress typing during periodic refresh. - Prefer NIC hardware counters when available for network statistics. - Enhance `SettingsApp` initialization to sync global settings. - Introduce network mode selection in `setup-dev.sh` with support for bridge and user NAT modes. - Implement bridge ACL checks and helper availability in `setup-dev.sh`. - Add `netcheck` application for network diagnostics, including DHCP lease acquisition and DNS resolution. - Refactor appearance management in `shelld` to use a shared `DesktopAppearance` struct for consistent theming. - Update various islands in `shelld` to utilize dynamic color settings from `ShellState`. - Introduce persistence for desktop appearance settings in `libmorpheus`.
1 parent 0ca5bbe commit 1ea4fdc

21 files changed

Lines changed: 911 additions & 197 deletions

File tree

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ members = [
2121
"shelld",
2222
"settings",
2323
"tests/syscall-e2e",
24+
"tests/netcheck",
2425
"tests/spinning-cube",
2526
"tests/system-visualizer",
2627
]

bootloader/src/baremetal_ops/network/config.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,13 @@ pub(super) unsafe fn net_cfg_get(buf: *mut u8) -> i64 {
4545
}
4646

4747
pub(super) unsafe fn net_cfg_dhcp() -> i64 {
48-
if state::user_net_stack_mut().is_some() {
49-
0
50-
} else {
51-
-1
48+
let Some(stack) = state::user_net_stack_mut() else {
49+
return -1;
50+
};
51+
52+
match stack.restart_dhcp() {
53+
Ok(()) => 0,
54+
Err(_) => -1,
5255
}
5356
}
5457

@@ -81,6 +84,8 @@ pub(super) unsafe fn net_poll_stats(buf: *mut u8) -> i64 {
8184
0,
8285
core::mem::size_of::<morpheus_hwinit::NetStats>(),
8386
);
87+
out.tx_packets = morpheus_network::stack::tx_packet_count() as u64;
88+
out.rx_packets = morpheus_network::stack::rx_packet_count() as u64;
8489
out.tcp_active = state::tcp_active_count();
8590
0
8691
}

compd/src/islands/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,9 @@ pub const TITLE_H: u32 = 22;
1313
pub const BORDER: u32 = 1;
1414
pub const CASCADE_STEP: i32 = 28;
1515

16-
pub const TITLE_FOCUSED_RGB: (u8, u8, u8) = (0, 85, 0);
1716
pub const TITLE_UNFOCUSED_RGB: (u8, u8, u8) = (40, 40, 40);
1817
pub const TITLE_TEXT_RGB: (u8, u8, u8) = (255, 255, 255);
19-
pub const BORDER_FOCUSED_RGB: (u8, u8, u8) = (0, 170, 0);
2018
pub const BORDER_UNFOCUSED_RGB: (u8, u8, u8) = (85, 85, 85);
21-
pub const DESKTOP_RGB: (u8, u8, u8) = (26, 26, 46);
2219
pub const CURSOR_RGB: (u8, u8, u8) = (255, 255, 255);
2320

2421
// shelld's panel height. hardcoded here so compd can re-blit it above windows.
@@ -93,6 +90,10 @@ pub struct CompState {
9390
pub last_buttons: u8,
9491
pub capture: Option<MouseCapture>,
9592

93+
pub desktop_rgb: (u8, u8, u8),
94+
pub title_focused_rgb: (u8, u8, u8),
95+
pub border_focused_rgb: (u8, u8, u8),
96+
9697
// --- channels (SPSC) ---
9798
pub ch_input_to_focus: Channel<InputMsg, 16>,
9899
pub ch_mouse_spatial: Channel<MouseSpatialMsg, 32>,
@@ -117,6 +118,9 @@ impl CompState {
117118
mouse_y: (fb_h / 2) as i32,
118119
last_buttons: 0,
119120
capture: None,
121+
desktop_rgb: (26, 26, 46),
122+
title_focused_rgb: (0, 85, 0),
123+
border_focused_rgb: (0, 170, 0),
120124
ch_input_to_focus: Channel::new(),
121125
ch_mouse_spatial: Channel::new(),
122126
ch_mouse_route: Channel::new(),
@@ -132,6 +136,12 @@ impl CompState {
132136
(r as u32) | ((g as u32) << 8) | ((b as u32) << 16)
133137
}
134138
}
139+
140+
pub fn apply_desktop_appearance(&mut self, a: &libmorpheus::desktop::DesktopAppearance) {
141+
self.desktop_rgb = a.desktop_rgb;
142+
self.title_focused_rgb = a.title_focus_rgb;
143+
self.border_focused_rgb = a.border_focus_rgb;
144+
}
135145
}
136146

137147
pub const fn zeroed_surface_entry() -> compsys::SurfaceEntry {

compd/src/islands/renderer.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn compose(state: &mut CompState) {
4343
}
4444
}
4545
if !drew_desktop {
46-
let (dr, dg, db) = DESKTOP_RGB;
46+
let (dr, dg, db) = state.desktop_rgb;
4747
raw_fill(
4848
fb_ptr,
4949
state.fb_stride,
@@ -148,16 +148,8 @@ fn draw_window(state: &mut CompState, idx: usize, focused: bool) {
148148
)
149149
};
150150

151-
let (tb_r, tb_g, tb_b) = if focused {
152-
TITLE_FOCUSED_RGB
153-
} else {
154-
TITLE_UNFOCUSED_RGB
155-
};
156-
let (br, bg, bb) = if focused {
157-
BORDER_FOCUSED_RGB
158-
} else {
159-
BORDER_UNFOCUSED_RGB
160-
};
151+
let (tb_r, tb_g, tb_b) = if focused { state.title_focused_rgb } else { TITLE_UNFOCUSED_RGB };
152+
let (br, bg, bb) = if focused { state.border_focused_rgb } else { BORDER_UNFOCUSED_RGB };
161153

162154
let outer_x = win_x - BORDER as i32;
163155
let outer_y = win_y - TITLE_H as i32 - BORDER as i32;

compd/src/main.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,22 @@ fn main() -> i32 {
3030
let mut state =
3131
islands::CompState::new(fb_ptr, fb_info.width, fb_info.height, fb_stride_px, is_bgrx);
3232

33+
if let Some(a) = libmorpheus::desktop::DesktopAppearance::load() {
34+
state.apply_desktop_appearance(&a);
35+
}
36+
37+
let mut last_appearance_poll_ms = 0u64;
38+
3339
// 5. enter main vsync loop
3440
loop {
41+
let now_ms = libmorpheus::time::uptime_ms();
42+
if now_ms.saturating_sub(last_appearance_poll_ms) >= 400 {
43+
if let Some(a) = libmorpheus::desktop::DesktopAppearance::load() {
44+
state.apply_desktop_appearance(&a);
45+
}
46+
last_appearance_poll_ms = now_ms;
47+
}
48+
3549
islands::vsync::tick(&mut state);
3650
islands::input::poll(&mut state);
3751
islands::surface_mgr::update(&mut state);

libmorpheus/src/desktop.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
//! Desktop environment appearance profile shared across settings, shelld, and compd.
2+
3+
use crate::persist;
4+
5+
pub const APPEARANCE_KEY: &str = "de_appearance_v1";
6+
pub const APPEARANCE_KEY_LEGACY: &str = "de.appearance.v1";
7+
const MAGIC: [u8; 4] = *b"MDE1";
8+
const VERSION: u8 = 1;
9+
const ENCODED_LEN: usize = 26;
10+
11+
#[derive(Clone, Copy, PartialEq, Eq)]
12+
pub struct DesktopAppearance {
13+
pub dark_mode: bool,
14+
pub accent_rgb: (u8, u8, u8),
15+
pub desktop_rgb: (u8, u8, u8),
16+
pub panel_rgb: (u8, u8, u8),
17+
pub start_rgb: (u8, u8, u8),
18+
pub title_focus_rgb: (u8, u8, u8),
19+
pub border_focus_rgb: (u8, u8, u8),
20+
}
21+
22+
impl DesktopAppearance {
23+
pub const fn default_dark() -> Self {
24+
Self {
25+
dark_mode: true,
26+
accent_rgb: (0, 230, 118),
27+
desktop_rgb: (26, 26, 46),
28+
panel_rgb: (18, 20, 30),
29+
start_rgb: (0, 85, 0),
30+
title_focus_rgb: (0, 85, 0),
31+
border_focus_rgb: (0, 170, 0),
32+
}
33+
}
34+
35+
pub const fn default_light() -> Self {
36+
Self {
37+
dark_mode: false,
38+
accent_rgb: (0, 132, 96),
39+
desktop_rgb: (236, 238, 245),
40+
panel_rgb: (220, 223, 230),
41+
start_rgb: (0, 132, 96),
42+
title_focus_rgb: (0, 132, 96),
43+
border_focus_rgb: (0, 165, 120),
44+
}
45+
}
46+
47+
pub fn from_theme_choice(dark_mode: bool, accent_rgb: (u8, u8, u8)) -> Self {
48+
let (ar, ag, ab) = accent_rgb;
49+
let title = scale_rgb(accent_rgb, if dark_mode { 38 } else { 68 });
50+
let border = scale_rgb(accent_rgb, if dark_mode { 76 } else { 92 });
51+
let start = scale_rgb(accent_rgb, if dark_mode { 34 } else { 74 });
52+
let desktop = if dark_mode {
53+
(26, 26, 46)
54+
} else {
55+
(236, 238, 245)
56+
};
57+
let panel = if dark_mode {
58+
(18, 20, 30)
59+
} else {
60+
(220, 223, 230)
61+
};
62+
63+
Self {
64+
dark_mode,
65+
accent_rgb: (ar, ag, ab),
66+
desktop_rgb: desktop,
67+
panel_rgb: panel,
68+
start_rgb: start,
69+
title_focus_rgb: title,
70+
border_focus_rgb: border,
71+
}
72+
}
73+
74+
pub fn load() -> Option<Self> {
75+
let mut buf = [0u8; ENCODED_LEN];
76+
if let Ok(n) = persist::get(APPEARANCE_KEY, &mut buf) {
77+
if n == ENCODED_LEN {
78+
if let Some(v) = decode(&buf) {
79+
return Some(v);
80+
}
81+
}
82+
}
83+
84+
if let Ok(n) = persist::get(APPEARANCE_KEY_LEGACY, &mut buf) {
85+
if n == ENCODED_LEN {
86+
return decode(&buf);
87+
}
88+
}
89+
90+
None
91+
}
92+
93+
pub fn store(&self) -> Result<(), u64> {
94+
let buf = encode(self);
95+
match persist::put(APPEARANCE_KEY, &buf) {
96+
Ok(()) => Ok(()),
97+
Err(_) => persist::put(APPEARANCE_KEY_LEGACY, &buf),
98+
}
99+
}
100+
}
101+
102+
#[inline(always)]
103+
fn scale8(v: u8, pct: u16) -> u8 {
104+
let x = (v as u16).saturating_mul(pct) / 100;
105+
x.min(255) as u8
106+
}
107+
108+
#[inline(always)]
109+
fn scale_rgb(rgb: (u8, u8, u8), pct: u16) -> (u8, u8, u8) {
110+
(scale8(rgb.0, pct), scale8(rgb.1, pct), scale8(rgb.2, pct))
111+
}
112+
113+
fn encode(a: &DesktopAppearance) -> [u8; ENCODED_LEN] {
114+
let mut out = [0u8; ENCODED_LEN];
115+
out[0..4].copy_from_slice(&MAGIC);
116+
out[4] = VERSION;
117+
out[5] = if a.dark_mode { 1 } else { 0 };
118+
119+
write_rgb(&mut out, 8, a.accent_rgb);
120+
write_rgb(&mut out, 11, a.desktop_rgb);
121+
write_rgb(&mut out, 14, a.panel_rgb);
122+
write_rgb(&mut out, 17, a.start_rgb);
123+
write_rgb(&mut out, 20, a.title_focus_rgb);
124+
write_rgb(&mut out, 23, a.border_focus_rgb);
125+
out
126+
}
127+
128+
fn decode(buf: &[u8; ENCODED_LEN]) -> Option<DesktopAppearance> {
129+
if buf[0..4] != MAGIC || buf[4] != VERSION {
130+
return None;
131+
}
132+
133+
Some(DesktopAppearance {
134+
dark_mode: buf[5] != 0,
135+
accent_rgb: read_rgb(buf, 8),
136+
desktop_rgb: read_rgb(buf, 11),
137+
panel_rgb: read_rgb(buf, 14),
138+
start_rgb: read_rgb(buf, 17),
139+
title_focus_rgb: read_rgb(buf, 20),
140+
border_focus_rgb: read_rgb(buf, 23),
141+
})
142+
}
143+
144+
#[inline(always)]
145+
fn write_rgb(buf: &mut [u8; ENCODED_LEN], i: usize, rgb: (u8, u8, u8)) {
146+
buf[i] = rgb.0;
147+
buf[i + 1] = rgb.1;
148+
buf[i + 2] = rgb.2;
149+
}
150+
151+
#[inline(always)]
152+
fn read_rgb(buf: &[u8; ENCODED_LEN], i: usize) -> (u8, u8, u8) {
153+
(buf[i], buf[i + 1], buf[i + 2])
154+
}

libmorpheus/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ extern crate alloc; // buddy.rs registers #[global_allocator] → Vec/Box/String
1616

1717
pub mod buddy;
1818
pub mod compositor;
19+
pub mod desktop;
1920
pub mod entry;
2021
pub mod env;
2122
pub mod error;

network/src/stack/interface.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,25 @@ impl<D: NetworkDevice> NetInterface<D> {
315315
})
316316
}
317317

318+
/// Restart DHCP discovery on an existing DHCP-enabled interface.
319+
pub fn restart_dhcp(&mut self) -> Result<()> {
320+
let Some(dhcp_handle) = self.dhcp_handle else {
321+
return Err(NetworkError::ProtocolNotAvailable);
322+
};
323+
324+
let dhcp = self.sockets.get_mut::<DhcpSocket>(dhcp_handle);
325+
dhcp.reset();
326+
327+
// Drop current lease immediately so userspace sees discovery state.
328+
self.iface.update_ip_addrs(|addrs| addrs.clear());
329+
self.iface.routes_mut().remove_default_ipv4_route();
330+
self.gateway = None;
331+
self.dns = None;
332+
self.state = NetState::DhcpDiscovering;
333+
334+
Ok(())
335+
}
336+
318337
/// Start a DNS query for a hostname. Returns a query handle.
319338
pub fn start_dns_query(&mut self, hostname: &str) -> Result<smoltcp::socket::dns::QueryHandle> {
320339
super::debug_log(80, "start_dns_query");

0 commit comments

Comments
 (0)