use iced::window::{Id as WindowId, Position};
use iced::{
executor,
widget::{button, column, container, row, scrollable, text, text_input, Space},
window, Application, Background, Color, Command, Element, Length, Settings, Theme,
};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
use wbackend::{Assignment, ExecutionMode, ResourceMode, WBackend};
use crate::parser::{ConfigParser, Protocol, WasmaConfig};
use crate::window_client::WindowClient;
use wsdg_app_manifest::manifest_parser::{CpuCoreServe, ManifestParser};
use wsdg_app_manifest::source_parser::{FileException, PermissionSource, SourceParser};
#[derive(Debug, Clone, PartialEq)]
pub enum WindowState {
Normal,
Minimized,
Maximized,
Fullscreen,
Hidden,
}
#[derive(Debug, Clone, PartialEq)]
pub enum WindowType {
Normal,
Dialog,
Utility,
Splash,
Menu,
Dropdown,
Popup,
Tooltip,
Notification,
}
#[derive(Debug, Clone, Copy)]
pub struct WindowGeometry {
pub x: i32,
pub y: i32,
pub width: u32,
pub height: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub enum BackendType {
Native,
Wayland,
X11,
Remote(String),
}
#[derive(Debug, Clone)]
pub struct ResourceLimits {
pub max_memory_mb: u64,
pub max_gpu_memory_mb: u64,
pub cpu_cores: Vec<usize>,
pub lease_duration: Duration,
pub execution_mode: Option<ExecutionMode>,
pub renderer: String,
pub pixel_load_limit: u32,
}
impl Default for ResourceLimits {
fn default() -> Self {
Self {
max_memory_mb: 512,
max_gpu_memory_mb: 256,
cpu_cores: Vec::new(),
execution_mode: Some(ExecutionMode::GpuPreferred),
lease_duration: Duration::from_secs(30),
renderer: "cpu_renderer".to_string(),
pixel_load_limit: 50,
}
}
}
#[derive(Debug, Clone)]
pub struct PermissionScope {
pub can_access_network: bool,
pub can_access_filesystem: bool,
pub can_spawn_children: bool,
pub can_use_gpu: bool,
pub allowed_protocols: Vec<String>,
pub sandbox_level: u8,
}
impl Default for PermissionScope {
fn default() -> Self {
Self {
can_access_network: false,
can_access_filesystem: false,
can_spawn_children: false,
can_use_gpu: true,
allowed_protocols: vec!["http".to_string(), "https".to_string()],
sandbox_level: 5,
}
}
}
#[derive(Debug, Clone)]
pub struct Window {
pub id: u64,
pub iced_window_id: Option<WindowId>,
pub title: String,
pub app_id: String,
pub state: WindowState,
pub window_type: WindowType,
pub geometry: WindowGeometry,
pub parent_id: Option<u64>,
pub children_ids: Vec<u64>,
pub visible: bool,
pub focused: bool,
pub resource_limits: ResourceLimits,
pub permissions: PermissionScope,
pub manifest_path: Option<String>,
pub created_at: SystemTime,
pub last_activity: SystemTime,
pub backend_type: BackendType,
pub assignment_id: Option<u32>,
pub resource_mode: ResourceMode,
}
#[derive(Debug, Clone)]
pub struct ResourceUsage {
pub window_id: u64,
pub assignment_id: u32,
pub ram_allocated_mb: u64,
pub vram_allocated_mb: u64,
pub cpu_cores: Vec<usize>,
pub gpu_device: Option<String>,
pub task_active: bool,
pub gpu_active: bool,
pub remaining_lease_secs: u64,
pub execution_mode: ExecutionMode,
}
pub struct WindowHandler {
windows: Arc<Mutex<HashMap<u64, Window>>>,
next_id: Arc<Mutex<u64>>,
focused_window: Arc<Mutex<Option<u64>>>,
wbackend: Arc<WBackend>,
assignment_to_window: Arc<Mutex<HashMap<u32, u64>>>,
wasma_config: Arc<Mutex<Option<WasmaConfig>>>,
}
impl WindowHandler {
pub fn new(resource_mode: ResourceMode) -> Self {
Self {
windows: Arc::new(Mutex::new(HashMap::new())),
next_id: Arc::new(Mutex::new(1)),
focused_window: Arc::new(Mutex::new(None)),
wbackend: Arc::new(WBackend::new(resource_mode)),
assignment_to_window: Arc::new(Mutex::new(HashMap::new())),
wasma_config: Arc::new(Mutex::new(None)),
}
}
pub fn load_wasma_config(&self, config_path: &str) -> Result<(), String> {
let parser = ConfigParser::new(Some(config_path.to_string()));
let config = parser
.load()
.map_err(|e| format!("Config could not be loaded: {:?}", e))?;
parser
.validate(&config)
.map_err(|e| format!("Config is invalid: {:?}", e))?;
let mut wasma_cfg = self.wasma_config.lock().unwrap();
*wasma_cfg = Some(config);
println!("✅ WASMA Config loaded: {}", config_path);
Ok(())
}
pub fn create_window(
&self,
title: String,
app_id: String,
geometry: WindowGeometry,
manifest_path: Option<String>,
resource_mode: ResourceMode,
) -> Result<u64, String> {
let mut next_id = self.next_id.lock().unwrap();
let window_id = *next_id;
*next_id += 1;
let (mut resource_limits, mut permissions) = if let Some(ref path) = manifest_path {
self.load_manifest_and_source(path)?
} else {
(ResourceLimits::default(), PermissionScope::default())
};
if let Some(ref wasma_cfg) = *self.wasma_config.lock().unwrap() {
resource_limits.renderer = wasma_cfg.resource_limits.renderer.clone();
resource_limits.pixel_load_limit = wasma_cfg.resource_limits.scope_level;
for proto_cfg in &wasma_cfg.uri_handling.protocols {
let proto_str = match proto_cfg.protocol {
Protocol::Http => "http",
Protocol::Https => "https",
Protocol::Grpc => "grpc",
Protocol::Tor => "tor",
};
if !permissions.allowed_protocols.contains(&proto_str.to_string()) {
permissions.allowed_protocols.push(proto_str.to_string());
}
}
}
let assignment_id = window_id as u32;
let mut assignment = Assignment::new(assignment_id);
assignment.execution_mode = resource_limits
.execution_mode
.unwrap_or(ExecutionMode::GpuPreferred);
assignment.ram_limit = (resource_limits.max_memory_mb * 1024 * 1024) as usize;
assignment.vram_limit = (resource_limits.max_gpu_memory_mb * 1024 * 1024) as usize;
if !resource_limits.cpu_cores.is_empty() {
assignment.cpu_cores = resource_limits.cpu_cores.clone();
}
assignment.start_lease(resource_limits.lease_duration);
self.wbackend.add_assignment(assignment);
let mut mapping = self.assignment_to_window.lock().unwrap();
mapping.insert(assignment_id, window_id);
let window = Window {
id: window_id,
iced_window_id: None,
title,
app_id,
state: WindowState::Normal,
window_type: WindowType::Normal,
geometry,
parent_id: None,
children_ids: Vec::new(),
visible: true,
focused: false,
resource_limits,
permissions,
manifest_path,
created_at: SystemTime::now(),
last_activity: SystemTime::now(),
backend_type: BackendType::Native,
assignment_id: Some(assignment_id),
resource_mode,
};
let mut windows = self.windows.lock().unwrap();
windows.insert(window_id, window);
println!(
"🪟 Window {} created | Assignment {} | Mode: {:?}",
window_id, assignment_id, resource_mode
);
Ok(window_id)
}
fn load_manifest_and_source(
&self,
manifest_path: &str,
) -> Result<(ResourceLimits, PermissionScope), String> {
let parser = ManifestParser::new(manifest_path.to_string());
let manifest = parser
.load()
.map_err(|e| format!("Manifest could not be loaded: {:?}", e))?;
let limits = ResourceLimits {
cpu_cores: match manifest.resources.cpu_core_serve {
CpuCoreServe::Static(n) => (0..n as usize).collect(),
CpuCoreServe::Dynamic => Vec::new(),
CpuCoreServe::AffinityDefault => Vec::new(),
},
max_memory_mb: manifest.resources.ram_using.size,
max_gpu_memory_mb: manifest.resources.gpu_using.size,
execution_mode: Some(ExecutionMode::GpuPreferred),
..Default::default()
};
let source_parser = SourceParser::new(None);
let perms = if let Ok(Some(src)) = source_parser.load_embedded(&std::fs::read_to_string(manifest_path).unwrap_or_default()) {
self.parse_permissions(src)
} else {
PermissionScope::default()
};
Ok((limits, perms))
}
fn parse_permissions(&self, source: PermissionSource) -> PermissionScope {
PermissionScope {
can_access_network: source.network.ethernet || source.network.wifi,
can_access_filesystem: !matches!(source.filesystem.file_exception, FileException::None),
can_use_gpu: true,
allowed_protocols: vec!["http".to_string(), "https".to_string()],
..Default::default()
}
}
pub fn run_resource_cycle(&self) {
self.wbackend.run_cycle();
}
pub fn adjust_window_resources(
&self,
window_id: u64,
new_limits: ResourceLimits,
) -> Result<(), String> {
let mut windows = self.windows.lock().unwrap();
let window = windows
.get_mut(&window_id)
.ok_or_else(|| format!("Window {} not found", window_id))?;
if window.resource_mode != ResourceMode::Manual {
return Err(format!(
"Window {} is in Auto mode, manual adjustment not allowed",
window_id
));
}
window.resource_limits = new_limits.clone();
if let Some(assignment_id) = window.assignment_id {
if let Some(mut assignment) = self.wbackend.get_assignment(assignment_id) {
assignment.execution_mode = new_limits
.execution_mode
.unwrap_or(ExecutionMode::GpuPreferred);
assignment.ram_limit = (new_limits.max_memory_mb * 1024 * 1024) as usize;
assignment.vram_limit = (new_limits.max_gpu_memory_mb * 1024 * 1024) as usize;
if !new_limits.cpu_cores.is_empty() {
assignment.cpu_cores = new_limits.cpu_cores.clone();
assignment.bind_cpu();
}
if assignment.should_bind_gpu() {
assignment.bind_gpu();
}
}
}
Ok(())
}
pub fn get_window_resource_usage(&self, window_id: u64) -> Result<ResourceUsage, String> {
let windows = self.windows.lock().unwrap();
let window = windows
.get(&window_id)
.ok_or_else(|| format!("Window {} not found", window_id))?;
if let Some(assignment_id) = window.assignment_id {
if let Some(assignment) = self.wbackend.get_assignment(assignment_id) {
let gpu_active = assignment.gpu_device.is_some()
&& !matches!(assignment.execution_mode, ExecutionMode::CpuOnly);
let task_running = assignment.task_handle.is_some();
let remaining_lease = assignment
.lease_duration
.and_then(|d| {
assignment
.lease_start
.map(|s| d.as_secs().saturating_sub(s.elapsed().as_secs()))
})
.unwrap_or(0);
return Ok(ResourceUsage {
window_id,
assignment_id,
ram_allocated_mb: (assignment.ram_limit / (1024 * 1024)) as u64,
vram_allocated_mb: (assignment.vram_limit / (1024 * 1024)) as u64,
cpu_cores: assignment.cpu_cores.clone(),
gpu_device: assignment.gpu_device.clone(),
task_active: task_running,
gpu_active,
remaining_lease_secs: remaining_lease,
execution_mode: assignment.execution_mode,
});
}
}
Err(format!("Assignment not found: window {}", window_id))
}
pub fn set_window_state(&self, id: u64, state: WindowState) -> Result<(), String> {
let mut windows = self.windows.lock().unwrap();
if let Some(window) = windows.get_mut(&id) {
window.state = state;
window.last_activity = SystemTime::now();
Ok(())
} else {
Err(format!("Window {} not found", id))
}
}
pub fn set_geometry(&self, id: u64, geometry: WindowGeometry) -> Result<(), String> {
let mut windows = self.windows.lock().unwrap();
if let Some(window) = windows.get_mut(&id) {
window.geometry = geometry;
window.last_activity = SystemTime::now();
Ok(())
} else {
Err(format!("Window {} not found", id))
}
}
pub fn focus_window(&self, id: u64) -> Result<(), String> {
let mut windows = self.windows.lock().unwrap();
for window in windows.values_mut() {
window.focused = false;
}
if let Some(window) = windows.get_mut(&id) {
window.focused = true;
window.last_activity = SystemTime::now();
drop(windows);
let mut focused = self.focused_window.lock().unwrap();
*focused = Some(id);
Ok(())
} else {
Err(format!("Window {} not found", id))
}
}
pub fn close_window(&self, id: u64) -> Result<(), String> {
let mut windows = self.windows.lock().unwrap();
if let Some(window) = windows.get(&id).cloned() {
let assignment_id = window.assignment_id;
let children = window.children_ids.clone();
for child_id in children {
if let Some(child) = windows.get(&child_id) {
if let Some(child_assignment_id) = child.assignment_id {
if let Some(mut assignment) =
self.wbackend.get_assignment(child_assignment_id)
{
assignment.stop_task();
}
}
}
windows.remove(&child_id);
}
if let Some(parent_id) = window.parent_id {
if let Some(parent) = windows.get_mut(&parent_id) {
parent.children_ids.retain(|&cid| cid != id);
}
}
if let Some(aid) = assignment_id {
if let Some(mut assignment) = self.wbackend.get_assignment(aid) {
assignment.stop_task();
}
let mut mapping = self.assignment_to_window.lock().unwrap();
mapping.remove(&aid);
}
windows.remove(&id);
println!("🗑️ Window {} closed", id);
Ok(())
} else {
Err(format!("Window {} not found", id))
}
}
pub fn set_parent(&self, child_id: u64, parent_id: u64) -> Result<(), String> {
let mut windows = self.windows.lock().unwrap();
if !windows.contains_key(&parent_id) {
return Err(format!("Parent window {} not found", parent_id));
}
if let Some(child) = windows.get_mut(&child_id) {
child.parent_id = Some(parent_id);
} else {
return Err(format!("Child window {} not found", child_id));
}
if let Some(parent) = windows.get_mut(&parent_id) {
if !parent.children_ids.contains(&child_id) {
parent.children_ids.push(child_id);
}
}
Ok(())
}
pub fn get_window(&self, id: u64) -> Option<Window> {
let windows = self.windows.lock().unwrap();
windows.get(&id).cloned()
}
pub fn list_windows(&self) -> Vec<Window> {
let windows = self.windows.lock().unwrap();
windows.values().cloned().collect()
}
pub fn get_focused_window(&self) -> Option<u64> {
let focused = self.focused_window.lock().unwrap();
*focused
}
}
#[derive(Debug, Clone)]
pub enum Message {
AppNameChanged(String),
BackendSelected(crate::backend_selector::Backend),
LaunchApp,
#[cfg(debug_assertions)]
CreateFakeWindow,
KillApp(u64),
CloseWindow(u64),
FocusWindow(u64),
MinimizeWindow(u64),
MaximizeWindow(u64),
ToggleFullscreen(u64),
HideWindow(u64),
UpdateResourceCycle,
AdjustResources(u64),
ChangeExecutionMode(u64, ExecutionMode),
}
pub struct WasmaWindowManager {
handler: Arc<WindowHandler>,
window_client: Arc<Mutex<WindowClient>>,
selected_window: Option<u64>,
app_name_input: String,
selected_backend: crate::backend_selector::Backend,
launch_error: Option<String>,
}
impl Application for WasmaWindowManager {
type Executor = executor::Default;
type Message = Message;
type Theme = Theme;
type Flags = ResourceMode;
fn new(flags: Self::Flags) -> (Self, Command<Message>) {
let handler = Arc::new(WindowHandler::new(flags));
let parser = ConfigParser::new(None);
let config = parser
.parse(&parser.generate_default_config())
.unwrap_or_else(|_| panic!("Default config parse failed"));
let window_client = Arc::new(Mutex::new(WindowClient::new(config, 1280, 800)));
if let Err(e) = handler.load_wasma_config("/etc/wasma/wasma.in.conf") {
eprintln!("⚠️ WASMA config could not be loaded: {}", e);
}
(
WasmaWindowManager {
handler,
window_client,
selected_window: None,
app_name_input: String::new(),
selected_backend: crate::backend_selector::Backend::X11,
launch_error: None,
},
Command::none(),
)
}
fn title(&self) -> String {
String::from("WASMA — Window Assignment System Monitoring Architecture")
}
fn update(&mut self, message: Message) -> Command<Message> {
match message {
Message::AppNameChanged(s) => {
self.app_name_input = s;
self.launch_error = None;
Command::none()
}
Message::BackendSelected(backend) => {
self.selected_backend = backend;
Command::none()
}
Message::LaunchApp => {
let name = self.app_name_input.trim().to_string();
if name.is_empty() {
self.launch_error = Some("App name cannot be empty.".to_string());
return Command::none();
}
let geometry = WindowGeometry {
x: 100,
y: 100,
width: 800,
height: 600,
};
match self.handler.create_window(
name.clone(),
name.clone(),
geometry,
None,
ResourceMode::Auto,
) {
Ok(window_id) => {
let wc = self.window_client.lock().unwrap();
match wc.launch_app_with_backend(window_id, &name, false, Some(self.selected_backend)) {
Ok(_) => {
self.app_name_input.clear();
self.launch_error = None;
println!("✅ Launched '{}' → window_id={} backend={}", name, window_id, self.selected_backend);
}
Err(e) => {
drop(wc);
let _ = self.handler.close_window(window_id);
self.launch_error = Some(format!("Launch failed: {}", e));
}
}
}
Err(e) => {
self.launch_error = Some(format!("Window creation failed: {}", e));
}
}
Command::none()
}
#[cfg(debug_assertions)]
Message::CreateFakeWindow => {
let geometry = WindowGeometry {
x: 100,
y: 100,
width: 800,
height: 600,
};
match self.handler.create_window(
format!(
"Debug Window {}",
self.handler.list_windows().len() + 1
),
"debug.fake.app".to_string(),
geometry,
None,
ResourceMode::Auto,
) {
Ok(id) => println!("🐛 Debug fake window created: {}", id),
Err(e) => eprintln!("❌ Fake window error: {}", e),
}
Command::none()
}
Message::KillApp(id) => {
let wc = self.window_client.lock().unwrap();
if let Err(e) = wc.kill_app(id) {
eprintln!("⚠️ kill_app {}: {}", id, e);
}
drop(wc);
if let Err(e) = self.handler.close_window(id) {
eprintln!("⚠️ close_window {}: {}", id, e);
}
if self.selected_window == Some(id) {
self.selected_window = None;
}
Command::none()
}
Message::CloseWindow(id) => {
if let Err(e) = self.handler.close_window(id) {
eprintln!("❌ Could not close window {}: {}", id, e);
}
if self.selected_window == Some(id) {
self.selected_window = None;
}
Command::none()
}
Message::FocusWindow(id) => {
let wc = self.window_client.lock().unwrap();
if let Err(e) = wc.set_focus(id) {
eprintln!("❌ Could not focus {}: {}", id, e);
}
drop(wc);
self.handler.set_window_state(id, WindowState::Normal).ok();
self.selected_window = Some(id);
Command::none()
}
Message::MinimizeWindow(id) => {
let wc = self.window_client.lock().unwrap();
if let Err(e) = wc.minimize(id) {
eprintln!("⚠️ minimize via x11rb failed: {}", e);
}
drop(wc);
self.handler.set_window_state(id, WindowState::Minimized).ok();
Command::none()
}
Message::MaximizeWindow(id) => {
let wc = self.window_client.lock().unwrap();
if let Err(e) = wc.maximize(id) {
eprintln!("⚠️ maximize via x11rb failed: {}", e);
}
drop(wc);
self.handler.set_window_state(id, WindowState::Maximized).ok();
Command::none()
}
Message::ToggleFullscreen(id) => {
if let Some(window) = self.handler.get_window(id) {
let new_state = if window.state == WindowState::Fullscreen {
WindowState::Normal
} else {
WindowState::Fullscreen
};
let wc = self.window_client.lock().unwrap();
if let Err(e) = wc.toggle_fullscreen(id) {
eprintln!("⚠️ fullscreen toggle via x11rb failed: {}", e);
}
drop(wc);
self.handler.set_window_state(id, new_state).ok();
}
Command::none()
}
Message::HideWindow(id) => {
let wc = self.window_client.lock().unwrap();
if let Err(e) = wc.hide(id) {
eprintln!("⚠️ hide via x11rb failed: {}", e);
}
drop(wc);
self.handler.set_window_state(id, WindowState::Hidden).ok();
Command::none()
}
Message::UpdateResourceCycle => {
let wc = self.window_client.lock().unwrap();
wc.reap_dead();
drop(wc);
self.handler.run_resource_cycle();
Command::none()
}
Message::AdjustResources(id) => {
println!("🔧 Resource adjustment requested: window {}", id);
Command::none()
}
Message::ChangeExecutionMode(id, mode) => {
if let Some(window) = self.handler.get_window(id) {
let mut new_limits = window.resource_limits.clone();
new_limits.execution_mode = Some(mode);
if let Err(e) = self.handler.adjust_window_resources(id, new_limits) {
eprintln!("❌ Execution mode change failed: {}", e);
}
}
Command::none()
}
}
}
fn view(&self) -> Element<'_, Message> {
let windows = self.handler.list_windows();
let launch_input = text_input("App name (e.g. firefox, alacritty...)", &self.app_name_input)
.on_input(Message::AppNameChanged)
.on_submit(Message::LaunchApp)
.width(Length::Fixed(320.0));
let backend_options = vec![
crate::backend_selector::Backend::X11,
crate::backend_selector::Backend::Wayland,
];
let backend_pick = iced::widget::pick_list(
backend_options,
Some(self.selected_backend),
Message::BackendSelected,
)
.width(Length::Fixed(120.0));
let launch_btn = button("Launch").on_press(Message::LaunchApp);
let launcher_row = {
let row = row![launch_input, backend_pick, launch_btn].spacing(8).align_items(iced::Alignment::Center);
#[cfg(debug_assertions)]
{
row.push(button("+ Fake (debug)").on_press(Message::CreateFakeWindow))
}
#[cfg(not(debug_assertions))]
{
row
}
};
let error_element: Element<Message> = if let Some(ref err) = self.launch_error {
text(format!("⚠️ {}", err))
.size(13)
.style(Color::from_rgb(1.0, 0.35, 0.35))
.into()
} else {
Space::with_height(Length::Fixed(0.0)).into()
};
let header = column![
row![
text("WASMA Window Manager")
.size(22)
.style(Color::from_rgb(0.2, 0.6, 1.0)),
Space::with_width(Length::Fill),
button("⟳ Resource Cycle").on_press(Message::UpdateResourceCycle),
]
.spacing(10)
.padding(20),
row![
Space::with_width(Length::Fixed(20.0)),
launcher_row,
]
.padding([0, 0, 4, 0]),
row![
Space::with_width(Length::Fixed(20.0)),
error_element,
]
.padding([0, 0, 8, 0]),
];
let mut window_list = column![].spacing(10).padding(20);
if windows.is_empty() {
window_list = window_list.push(
text("No active windows. Type an app name above and press Launch.")
.size(15)
.style(Color::from_rgb(0.5, 0.5, 0.5)),
);
} else {
for window in &windows {
let is_selected = self.selected_window == Some(window.id);
let card = self.create_window_card(window, is_selected);
window_list = window_list.push(card);
}
}
let content = column![header, scrollable(window_list)];
container(content)
.width(Length::Fill)
.height(Length::Fill)
.into()
}
}
impl WasmaWindowManager {
fn create_window_card(&self, window: &Window, is_selected: bool) -> Element<'_, Message> {
let state_icon = match window.state {
WindowState::Normal => "🟢",
WindowState::Minimized => "🟡",
WindowState::Maximized => "🔵",
WindowState::Fullscreen => "⚡",
WindowState::Hidden => "⚫",
};
let focus_indicator = if window.focused { "👁️ " } else { "" };
let is_fake = window.app_id == "debug.fake.app";
let close_kill_btn = if is_fake {
button("✕ Close").on_press(Message::CloseWindow(window.id))
} else {
button("✕ Kill").on_press(Message::KillApp(window.id))
};
let title_section = row![
text(format!("{}{} {}", focus_indicator, state_icon, window.title))
.size(18)
.style(if is_selected {
Color::from_rgb(0.8, 0.9, 1.0)
} else {
Color::from_rgb(0.9, 0.9, 0.9)
}),
Space::with_width(Length::Fill),
button("Focus").on_press(Message::FocusWindow(window.id)),
button("Min").on_press(Message::MinimizeWindow(window.id)),
button("Max").on_press(Message::MaximizeWindow(window.id)),
button("FS").on_press(Message::ToggleFullscreen(window.id)),
button("Hide").on_press(Message::HideWindow(window.id)),
close_kill_btn,
]
.spacing(6)
.align_items(iced::Alignment::Center)
.padding([0, 0, 8, 0]);
let details_section = if let Ok(usage) = self.handler.get_window_resource_usage(window.id) {
let mode_str = match usage.execution_mode {
ExecutionMode::CpuOnly => "CPU-Only",
ExecutionMode::GpuPreferred => "GPU Preferred",
ExecutionMode::GpuOnly => "GPU-Only",
ExecutionMode::Hybrid => "Hybrid",
};
let status_str = if usage.task_active { "RUNNING" } else { "STOPPED" };
column![
row![
text(format!("ID: {} | Assignment: {}", window.id, usage.assignment_id)).size(12),
Space::with_width(Length::Fill),
text(format!("{} | {}", mode_str, status_str))
.size(12)
.style(if usage.task_active {
Color::from_rgb(0.4, 0.8, 0.4)
} else {
Color::from_rgb(0.8, 0.6, 0.2)
}),
]
.align_items(iced::Alignment::Center),
row![
text(format!(
"RAM: {} MiB | VRAM: {} MiB | Cores: {:?}",
usage.ram_allocated_mb, usage.vram_allocated_mb, usage.cpu_cores
))
.size(12),
Space::with_width(Length::Fill),
text(format!(
"Renderer: {} | {}x{}",
window.resource_limits.renderer, window.geometry.width, window.geometry.height
))
.size(12),
]
.align_items(iced::Alignment::Center),
]
.spacing(4)
} else {
column![text("No resource info").size(12)]
};
let card_content = column![title_section, details_section]
.spacing(10)
.padding(14);
let border_color = if is_selected {
Color::from_rgb(0.3, 0.7, 1.0)
} else if is_fake {
Color::from_rgb(0.7, 0.5, 0.2)
} else {
Color::from_rgb(0.4, 0.4, 0.4)
};
let bg_color = if is_selected {
Color::from_rgb(0.25, 0.35, 0.45)
} else {
Color::from_rgb(0.18, 0.18, 0.18)
};
container(card_content)
.width(Length::Fill)
.style(move |_theme: &Theme| container::Appearance {
background: Some(Background::Color(bg_color)),
border: iced::Border {
color: border_color,
width: 2.0,
radius: 6.0.into(),
},
..Default::default()
})
.into()
}
}
pub fn launch_window_manager(resource_mode: ResourceMode) -> iced::Result {
WasmaWindowManager::run(Settings {
window: window::Settings {
size: [1200.0, 800.0].into(),
position: Position::Centered,
..Default::default()
},
flags: resource_mode,
fonts: vec![],
antialiasing: true,
default_font: Default::default(),
default_text_size: iced::Pixels(16.0),
id: None,
})
}
#[cfg(test)]
mod tests {
use super::*;
fn make_handler() -> WindowHandler {
WindowHandler::new(ResourceMode::Auto)
}
fn make_geo() -> WindowGeometry {
WindowGeometry { x: 0, y: 0, width: 800, height: 600 }
}
#[test]
fn test_window_creation() {
let handler = make_handler();
let id = handler
.create_window("Test".to_string(), "test.app".to_string(), make_geo(), None, ResourceMode::Auto)
.unwrap();
assert!(handler.get_window(id).is_some());
println!("✅ Window creation: id={}", id);
}
#[test]
fn test_window_lifecycle() {
let handler = make_handler();
let id = handler
.create_window("Test".to_string(), "test.app".to_string(), make_geo(), None, ResourceMode::Auto)
.unwrap();
handler.focus_window(id).unwrap();
assert_eq!(handler.get_focused_window(), Some(id));
handler.close_window(id).unwrap();
assert!(handler.get_window(id).is_none());
println!("✅ Window lifecycle complete");
}
#[test]
fn test_resource_adjustment() {
let handler = WindowHandler::new(ResourceMode::Manual);
let id = handler
.create_window("Res".to_string(), "res.app".to_string(), make_geo(), None, ResourceMode::Manual)
.unwrap();
let mut limits = ResourceLimits::default();
limits.max_memory_mb = 1024;
limits.execution_mode = Some(ExecutionMode::GpuOnly);
handler.adjust_window_resources(id, limits.clone()).unwrap();
let w = handler.get_window(id).unwrap();
assert_eq!(w.resource_limits.max_memory_mb, 1024);
println!("✅ Resource adjustment OK");
}
#[test]
fn test_parent_child() {
let handler = make_handler();
let parent = handler
.create_window("Parent".to_string(), "p.app".to_string(), make_geo(), None, ResourceMode::Auto)
.unwrap();
let child = handler
.create_window("Child".to_string(), "c.app".to_string(), make_geo(), None, ResourceMode::Auto)
.unwrap();
handler.set_parent(child, parent).unwrap();
assert!(handler.get_window(parent).unwrap().children_ids.contains(&child));
assert_eq!(handler.get_window(child).unwrap().parent_id, Some(parent));
println!("✅ Parent-child relationship OK");
}
}