use std::collections::HashMap;
use std::sync::{Arc, Mutex, RwLock};
use std::time::SystemTime;
use crate::parser::WasmaConfig;
use crate::uclient::SectionMemory;
use crate::wasma_client_unix_posix_raw_app::UClientEngine;
use crate::wasma_client_unix_posix_raw_window::RawWindowClient;
use crate::wasma_protocol_unix_posix_opt::{
DisplayBackend, PosixOpt, RuntimeOptStore, ToolkitTheme,
};
use crate::window_client::WindowClient;
use crate::window_handling::{WindowGeometry, WindowState, WindowType};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum WindowMode {
Singularity,
Multitary,
}
impl WindowMode {
pub fn name(&self) -> &'static str {
match self {
Self::Singularity => "singularity",
Self::Multitary => "multitary",
}
}
pub fn from_config(config: &WasmaConfig) -> Self {
if config.uri_handling.singularity_instances {
Self::Singularity
} else {
Self::Multitary
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum SpecSource {
Manifest(String),
Runtime,
Config,
}
impl SpecSource {
pub fn label(&self) -> String {
match self {
Self::Manifest(path) => format!("manifest:{}", path),
Self::Runtime => "runtime".to_string(),
Self::Config => "config".to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum DecorationStyle {
ServerSide,
ClientSide,
None,
Auto,
}
#[derive(Debug, Clone)]
pub struct WindowSpec {
pub app_id: String,
pub title: String,
pub window_type: WindowType,
pub geometry: WindowGeometry,
pub decoration: DecorationStyle,
pub initial_state: WindowState,
pub start_visible: bool,
pub start_focused: bool,
pub parent_id: Option<u64>,
pub properties: HashMap<String, String>,
pub source: SpecSource,
pub created_at: SystemTime,
}
impl WindowSpec {
pub fn new(app_id: impl Into<String>, title: impl Into<String>) -> Self {
Self {
app_id: app_id.into(),
title: title.into(),
window_type: WindowType::Normal,
geometry: WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
},
decoration: DecorationStyle::Auto,
initial_state: WindowState::Normal,
start_visible: true,
start_focused: true,
parent_id: None,
properties: HashMap::new(),
source: SpecSource::Runtime,
created_at: SystemTime::now(),
}
}
pub fn from_config(config: &WasmaConfig) -> Self {
let mut spec = Self::new(
config.uri_handling.window_app_spec.clone(),
"Wasma App".to_string(),
);
spec.source = SpecSource::Config;
spec.geometry = WindowGeometry {
x: 0,
y: 0,
width: config.resource_limits.scope_level.max(1) as u32 * 100 + 800,
height: 600,
};
spec
}
pub fn from_manifest(content: &str, path: impl Into<String>) -> Self {
let path = path.into();
let mut spec = Self::new("unknown.app", "Untitled");
spec.source = SpecSource::Manifest(path);
for line in content.lines() {
let line = line.trim();
if line.starts_with('#') || line.is_empty() {
continue;
}
if let Some((key, val)) = line.split_once('=') {
let key = key.trim();
let val = val.trim();
match key {
"app_id" => spec.app_id = val.to_string(),
"title" => spec.title = val.to_string(),
"width" => spec.geometry.width = val.parse().unwrap_or(800),
"height" => spec.geometry.height = val.parse().unwrap_or(600),
"x" => spec.geometry.x = val.parse().unwrap_or(0),
"y" => spec.geometry.y = val.parse().unwrap_or(0),
"visible" => spec.start_visible = val == "true",
"focused" => spec.start_focused = val == "true",
"decoration" => {
spec.decoration = match val {
"server" => DecorationStyle::ServerSide,
"client" => DecorationStyle::ClientSide,
"none" => DecorationStyle::None,
_ => DecorationStyle::Auto,
}
}
"type" => {
spec.window_type = match val {
"dialog" => WindowType::Dialog,
"utility" => WindowType::Utility,
_ => WindowType::Normal,
}
}
"state" => {
spec.initial_state = match val {
"minimized" => WindowState::Minimized,
"maximized" => WindowState::Maximized,
"fullscreen" => WindowState::Fullscreen,
"hidden" => WindowState::Hidden,
_ => WindowState::Normal,
}
}
_ => {
spec.properties.insert(key.to_string(), val.to_string());
}
}
}
}
spec
}
pub fn validate(&self) -> Result<(), Vec<String>> {
let mut errors = Vec::new();
if self.app_id.is_empty() {
errors.push("app_id cannot be empty".to_string());
}
if self.title.is_empty() {
errors.push("title cannot be empty".to_string());
}
if self.geometry.width == 0 || self.geometry.height == 0 {
errors.push(format!(
"Invalid geometry: {}x{} (must be > 0)",
self.geometry.width, self.geometry.height
));
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
pub struct WindowSpecBuilder {
spec: WindowSpec,
}
impl WindowSpecBuilder {
pub fn new(app_id: impl Into<String>, title: impl Into<String>) -> Self {
Self {
spec: WindowSpec::new(app_id, title),
}
}
pub fn geometry(mut self, x: i32, y: i32, w: u32, h: u32) -> Self {
self.spec.geometry = WindowGeometry {
x,
y,
width: w,
height: h,
};
self
}
pub fn window_type(mut self, t: WindowType) -> Self {
self.spec.window_type = t;
self
}
pub fn decoration(mut self, d: DecorationStyle) -> Self {
self.spec.decoration = d;
self
}
pub fn initial_state(mut self, s: WindowState) -> Self {
self.spec.initial_state = s;
self
}
pub fn start_visible(mut self, v: bool) -> Self {
self.spec.start_visible = v;
self
}
pub fn start_focused(mut self, f: bool) -> Self {
self.spec.start_focused = f;
self
}
pub fn parent(mut self, id: u64) -> Self {
self.spec.parent_id = Some(id);
self
}
pub fn property(mut self, key: impl Into<String>, val: impl Into<String>) -> Self {
self.spec.properties.insert(key.into(), val.into());
self
}
pub fn source(mut self, s: SpecSource) -> Self {
self.spec.source = s;
self
}
pub fn build(self) -> Result<WindowSpec, Vec<String>> {
self.spec.validate()?;
Ok(self.spec)
}
pub fn build_unchecked(self) -> WindowSpec {
self.spec
}
}
#[derive(Debug, Clone)]
pub struct PosixWindow {
pub id: u64,
pub spec: WindowSpec,
pub geometry: WindowGeometry,
pub state: WindowState,
pub visible: bool,
pub focused: bool,
pub applied_opt_source: String,
pub launched_at: SystemTime,
pub backend: DisplayBackend,
}
impl PosixWindow {
fn from_spec(id: u64, spec: WindowSpec, opt: &PosixOpt) -> Self {
let backend = opt.backend.effective_backend();
let geometry = WindowGeometry {
x: spec.geometry.x,
y: spec.geometry.y,
width: spec.geometry.width.max(opt.draw.size.min_width),
height: spec.geometry.height.max(opt.draw.size.min_height),
};
let state = spec.initial_state.clone();
let visible = spec.start_visible;
let focused = spec.start_focused;
Self {
id,
geometry,
state,
visible,
focused,
applied_opt_source: opt.source.clone(),
launched_at: SystemTime::now(),
backend,
spec,
}
}
pub fn is_alive(&self) -> bool {
self.visible || matches!(self.state, WindowState::Minimized)
}
}
pub struct PosixWindowLauncher {
config: Arc<WasmaConfig>,
opt_store: Arc<RuntimeOptStore>,
mode: WindowMode,
windows: Arc<RwLock<HashMap<u64, PosixWindow>>>,
next_id: Arc<Mutex<u64>>,
window_client: Option<Arc<Mutex<WindowClient>>>,
raw_client: Option<Arc<Mutex<RawWindowClient>>>,
active: bool,
memory: SectionMemory,
}
impl PosixWindowLauncher {
pub fn new(config: WasmaConfig) -> Self {
let mode = WindowMode::from_config(&config);
let opt = PosixOpt::from_config(&config);
let level = config.resource_limits.scope_level;
Self {
mode,
opt_store: Arc::new(RuntimeOptStore::new(opt)),
windows: Arc::new(RwLock::new(HashMap::new())),
next_id: Arc::new(Mutex::new(1)),
window_client: None,
raw_client: None,
active: false,
memory: SectionMemory::new(level),
config: Arc::new(config),
}
}
pub fn from_config(config: Arc<WasmaConfig>) -> Self {
let mode = WindowMode::from_config(&config);
let opt = PosixOpt::from_config(&config);
let level = config.resource_limits.scope_level;
Self {
mode,
opt_store: Arc::new(RuntimeOptStore::new(opt)),
windows: Arc::new(RwLock::new(HashMap::new())),
next_id: Arc::new(Mutex::new(1)),
window_client: None,
raw_client: None,
active: false,
memory: SectionMemory::new(level),
config,
}
}
pub fn attach_window_client(&mut self, wc: Arc<Mutex<WindowClient>>) {
self.window_client = Some(wc);
println!("🔗 PosixWindowLauncher: WindowClient attached (rendering delegate)");
}
pub fn attach_raw_client(&mut self, rc: Arc<Mutex<RawWindowClient>>) {
self.raw_client = Some(rc);
println!("🔗 PosixWindowLauncher: RawWindowClient attached (low-level delegate)");
}
pub fn detach_window_client(&mut self) {
self.window_client = None;
println!("🔌 PosixWindowLauncher: WindowClient detached");
}
pub fn detach_raw_client(&mut self) {
self.raw_client = None;
println!("🔌 PosixWindowLauncher: RawWindowClient detached");
}
pub fn set_mode(&mut self, mode: WindowMode) {
println!(
"🔄 PosixWindowLauncher: Mode {} → {}",
self.mode.name(),
mode.name()
);
self.mode = mode;
}
pub fn mode(&self) -> WindowMode {
self.mode
}
pub fn override_opt<F>(&self, f: F)
where
F: FnOnce(&mut PosixOpt),
{
self.opt_store.override_with(f);
}
pub fn opt_store(&self) -> Arc<RuntimeOptStore> {
self.opt_store.clone()
}
fn alloc_id(&self) -> u64 {
let mut n = self.next_id.lock().unwrap();
let id = *n;
*n += 1;
id
}
pub fn launch(&self, spec: WindowSpec) -> Result<u64, String> {
spec.validate().map_err(|e| e.join(", "))?;
if self.mode == WindowMode::Singularity {
let ids: Vec<u64> = { self.windows.read().unwrap().keys().cloned().collect() };
for id in ids {
self.close_window(id).ok();
}
}
let id = self.alloc_id();
let opt = self.opt_store.read();
let window = PosixWindow::from_spec(id, spec.clone(), &opt);
println!(
"🪟 PosixWindowLauncher [{}]: Launching window {} — '{}' [{}x{}] via {} (source: {})",
self.mode.name(),
id,
spec.title,
window.geometry.width,
window.geometry.height,
window.backend.name(),
spec.source.label(),
);
if let Some(ref rc) = self.raw_client {
let raw = rc.lock().unwrap();
match raw.create_window(
&spec.title,
&spec.app_id,
window.geometry,
spec.window_type.clone(),
) {
Ok(raw_id) => println!(" ↳ RawWindowClient delegate: raw window id={}", raw_id),
Err(e) => println!(" ⚠️ RawWindowClient delegate failed (non-fatal): {}", e),
}
}
if let Some(ref wc) = self.window_client {
let mut client = wc.lock().unwrap();
client.resize(window.geometry.width, window.geometry.height);
println!(
" ↳ WindowClient rendering configured: {}x{}",
window.geometry.width, window.geometry.height
);
}
self.apply_toolkit_theme(&opt, id);
self.windows.write().unwrap().insert(id, window);
Ok(id)
}
pub fn launch_from_config(&self) -> Result<u64, String> {
let spec = WindowSpec::from_config(&self.config);
println!("📋 PosixWindowLauncher: Launching from config");
self.launch(spec)
}
pub fn launch_from_manifest(
&self,
content: &str,
path: impl Into<String>,
) -> Result<u64, String> {
let path = path.into();
let spec = WindowSpec::from_manifest(content, &path);
println!("📄 PosixWindowLauncher: Launching from manifest: {}", path);
self.launch(spec)
}
fn apply_toolkit_theme(&self, opt: &PosixOpt, window_id: u64) {
match &opt.draw.toolkit {
ToolkitTheme::Gtk(gtk) => {
println!(
" 🎨 Toolkit: GTK{} theme='{}' dark={}",
gtk.version, gtk.theme_name, gtk.dark_mode
);
}
ToolkitTheme::Iced(iced) => {
println!(" 🎨 Toolkit: Iced theme={:?}", iced.variant);
}
ToolkitTheme::Qt(qt) => {
println!(
" 🎨 Toolkit: Qt{} style='{}' dark={}",
qt.version, qt.style_name, qt.dark_mode
);
}
ToolkitTheme::None => {
println!(" 🎨 Toolkit: None (raw drawing) for window {}", window_id);
}
}
}
pub fn close_window(&self, id: u64) -> Result<(), String> {
if let Some(ref rc) = self.raw_client {
let raw = rc.lock().unwrap();
let _ = raw.destroy_window(id);
}
let mut windows = self.windows.write().unwrap();
if windows.remove(&id).is_some() {
println!("🗑️ PosixWindowLauncher: Window {} closed", id);
Ok(())
} else {
Err(format!("Window {} not found", id))
}
}
pub fn close_all(&self) {
let ids: Vec<u64> = self.windows.read().unwrap().keys().cloned().collect();
for id in ids {
self.close_window(id).ok();
}
println!("🗑️ PosixWindowLauncher: All windows closed");
}
pub fn set_geometry(&self, id: u64, geo: WindowGeometry) -> Result<(), String> {
if let Some(ref rc) = self.raw_client {
let raw = rc.lock().unwrap();
let _ = raw.set_geometry(id, geo);
}
let mut windows = self.windows.write().unwrap();
match windows.get_mut(&id) {
Some(w) => {
w.geometry = geo;
if let Some(ref wc) = self.window_client {
let mut client = wc.lock().unwrap();
client.resize(geo.width, geo.height);
}
Ok(())
}
None => Err(format!("Window {} not found", id)),
}
}
pub fn set_state(&self, id: u64, state: WindowState) -> Result<(), String> {
if let Some(ref rc) = self.raw_client {
let raw = rc.lock().unwrap();
let _ = raw.set_state(id, state.clone());
}
let mut windows = self.windows.write().unwrap();
match windows.get_mut(&id) {
Some(w) => {
w.state = state;
Ok(())
}
None => Err(format!("Window {} not found", id)),
}
}
pub fn set_focus(&self, id: u64) -> Result<(), String> {
{
let mut windows = self.windows.write().unwrap();
for w in windows.values_mut() {
w.focused = false;
}
}
if let Some(ref rc) = self.raw_client {
let raw = rc.lock().unwrap();
let _ = raw.set_focus(id);
}
let mut windows = self.windows.write().unwrap();
match windows.get_mut(&id) {
Some(w) => {
w.focused = true;
Ok(())
}
None => Err(format!("Window {} not found", id)),
}
}
pub fn set_visible(&self, id: u64, visible: bool) -> Result<(), String> {
if let Some(ref rc) = self.raw_client {
let raw = rc.lock().unwrap();
let _ = raw.set_visible(id, visible);
}
let mut windows = self.windows.write().unwrap();
match windows.get_mut(&id) {
Some(w) => {
w.visible = visible;
Ok(())
}
None => Err(format!("Window {} not found", id)),
}
}
pub fn set_title(&self, id: u64, title: impl Into<String>) -> Result<(), String> {
let title = title.into();
if let Some(ref rc) = self.raw_client {
let raw = rc.lock().unwrap();
let _ = raw.set_title(id, &title);
}
let mut windows = self.windows.write().unwrap();
match windows.get_mut(&id) {
Some(w) => {
w.spec.title = title;
Ok(())
}
None => Err(format!("Window {} not found", id)),
}
}
pub fn render_frame(&self, id: u64, data: &[u8]) -> Result<(), String> {
let visible = {
let windows = self.windows.read().unwrap();
match windows.get(&id) {
Some(w) => w.visible && !matches!(w.state, WindowState::Hidden),
None => return Err(format!("Window {} not found", id)),
}
};
if !visible {
return Ok(());
}
self.dispatch_data(data);
Ok(())
}
pub fn get_window(&self, id: u64) -> Option<PosixWindow> {
self.windows.read().unwrap().get(&id).cloned()
}
pub fn list_windows(&self) -> Vec<PosixWindow> {
let windows = self.windows.read().unwrap();
let mut v: Vec<_> = windows.values().cloned().collect();
v.sort_by_key(|w| w.id);
v
}
pub fn window_count(&self) -> usize {
self.windows.read().unwrap().len()
}
pub fn focused_window(&self) -> Option<PosixWindow> {
let windows = self.windows.read().unwrap();
windows.values().find(|w| w.focused).cloned()
}
pub fn has_window_client(&self) -> bool {
self.window_client.is_some()
}
pub fn has_raw_client(&self) -> bool {
self.raw_client.is_some()
}
}
impl UClientEngine for PosixWindowLauncher {
fn start_engine(&mut self) -> Result<(), Box<dyn std::error::Error>> {
self.active = true;
let opt = self.opt_store.read();
println!("🟢 WASMA PosixWindowLauncher: Engine Started");
println!(" Mode: {}", self.mode.name());
println!(" Backend: {}", opt.backend.effective_backend().name());
println!(" Toolkit: {}", opt.draw.toolkit.name());
println!(
" Xlinx: {} | cache={}",
opt.xlinx.arch.name(),
opt.xlinx.cache_mode.name()
);
println!(
" Delegates: WindowClient={} RawClient={}",
self.window_client.is_some(),
self.raw_client.is_some()
);
drop(opt);
if self.windows.read().unwrap().is_empty() {
println!(" Auto-launching from config...");
match self.launch_from_config() {
Ok(id) => println!(" Auto-launch OK: window id={}", id),
Err(e) => eprintln!(" ⚠️ Auto-launch failed: {}", e),
}
}
loop {
if !self.active {
break;
}
std::thread::sleep(std::time::Duration::from_millis(16)); }
Ok(())
}
fn dispatch_data(&self, data: &[u8]) {
if let Some(w) = self.focused_window() {
let _ = self.render_frame(w.id, data);
}
}
fn memory_usage(&self) -> (usize, usize, usize) {
(
self.memory.raw_storage.len(),
self.memory.cell_count,
self.memory.cell_size,
)
}
fn get_config(&self) -> &WasmaConfig {
&self.config
}
fn shutdown(&mut self) -> Result<(), Box<dyn std::error::Error>> {
self.active = false;
self.close_all();
println!("🛑 PosixWindowLauncher: Shutdown complete");
Ok(())
}
fn is_active(&self) -> bool {
self.active
}
}
pub struct PosixWindowLauncherBuilder {
config: Option<WasmaConfig>,
mode: Option<WindowMode>,
opt_overrides: Vec<Box<dyn FnOnce(&mut PosixOpt)>>,
window_client: Option<Arc<Mutex<WindowClient>>>,
raw_client: Option<Arc<Mutex<RawWindowClient>>>,
}
impl PosixWindowLauncherBuilder {
pub fn new() -> Self {
Self {
config: None,
mode: None,
opt_overrides: Vec::new(),
window_client: None,
raw_client: None,
}
}
pub fn with_config(mut self, config: WasmaConfig) -> Self {
self.config = Some(config);
self
}
pub fn with_mode(mut self, mode: WindowMode) -> Self {
self.mode = Some(mode);
self
}
pub fn with_window_client(mut self, wc: Arc<Mutex<WindowClient>>) -> Self {
self.window_client = Some(wc);
self
}
pub fn with_raw_client(mut self, rc: Arc<Mutex<RawWindowClient>>) -> Self {
self.raw_client = Some(rc);
self
}
pub fn opt_override<F: FnOnce(&mut PosixOpt) + 'static>(mut self, f: F) -> Self {
self.opt_overrides.push(Box::new(f));
self
}
pub fn build(self) -> Result<PosixWindowLauncher, String> {
let config = self.config.ok_or("WasmaConfig required")?;
let mut launcher = PosixWindowLauncher::new(config);
if let Some(mode) = self.mode {
launcher.mode = mode;
}
for f in self.opt_overrides {
launcher.opt_store.override_with(f);
}
if let Some(wc) = self.window_client {
launcher.attach_window_client(wc);
}
if let Some(rc) = self.raw_client {
launcher.attach_raw_client(rc);
}
Ok(launcher)
}
}
impl Default for PosixWindowLauncherBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::ConfigParser;
use crate::wasma_protocol_unix_posix_opt::XlinxCacheMode;
fn make_config() -> WasmaConfig {
let parser = ConfigParser::new(None);
let content = parser.generate_default_config();
parser.parse(&content).unwrap()
}
fn make_launcher() -> PosixWindowLauncher {
PosixWindowLauncher::new(make_config())
}
#[test]
fn test_launcher_creation() {
let launcher = make_launcher();
assert!(!launcher.is_active());
assert_eq!(launcher.window_count(), 0);
assert!(!launcher.has_window_client());
assert!(!launcher.has_raw_client());
println!(
"✅ PosixWindowLauncher creation working (mode: {})",
launcher.mode().name()
);
}
#[test]
fn test_launch_runtime_spec() {
let launcher = make_launcher();
let spec = WindowSpecBuilder::new("test.app", "Test Window")
.geometry(100, 100, 1280, 720)
.window_type(WindowType::Normal)
.decoration(DecorationStyle::ServerSide)
.build()
.unwrap();
let id = launcher.launch(spec).unwrap();
assert_eq!(launcher.window_count(), 1);
let window = launcher.get_window(id).unwrap();
assert_eq!(window.spec.app_id, "test.app");
assert_eq!(window.geometry.width, 1280);
assert_eq!(window.geometry.height, 720);
println!("✅ Runtime spec launch working: id={}", id);
}
#[test]
fn test_launch_from_config() {
let launcher = make_launcher();
let id = launcher.launch_from_config().unwrap();
assert_eq!(launcher.window_count(), 1);
assert!(launcher.get_window(id).is_some());
println!("✅ Config-based launch working: id={}", id);
}
#[test]
fn test_launch_from_manifest() {
let launcher = make_launcher();
let manifest = "
# Test manifest
app_id=manifest.app
title=Manifest Window
width=1024
height=768
decoration=client
visible=true
focused=false
custom_key=custom_value
";
let id = launcher
.launch_from_manifest(manifest, "/etc/wasma/test.spec")
.unwrap();
let window = launcher.get_window(id).unwrap();
assert_eq!(window.spec.app_id, "manifest.app");
assert_eq!(window.spec.title, "Manifest Window");
assert_eq!(window.geometry.width, 1024);
assert_eq!(window.geometry.height, 768);
assert!(!window.focused);
assert_eq!(
window.spec.properties.get("custom_key").map(|s| s.as_str()),
Some("custom_value")
);
println!("✅ Manifest launch working: id={}", id);
}
#[test]
fn test_singularity_mode_replaces() {
let mut launcher = make_launcher();
launcher.set_mode(WindowMode::Singularity);
let spec1 = WindowSpecBuilder::new("app1", "Win1").build_unchecked();
let spec2 = WindowSpecBuilder::new("app2", "Win2").build_unchecked();
let spec3 = WindowSpecBuilder::new("app3", "Win3").build_unchecked();
launcher.launch(spec1).unwrap();
assert_eq!(launcher.window_count(), 1);
launcher.launch(spec2).unwrap();
assert_eq!(launcher.window_count(), 1); launcher.launch(spec3).unwrap();
assert_eq!(launcher.window_count(), 1);
let w = launcher.list_windows();
assert_eq!(w[0].spec.app_id, "app3");
println!("✅ Singularity mode replacement working");
}
#[test]
fn test_multitary_mode_accumulates() {
let mut launcher = make_launcher();
launcher.set_mode(WindowMode::Multitary);
for i in 0..4 {
let spec =
WindowSpecBuilder::new(format!("app{}", i), format!("Win{}", i)).build_unchecked();
launcher.launch(spec).unwrap();
}
assert_eq!(launcher.window_count(), 4);
println!(
"✅ Multitary mode accumulation working: {} windows",
launcher.window_count()
);
}
#[test]
fn test_mode_switch_at_runtime() {
let mut launcher = make_launcher();
launcher.set_mode(WindowMode::Multitary);
for i in 0..3 {
let spec =
WindowSpecBuilder::new(format!("a{}", i), format!("W{}", i)).build_unchecked();
launcher.launch(spec).unwrap();
}
assert_eq!(launcher.window_count(), 3);
launcher.set_mode(WindowMode::Singularity);
let spec = WindowSpecBuilder::new("final.app", "Final").build_unchecked();
launcher.launch(spec).unwrap();
assert_eq!(launcher.window_count(), 1);
println!("✅ Runtime mode switch working");
}
#[test]
fn test_window_operations() {
let launcher = make_launcher();
let spec = WindowSpecBuilder::new("ops.app", "Ops Window")
.geometry(0, 0, 800, 600)
.build_unchecked();
let id = launcher.launch(spec).unwrap();
let new_geo = WindowGeometry {
x: 50,
y: 50,
width: 1920,
height: 1080,
};
launcher.set_geometry(id, new_geo).unwrap();
assert_eq!(launcher.get_window(id).unwrap().geometry.width, 1920);
launcher.set_state(id, WindowState::Maximized).unwrap();
assert_eq!(
launcher.get_window(id).unwrap().state,
WindowState::Maximized
);
launcher.set_visible(id, false).unwrap();
assert!(!launcher.get_window(id).unwrap().visible);
launcher.set_title(id, "Updated Title").unwrap();
assert_eq!(launcher.get_window(id).unwrap().spec.title, "Updated Title");
println!("✅ Window operations working");
}
#[test]
fn test_focus_management() {
let mut launcher = make_launcher();
launcher.set_mode(WindowMode::Multitary);
let id1 = launcher
.launch(WindowSpecBuilder::new("a1", "W1").build_unchecked())
.unwrap();
let id2 = launcher
.launch(WindowSpecBuilder::new("a2", "W2").build_unchecked())
.unwrap();
launcher.set_focus(id1).unwrap();
assert!(launcher.get_window(id1).unwrap().focused);
assert!(!launcher.get_window(id2).unwrap().focused);
assert_eq!(launcher.focused_window().unwrap().id, id1);
launcher.set_focus(id2).unwrap();
assert!(!launcher.get_window(id1).unwrap().focused);
assert_eq!(launcher.focused_window().unwrap().id, id2);
println!("✅ Focus management working");
}
#[test]
fn test_close_window() {
let launcher = make_launcher();
let id = launcher.launch_from_config().unwrap();
assert_eq!(launcher.window_count(), 1);
launcher.close_window(id).unwrap();
assert_eq!(launcher.window_count(), 0);
assert!(launcher.get_window(id).is_none());
println!("✅ Window close working");
}
#[test]
fn test_close_all() {
let mut launcher = make_launcher();
launcher.set_mode(WindowMode::Multitary);
for i in 0..5 {
launcher
.launch(
WindowSpecBuilder::new(format!("a{}", i), format!("W{}", i)).build_unchecked(),
)
.unwrap();
}
assert_eq!(launcher.window_count(), 5);
launcher.close_all();
assert_eq!(launcher.window_count(), 0);
println!("✅ close_all working");
}
#[test]
fn test_opt_override_applied() {
let launcher = make_launcher();
launcher.override_opt(|opt| {
opt.draw.vsync = false;
opt.draw.target_fps = Some(144);
opt.xlinx.cache_mode = XlinxCacheMode::Aggressive;
});
let opt = launcher.opt_store.read();
assert!(!opt.draw.vsync);
assert_eq!(opt.draw.target_fps, Some(144));
assert_eq!(opt.xlinx.cache_mode, XlinxCacheMode::Aggressive);
println!("✅ Opt override applied correctly");
}
#[test]
fn test_posix_opt_min_size_constraint() {
let config = make_config();
let mut launcher = PosixWindowLauncher::new(config);
launcher.override_opt(|opt| {
opt.draw.size.min_width = 500;
opt.draw.size.min_height = 400;
});
let spec = WindowSpecBuilder::new("small.app", "Small")
.geometry(0, 0, 100, 100) .build_unchecked();
let id = launcher.launch(spec).unwrap();
let w = launcher.get_window(id).unwrap();
assert!(w.geometry.width >= 500);
assert!(w.geometry.height >= 400);
println!(
"✅ PosixOpt min size constraint applied: {}x{}",
w.geometry.width, w.geometry.height
);
}
#[test]
fn test_spec_from_manifest_invalid_values() {
let launcher = make_launcher();
let manifest = "
app_id=broken.app
title=Broken
width=notanumber
height=600
";
let id = launcher
.launch_from_manifest(manifest, "/tmp/broken.spec")
.unwrap();
let w = launcher.get_window(id).unwrap();
assert_eq!(w.spec.geometry.width, 800);
println!("✅ Manifest invalid value fallback working");
}
#[test]
fn test_uclient_engine_trait_object() {
let launcher: Box<dyn UClientEngine> = Box::new(make_launcher());
assert!(!launcher.is_active());
let (total, cells, _) = launcher.memory_usage();
assert!(total > 0 && cells > 0);
println!("✅ UClientEngine trait object (PosixWindowLauncher) working");
}
#[test]
fn test_builder() {
let config = make_config();
let launcher = PosixWindowLauncherBuilder::new()
.with_config(config)
.with_mode(WindowMode::Multitary)
.opt_override(|opt| opt.draw.antialiasing = false)
.build()
.unwrap();
assert_eq!(launcher.mode(), WindowMode::Multitary);
assert!(!launcher.opt_store.read().draw.antialiasing);
println!("✅ PosixWindowLauncherBuilder working");
}
#[test]
fn test_list_windows_sorted() {
let mut launcher = make_launcher();
launcher.set_mode(WindowMode::Multitary);
for i in 0..4 {
launcher
.launch(
WindowSpecBuilder::new(format!("a{}", i), format!("W{}", i)).build_unchecked(),
)
.unwrap();
}
let windows = launcher.list_windows();
assert_eq!(windows.len(), 4);
for pair in windows.windows(2) {
assert!(pair[0].id < pair[1].id);
}
println!("✅ list_windows sorted correctly");
}
}