dev/runtime-mode-separation-game-system #24
@ -343,6 +343,22 @@ mod tests {
|
||||
assert_eq!(firmware.hub.window_manager.windows.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn system_running_ticks_focused_system_app_through_hub_pipeline() {
|
||||
let mut firmware = Firmware::new(None);
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
|
||||
firmware.load_cartridge(valid_cartridge(AppMode::System));
|
||||
firmware.tick(&signals, &mut hardware);
|
||||
|
||||
let tick_index_before_system_update = firmware.os.tick_index;
|
||||
firmware.tick(&signals, &mut hardware);
|
||||
|
||||
assert!(matches!(firmware.state, FirmwareState::SystemRunning(_)));
|
||||
assert_eq!(firmware.os.tick_index, tick_index_before_system_update + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_cartridge_routes_game_apps_to_game_running() {
|
||||
let mut firmware = Firmware::new(None);
|
||||
|
||||
@ -11,26 +11,8 @@ impl HubHomeStep {
|
||||
}
|
||||
|
||||
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||
let mut error = None;
|
||||
|
||||
// Always updates the Hub GUI (clears screen and processes input if no focus)
|
||||
ctx.hub.gui_update(ctx.os, ctx.hw);
|
||||
|
||||
if let Some(focused_id) = ctx.hub.window_manager.focused {
|
||||
if ctx.hw.pad().start().down {
|
||||
ctx.hub.window_manager.remove_window(focused_id);
|
||||
} else {
|
||||
// System App runs here, drawing over the Hub background
|
||||
error = ctx.os.tick(ctx.vm, ctx.signals, ctx.hw);
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the System App window borders
|
||||
ctx.hub.render(ctx.os, ctx.hw);
|
||||
|
||||
ctx.hw.gfx_mut().present();
|
||||
|
||||
if let Some(report) = error {
|
||||
let outcome = ctx.hub.update_system_profile(ctx.os, ctx.vm, ctx.signals, ctx.hw);
|
||||
if let Some(report) = outcome.crash {
|
||||
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||
}
|
||||
|
||||
|
||||
@ -11,23 +11,16 @@ impl SystemRunningStep {
|
||||
}
|
||||
|
||||
pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option<FirmwareState> {
|
||||
let mut error = None;
|
||||
|
||||
ctx.hub.gui_update(ctx.os, ctx.hw);
|
||||
|
||||
if let Some(focused_id) = ctx.hub.window_manager.focused {
|
||||
if ctx.hw.pad().start().down {
|
||||
ctx.hub.window_manager.remove_window(focused_id);
|
||||
return Some(FirmwareState::HubHome(HubHomeStep));
|
||||
}
|
||||
|
||||
error = ctx.os.tick(ctx.vm, ctx.signals, ctx.hw);
|
||||
let outcome = ctx.hub.update_system_profile(ctx.os, ctx.vm, ctx.signals, ctx.hw);
|
||||
if let Some(report) = outcome.crash {
|
||||
return Some(FirmwareState::AppCrashes(AppCrashesStep { report }));
|
||||
}
|
||||
|
||||
ctx.hub.render(ctx.os, ctx.hw);
|
||||
ctx.hw.gfx_mut().present();
|
||||
if !outcome.focused_window_active {
|
||||
return Some(FirmwareState::HubHome(HubHomeStep));
|
||||
}
|
||||
|
||||
error.map(|report| FirmwareState::AppCrashes(AppCrashesStep { report }))
|
||||
None
|
||||
}
|
||||
|
||||
pub fn on_exit(&mut self, _ctx: &mut PrometeuContext) {}
|
||||
|
||||
@ -1,15 +1,21 @@
|
||||
use crate::VirtualMachineRuntime;
|
||||
use crate::programs::prometeu_hub::window_manager::WindowManager;
|
||||
use prometeu_hal::HardwareBridge;
|
||||
use crate::{CrashReport, VirtualMachineRuntime};
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::log::{LogLevel, LogSource};
|
||||
use prometeu_hal::window::Rect;
|
||||
use prometeu_hal::{HardwareBridge, InputSignals};
|
||||
use prometeu_vm::VirtualMachine;
|
||||
|
||||
/// PrometeuHub: Launcher and system UI environment.
|
||||
pub struct PrometeuHub {
|
||||
pub window_manager: WindowManager,
|
||||
}
|
||||
|
||||
pub struct SystemProfileUpdate {
|
||||
pub crash: Option<CrashReport>,
|
||||
pub focused_window_active: bool,
|
||||
}
|
||||
|
||||
impl Default for PrometeuHub {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
@ -75,4 +81,29 @@ impl PrometeuHub {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_system_profile(
|
||||
&mut self,
|
||||
os: &mut VirtualMachineRuntime,
|
||||
vm: &mut VirtualMachine,
|
||||
signals: &InputSignals,
|
||||
hw: &mut dyn HardwareBridge,
|
||||
) -> SystemProfileUpdate {
|
||||
let mut crash = None;
|
||||
|
||||
self.gui_update(os, hw);
|
||||
|
||||
if let Some(focused_id) = self.window_manager.focused {
|
||||
if hw.pad().start().down {
|
||||
self.window_manager.remove_window(focused_id);
|
||||
} else {
|
||||
crash = os.tick(vm, signals, hw);
|
||||
}
|
||||
}
|
||||
|
||||
self.render(os, hw);
|
||||
hw.gfx_mut().present();
|
||||
|
||||
SystemProfileUpdate { crash, focused_window_active: self.window_manager.focused.is_some() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,4 +29,4 @@
|
||||
{"type":"discussion","id":"DSC-0018","status":"done","ticket":"asset-load-asset-id-int-contract","title":"Asset Load Asset ID Int Contract","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["asset","runtime","abi"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0019","file":"discussion/lessons/DSC-0018-asset-load-asset-id-int-contract/LSN-0019-asset-load-id-abi-convergence.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
||||
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"discussion/lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
|
||||
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"internal-viewport-270p","title":"Agenda - Internal Viewport 270p (480x270)","created_at":"2026-04-27","updated_at":"2026-04-28","tags":["gfx","runtime","viewport","resolution","frame-composer","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0030-internal-viewport-270p/LSN-0039-resolution-baseline-changes-are-runtime-wide-contracts.md","status":"done","created_at":"2026-04-28","updated_at":"2026-04-28"}]}
|
||||
{"type":"discussion","id":"DSC-0031","status":"in_progress","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[{"id":"AGD-0031","file":"AGD-0031-runtime-mode-separation-game-system.md","status":"accepted","created_at":"2026-05-11","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0023","file":"DEC-0023-system-pipeline-separation.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"plans":[{"id":"PLN-0046","file":"PLN-0046-profile-separation-specification.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0047","file":"PLN-0047-firmware-runtime-profile-dispatch.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0048","file":"PLN-0048-minimal-system-hub-pipeline.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0049","file":"PLN-0049-system-profile-abi-gates.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0050","file":"PLN-0050-system-pipeline-evidence-and-learning.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0031","status":"in_progress","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[{"id":"AGD-0031","file":"AGD-0031-runtime-mode-separation-game-system.md","status":"accepted","created_at":"2026-05-11","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0023","file":"DEC-0023-system-pipeline-separation.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"plans":[{"id":"PLN-0046","file":"PLN-0046-profile-separation-specification.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0047","file":"PLN-0047-firmware-runtime-profile-dispatch.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0048","file":"PLN-0048-minimal-system-hub-pipeline.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0049","file":"PLN-0049-system-profile-abi-gates.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]},{"id":"PLN-0050","file":"PLN-0050-system-pipeline-evidence-and-learning.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0023"]}],"lessons":[]}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
id: PLN-0048
|
||||
ticket: runtime-mode-separation-game-system
|
||||
title: Minimal System Hub Pipeline
|
||||
status: open
|
||||
status: done
|
||||
created: 2026-05-14
|
||||
completed:
|
||||
ref_decisions: [DEC-0023]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user