use std::collections::HashMap;
use std::os::unix::io::RawFd;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
use crate::parser::WasmaConfig;
use crate::uclient::SectionMemory;
use crate::wasma_client_unix_posix_raw_app::{posix, RawAppSource, UClientEngine};
use crate::window_client::WindowClient;
use crate::window_handling::{WindowGeometry, WindowState, WindowType};
pub const WASMA_CMD_MAGIC: [u8; 4] = [0x57, 0x41, 0x57, 0x4D]; pub const WASMA_RSP_MAGIC: [u8; 4] = [0x57, 0x52, 0x53, 0x50]; pub const WASMA_HDR_SIZE: usize = 16;
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RawWindowCommand {
CreateWindow = 0x01,
DestroyWindow = 0x02,
SetGeometry = 0x03,
GetGeometry = 0x04,
SetState = 0x05,
GetState = 0x06,
SetFocus = 0x07,
GetFocus = 0x08,
SetTitle = 0x09,
SetParent = 0x0A,
ListWindows = 0x0B,
SetVisible = 0x0C,
SetType = 0x0D,
Ping = 0xFF,
}
impl RawWindowCommand {
pub fn from_u32(v: u32) -> Option<Self> {
match v {
0x01 => Some(Self::CreateWindow),
0x02 => Some(Self::DestroyWindow),
0x03 => Some(Self::SetGeometry),
0x04 => Some(Self::GetGeometry),
0x05 => Some(Self::SetState),
0x06 => Some(Self::GetState),
0x07 => Some(Self::SetFocus),
0x08 => Some(Self::GetFocus),
0x09 => Some(Self::SetTitle),
0x0A => Some(Self::SetParent),
0x0B => Some(Self::ListWindows),
0x0C => Some(Self::SetVisible),
0x0D => Some(Self::SetType),
0xFF => Some(Self::Ping),
_ => None,
}
}
pub fn to_u32(self) -> u32 {
self as u32
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RawWindowStatus {
Ok = 0x00,
ErrNotFound = 0x01,
ErrInvalidParam = 0x02,
ErrPermission = 0x03,
ErrInternal = 0x04,
Pong = 0xFF,
}
impl RawWindowStatus {
pub fn from_u32(v: u32) -> Self {
match v {
0x00 => Self::Ok,
0x01 => Self::ErrNotFound,
0x02 => Self::ErrInvalidParam,
0x03 => Self::ErrPermission,
0x04 => Self::ErrInternal,
0xFF => Self::Pong,
_ => Self::ErrInternal,
}
}
}
pub struct RawWindowFd {
ctrl_fd: Option<RawFd>,
source: RawAppSource,
connected: bool,
}
impl RawWindowFd {
pub fn new(source: RawAppSource) -> Self {
Self {
ctrl_fd: None,
source,
connected: false,
}
}
pub fn connect(&mut self) -> Result<(), std::io::Error> {
if self.connected {
return Ok(());
}
let fd = match &self.source {
RawAppSource::UnixSocket(path) => self.open_unix_socket(path)?,
RawAppSource::TcpSocket { ip, port } => self.open_tcp(ip, *port)?,
RawAppSource::NamedPipe(path) => posix::posix_open(path, libc::O_RDWR)?,
RawAppSource::CharDevice(path) => posix::posix_open(path, libc::O_RDWR)?,
RawAppSource::Stdin => 0,
};
self.ctrl_fd = Some(fd);
self.connected = true;
println!("🔗 RawWindowFd: Connected → {}", self.source.display_name());
Ok(())
}
fn open_unix_socket(&self, path: &str) -> Result<RawFd, std::io::Error> {
use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixStream;
let stream = UnixStream::connect(path)?;
let fd = stream.as_raw_fd();
let _ = std::mem::ManuallyDrop::new(stream);
Ok(fd)
}
fn open_tcp(&self, ip: &str, port: u16) -> Result<RawFd, std::io::Error> {
use std::net::TcpStream;
use std::os::unix::io::AsRawFd;
let stream = TcpStream::connect(format!("{}:{}", ip, port))?;
let fd = stream.as_raw_fd();
let _ = std::mem::ManuallyDrop::new(stream);
Ok(fd)
}
fn write_header(
&self,
fd: RawFd,
cmd: RawWindowCommand,
window_id: u32,
payload_len: u32,
) -> Result<(), std::io::Error> {
let mut hdr = [0u8; WASMA_HDR_SIZE];
hdr[0..4].copy_from_slice(&WASMA_CMD_MAGIC);
hdr[4..8].copy_from_slice(&cmd.to_u32().to_le_bytes());
hdr[8..12].copy_from_slice(&window_id.to_le_bytes());
hdr[12..16].copy_from_slice(&payload_len.to_le_bytes());
let mut written = 0;
while written < WASMA_HDR_SIZE {
let n = unsafe {
libc::write(
fd,
hdr[written..].as_ptr() as *const libc::c_void,
WASMA_HDR_SIZE - written,
)
};
match n {
-1 => return Err(std::io::Error::last_os_error()),
0 => {
return Err(std::io::Error::new(
std::io::ErrorKind::WriteZero,
"write() sıfır byte yazdı",
))
}
n => written += n as usize,
}
}
Ok(())
}
fn write_payload(&self, fd: RawFd, payload: &[u8]) -> Result<(), std::io::Error> {
let mut written = 0;
while written < payload.len() {
let n = unsafe {
libc::write(
fd,
payload[written..].as_ptr() as *const libc::c_void,
payload.len() - written,
)
};
match n {
-1 => return Err(std::io::Error::last_os_error()),
0 => {
return Err(std::io::Error::new(
std::io::ErrorKind::WriteZero,
"write() sıfır byte yazdı",
))
}
n => written += n as usize,
}
}
Ok(())
}
fn read_response_header(
&self,
fd: RawFd,
) -> Result<(RawWindowStatus, u32, u32), std::io::Error> {
let mut hdr = [0u8; WASMA_HDR_SIZE];
posix::posix_read_exact(fd, &mut hdr)?;
if hdr[0..4] != WASMA_RSP_MAGIC {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("Geçersiz yanıt magic: {:?}", &hdr[0..4]),
));
}
let status = RawWindowStatus::from_u32(u32::from_le_bytes(hdr[4..8].try_into().unwrap()));
let window_id = u32::from_le_bytes(hdr[8..12].try_into().unwrap());
let payload_len = u32::from_le_bytes(hdr[12..16].try_into().unwrap());
Ok((status, window_id, payload_len))
}
pub fn send_command(
&self,
cmd: RawWindowCommand,
window_id: u32,
payload: &[u8],
) -> Result<(RawWindowStatus, Vec<u8>), std::io::Error> {
let fd = self.ctrl_fd.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::NotConnected,
"Kontrol kanalı açık değil",
)
})?;
self.write_header(fd, cmd, window_id, payload.len() as u32)?;
if !payload.is_empty() {
self.write_payload(fd, payload)?;
}
let (status, _resp_wid, payload_len) = self.read_response_header(fd)?;
let mut resp_payload = vec![0u8; payload_len as usize];
if payload_len > 0 {
posix::posix_read_exact(fd, &mut resp_payload)?;
}
Ok((status, resp_payload))
}
pub fn is_connected(&self) -> bool {
self.connected
}
}
impl Drop for RawWindowFd {
fn drop(&mut self) {
if let Some(fd) = self.ctrl_fd.take() {
if fd != 0 {
let _ = posix::posix_close(fd);
}
}
}
}
#[derive(Debug, Clone)]
pub struct RawWindowRecord {
pub id: u64,
pub title: String,
pub app_id: String,
pub geometry: WindowGeometry,
pub state: WindowState,
pub window_type: WindowType,
pub visible: bool,
pub focused: bool,
pub parent_id: Option<u64>,
pub children: Vec<u64>,
pub created_at: SystemTime,
pub last_modified: SystemTime,
}
impl RawWindowRecord {
pub fn new(id: u64, title: impl Into<String>, app_id: impl Into<String>) -> Self {
let now = SystemTime::now();
Self {
id,
title: title.into(),
app_id: app_id.into(),
geometry: WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
},
state: WindowState::Normal,
window_type: WindowType::Normal,
visible: true,
focused: false,
parent_id: None,
children: Vec::new(),
created_at: now,
last_modified: now,
}
}
pub fn touch(&mut self) {
self.last_modified = SystemTime::now();
}
}
pub mod geometry_codec {
use crate::window_handling::WindowGeometry;
pub const GEOMETRY_SIZE: usize = 16;
pub fn encode(g: &WindowGeometry) -> [u8; GEOMETRY_SIZE] {
let mut buf = [0u8; GEOMETRY_SIZE];
buf[0..4].copy_from_slice(&g.x.to_le_bytes());
buf[4..8].copy_from_slice(&g.y.to_le_bytes());
buf[8..12].copy_from_slice(&g.width.to_le_bytes());
buf[12..16].copy_from_slice(&g.height.to_le_bytes());
buf
}
pub fn decode(buf: &[u8]) -> Option<WindowGeometry> {
if buf.len() < GEOMETRY_SIZE {
return None;
}
Some(WindowGeometry {
x: i32::from_le_bytes(buf[0..4].try_into().ok()?),
y: i32::from_le_bytes(buf[4..8].try_into().ok()?),
width: u32::from_le_bytes(buf[8..12].try_into().ok()?),
height: u32::from_le_bytes(buf[12..16].try_into().ok()?),
})
}
}
pub mod state_codec {
use crate::window_handling::WindowState;
pub fn encode(s: &WindowState) -> u8 {
match s {
WindowState::Normal => 0x00,
WindowState::Minimized => 0x01,
WindowState::Maximized => 0x02,
WindowState::Fullscreen => 0x03,
WindowState::Hidden => 0x04,
}
}
pub fn decode(v: u8) -> WindowState {
match v {
0x00 => WindowState::Normal,
0x01 => WindowState::Minimized,
0x02 => WindowState::Maximized,
0x03 => WindowState::Fullscreen,
0x04 => WindowState::Hidden,
_ => WindowState::Normal,
}
}
}
pub struct RawWindowClient {
config: Arc<WasmaConfig>,
fd_manager: RawWindowFd,
window_registry: Arc<Mutex<HashMap<u64, RawWindowRecord>>>,
next_id: Arc<Mutex<u64>>,
window_client: Option<Arc<Mutex<WindowClient>>>,
active: bool,
memory: SectionMemory,
}
impl RawWindowClient {
pub fn new(config: WasmaConfig) -> Self {
let level = config.resource_limits.scope_level;
let source = RawAppSource::UnixSocket("/run/wasma/window.sock".to_string());
Self {
fd_manager: RawWindowFd::new(source),
window_registry: Arc::new(Mutex::new(HashMap::new())),
next_id: Arc::new(Mutex::new(1)),
window_client: None,
active: false,
memory: SectionMemory::new(level),
config: Arc::new(config),
}
}
pub fn from_config(config: Arc<WasmaConfig>) -> Self {
let level = config.resource_limits.scope_level;
let source = RawAppSource::UnixSocket("/run/wasma/window.sock".to_string());
Self {
fd_manager: RawWindowFd::new(source),
window_registry: Arc::new(Mutex::new(HashMap::new())),
next_id: Arc::new(Mutex::new(1)),
window_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!("🔗 RawWindowClient: WindowClient attached (rendering delegated)");
}
pub fn with_source(mut self, source: RawAppSource) -> Self {
self.fd_manager = RawWindowFd::new(source);
self
}
fn next_window_id(&self) -> u64 {
let mut id = self.next_id.lock().unwrap();
let current = *id;
*id += 1;
current
}
pub fn create_window(
&self,
title: impl Into<String>,
app_id: impl Into<String>,
geometry: WindowGeometry,
window_type: WindowType,
) -> Result<u64, String> {
let title = title.into();
let app_id = app_id.into();
let window_id = self.next_window_id();
let title_bytes = title.as_bytes();
let app_id_bytes = app_id.as_bytes();
let mut payload = Vec::with_capacity(
geometry_codec::GEOMETRY_SIZE + 2 + title_bytes.len() + 2 + app_id_bytes.len() + 1,
);
payload.extend_from_slice(&geometry_codec::encode(&geometry));
payload.extend_from_slice(&(title_bytes.len() as u16).to_le_bytes());
payload.extend_from_slice(title_bytes);
payload.extend_from_slice(&(app_id_bytes.len() as u16).to_le_bytes());
payload.extend_from_slice(app_id_bytes);
payload.push(state_codec::encode(&WindowState::Normal));
let remote_ok = if self.fd_manager.is_connected() {
match self.fd_manager.send_command(
RawWindowCommand::CreateWindow,
window_id as u32,
&payload,
) {
Ok((RawWindowStatus::Ok, _)) => true,
Ok((status, _)) => {
eprintln!("⚠️ CreateWindow server error: {:?}", status);
false
}
Err(e) => {
eprintln!("⚠️ CreateWindow communication error: {}", e);
false
}
}
} else {
true };
if remote_ok {
let mut record = RawWindowRecord::new(window_id, &title, &app_id);
record.geometry = geometry;
record.window_type = window_type;
let mut registry = self.window_registry.lock().unwrap();
registry.insert(window_id, record);
println!(
"🪟 RawWindowClient: Window {} created [{}x{} @ ({},{})]",
window_id, geometry.width, geometry.height, geometry.x, geometry.y
);
Ok(window_id)
} else {
Err(format!("Window {} could not be created", window_id))
}
}
pub fn destroy_window(&self, window_id: u64) -> Result<(), String> {
let children: Vec<u64> = {
let registry = self.window_registry.lock().unwrap();
registry
.get(&window_id)
.map(|r| r.children.clone())
.unwrap_or_default()
};
for child_id in children {
self.destroy_window(child_id)?;
}
let parent_id = {
let registry = self.window_registry.lock().unwrap();
registry.get(&window_id).and_then(|r| r.parent_id)
};
if let Some(pid) = parent_id {
let mut registry = self.window_registry.lock().unwrap();
if let Some(parent) = registry.get_mut(&pid) {
parent.children.retain(|&id| id != window_id);
parent.touch();
}
}
if self.fd_manager.is_connected() {
let _ = self.fd_manager.send_command(
RawWindowCommand::DestroyWindow,
window_id as u32,
&[],
);
}
let mut registry = self.window_registry.lock().unwrap();
if registry.remove(&window_id).is_some() {
println!("🗑️ RawWindowClient: Window {} closed", window_id);
Ok(())
} else {
Err(format!("Pencere {} bulunamadı", window_id))
}
}
pub fn set_geometry(&self, window_id: u64, geometry: WindowGeometry) -> Result<(), String> {
let payload = geometry_codec::encode(&geometry);
if self.fd_manager.is_connected() {
match self.fd_manager.send_command(
RawWindowCommand::SetGeometry,
window_id as u32,
&payload,
) {
Ok((RawWindowStatus::Ok, _)) => {}
Ok((status, _)) => return Err(format!("SetGeometry hatası: {:?}", status)),
Err(e) => return Err(format!("SetGeometry iletişim hatası: {}", e)),
}
}
let mut registry = self.window_registry.lock().unwrap();
match registry.get_mut(&window_id) {
Some(record) => {
record.geometry = geometry;
record.touch();
println!(
"📐 Window {} geometry updated: {}x{} @ ({},{})",
window_id, geometry.width, geometry.height, geometry.x, geometry.y
);
if let Some(ref wc) = self.window_client {
let mut client = wc.lock().unwrap();
client.resize(geometry.width, geometry.height);
}
Ok(())
}
None => Err(format!("Pencere {} bulunamadı", window_id)),
}
}
pub fn get_geometry(&self, window_id: u64) -> Result<WindowGeometry, String> {
{
let registry = self.window_registry.lock().unwrap();
if let Some(record) = registry.get(&window_id) {
return Ok(record.geometry);
}
}
if self.fd_manager.is_connected() {
match self
.fd_manager
.send_command(RawWindowCommand::GetGeometry, window_id as u32, &[])
{
Ok((RawWindowStatus::Ok, payload)) => geometry_codec::decode(&payload)
.ok_or_else(|| "Geometry decode hatası".to_string()),
Ok((status, _)) => Err(format!("GetGeometry sunucu hatası: {:?}", status)),
Err(e) => Err(format!("GetGeometry iletişim hatası: {}", e)),
}
} else {
Err(format!("Pencere {} bulunamadı", window_id))
}
}
pub fn set_state(&self, window_id: u64, state: WindowState) -> Result<(), String> {
let payload = [state_codec::encode(&state)];
if self.fd_manager.is_connected() {
match self.fd_manager.send_command(
RawWindowCommand::SetState,
window_id as u32,
&payload,
) {
Ok((RawWindowStatus::Ok, _)) => {}
Ok((status, _)) => return Err(format!("SetState hatası: {:?}", status)),
Err(e) => return Err(format!("SetState iletişim hatası: {}", e)),
}
}
let mut registry = self.window_registry.lock().unwrap();
match registry.get_mut(&window_id) {
Some(record) => {
record.state = state.clone();
record.touch();
println!("🔄 Window {} state: {:?}", window_id, state);
Ok(())
}
None => Err(format!("Pencere {} bulunamadı", window_id)),
}
}
pub fn get_state(&self, window_id: u64) -> Result<WindowState, String> {
let registry = self.window_registry.lock().unwrap();
match registry.get(&window_id) {
Some(record) => Ok(record.state.clone()),
None => Err(format!("Pencere {} bulunamadı", window_id)),
}
}
pub fn set_focus(&self, window_id: u64) -> Result<(), String> {
{
let mut registry = self.window_registry.lock().unwrap();
for record in registry.values_mut() {
record.focused = false;
}
}
if self.fd_manager.is_connected() {
let _ = self
.fd_manager
.send_command(RawWindowCommand::SetFocus, window_id as u32, &[]);
}
let mut registry = self.window_registry.lock().unwrap();
match registry.get_mut(&window_id) {
Some(record) => {
record.focused = true;
record.touch();
println!("👁️ Window {} focused", window_id);
Ok(())
}
None => Err(format!("Pencere {} bulunamadı", window_id)),
}
}
pub fn get_focused_window(&self) -> Option<u64> {
let registry = self.window_registry.lock().unwrap();
registry.values().find(|r| r.focused).map(|r| r.id)
}
pub fn set_title(&self, window_id: u64, title: impl Into<String>) -> Result<(), String> {
let title = title.into();
let title_bytes = title.as_bytes();
if self.fd_manager.is_connected() {
let mut payload = Vec::with_capacity(2 + title_bytes.len());
payload.extend_from_slice(&(title_bytes.len() as u16).to_le_bytes());
payload.extend_from_slice(title_bytes);
let _ = self.fd_manager.send_command(
RawWindowCommand::SetTitle,
window_id as u32,
&payload,
);
}
let mut registry = self.window_registry.lock().unwrap();
match registry.get_mut(&window_id) {
Some(record) => {
record.title = title.clone();
record.touch();
println!("📝 Window {} title: \"{}\"", window_id, title);
Ok(())
}
None => Err(format!("Pencere {} bulunamadı", window_id)),
}
}
pub fn set_visible(&self, window_id: u64, visible: bool) -> Result<(), String> {
if self.fd_manager.is_connected() {
let _ = self.fd_manager.send_command(
RawWindowCommand::SetVisible,
window_id as u32,
&[visible as u8],
);
}
let mut registry = self.window_registry.lock().unwrap();
match registry.get_mut(&window_id) {
Some(record) => {
record.visible = visible;
record.touch();
println!("👀 Window {} visibility: {}", window_id, visible);
Ok(())
}
None => Err(format!("Pencere {} bulunamadı", window_id)),
}
}
pub fn set_parent(&self, child_id: u64, parent_id: u64) -> Result<(), String> {
{
let registry = self.window_registry.lock().unwrap();
if !registry.contains_key(&parent_id) {
return Err(format!("Ebeveyn pencere {} bulunamadı", parent_id));
}
}
if self.fd_manager.is_connected() {
let payload = (parent_id as u32).to_le_bytes();
let _ = self.fd_manager.send_command(
RawWindowCommand::SetParent,
child_id as u32,
&payload,
);
}
let mut registry = self.window_registry.lock().unwrap();
if let Some(child) = registry.get_mut(&child_id) {
child.parent_id = Some(parent_id);
child.touch();
} else {
return Err(format!("Çocuk pencere {} bulunamadı", child_id));
}
if let Some(parent) = registry.get_mut(&parent_id) {
if !parent.children.contains(&child_id) {
parent.children.push(child_id);
}
parent.touch();
}
println!("👨👧 Window {} → parent {}", child_id, parent_id);
Ok(())
}
pub fn list_windows(&self) -> Vec<RawWindowRecord> {
let registry = self.window_registry.lock().unwrap();
let mut windows: Vec<RawWindowRecord> = registry.values().cloned().collect();
windows.sort_by_key(|w| w.id);
windows
}
pub fn get_window(&self, window_id: u64) -> Option<RawWindowRecord> {
let registry = self.window_registry.lock().unwrap();
registry.get(&window_id).cloned()
}
pub fn render_frame(&self, window_id: u64, _stream_id: u8, data: &[u8]) -> Result<(), String> {
{
let registry = self.window_registry.lock().unwrap();
match registry.get(&window_id) {
Some(record) => {
if !record.visible || record.state == WindowState::Hidden {
return Ok(());
}
}
None => return Err(format!("Window {} not found", window_id)),
}
}
self.dispatch_data(data);
Ok(())
}
pub fn ping(&self) -> Result<Duration, String> {
if !self.fd_manager.is_connected() {
return Err("No connection".to_string());
}
let start = std::time::Instant::now();
match self.fd_manager.send_command(RawWindowCommand::Ping, 0, &[]) {
Ok((RawWindowStatus::Pong, _)) => Ok(start.elapsed()),
Ok((status, _)) => Err(format!("Ping hatası: {:?}", status)),
Err(e) => Err(format!("Ping iletişim hatası: {}", e)),
}
}
}
impl UClientEngine for RawWindowClient {
fn start_engine(&mut self) -> Result<(), Box<dyn std::error::Error>> {
println!("🔌 RawWindowClient: Opening control channel...");
if let Err(e) = self.fd_manager.connect() {
eprintln!("⚠️ Server connection failed, running in local mode: {}", e);
}
self.active = true;
println!("🟢 WASMA RawWindowClient: Engine Started");
println!(
"🎨 Renderer: {} (delegated to WindowClient)",
self.config.resource_limits.renderer
);
println!("📡 Mode: Window Management Engine");
if self.fd_manager.is_connected() {
let fd = self.fd_manager.ctrl_fd.unwrap();
let mut event_buf = vec![0u8; WASMA_HDR_SIZE + 256];
loop {
match posix::posix_poll_readable(fd, 50) {
Ok(false) => {
if !self.active {
break;
}
continue;
}
Ok(true) => {}
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => {
eprintln!("⚠️ Poll error: {}", e);
break;
}
}
match posix::posix_read(fd, &mut event_buf[..WASMA_HDR_SIZE]) {
Ok(0) => {
println!("📭 Server connection closed.");
break;
}
Ok(n) if n < WASMA_HDR_SIZE => {
eprintln!("⚠️ Short header: {} bytes", n);
continue;
}
Ok(_) => {
self.handle_server_event(&event_buf[..WASMA_HDR_SIZE]);
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => continue,
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => {
eprintln!("⚠️ Read error: {}", e);
break;
}
}
}
}
self.active = false;
Ok(())
}
fn dispatch_data(&self, data: &[u8]) {
if let Some(focused_id) = self.get_focused_window() {
let _ = self.render_frame(focused_id, 0, 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;
let ids: Vec<u64> = {
let registry = self.window_registry.lock().unwrap();
registry.keys().cloned().collect()
};
for id in ids {
let _ = self.destroy_window(id);
}
println!("🛑 RawWindowClient shutdown");
Ok(())
}
fn is_active(&self) -> bool {
self.active
}
}
impl RawWindowClient {
fn handle_server_event(&self, hdr: &[u8]) {
if hdr.len() < WASMA_HDR_SIZE {
return;
}
if hdr[0..4] != WASMA_RSP_MAGIC {
return;
}
let status =
RawWindowStatus::from_u32(u32::from_le_bytes(hdr[4..8].try_into().unwrap_or([0; 4])));
let window_id = u32::from_le_bytes(hdr[8..12].try_into().unwrap_or([0; 4]));
println!(
"📨 Server event: window_id={} status={:?}",
window_id, status
);
}
}
pub struct RawWindowClientBuilder {
config: Option<WasmaConfig>,
source: Option<RawAppSource>,
window_client: Option<Arc<Mutex<WindowClient>>>,
}
impl RawWindowClientBuilder {
pub fn new() -> Self {
Self {
config: None,
source: None,
window_client: None,
}
}
pub fn with_config(mut self, config: WasmaConfig) -> Self {
self.config = Some(config);
self
}
pub fn with_source(mut self, source: RawAppSource) -> Self {
self.source = Some(source);
self
}
pub fn with_window_client(mut self, wc: Arc<Mutex<WindowClient>>) -> Self {
self.window_client = Some(wc);
self
}
pub fn build(self) -> Result<RawWindowClient, String> {
let config = self.config.ok_or("Config required")?;
let mut client = RawWindowClient::new(config);
if let Some(source) = self.source {
client.fd_manager = RawWindowFd::new(source);
}
if let Some(wc) = self.window_client {
client.attach_window_client(wc);
}
Ok(client)
}
}
impl Default for RawWindowClientBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::ConfigParser;
fn make_config() -> WasmaConfig {
let parser = ConfigParser::new(None);
let content = parser.generate_default_config();
parser.parse(&content).unwrap()
}
#[test]
fn test_create_and_destroy_window() {
let config = make_config();
let client = RawWindowClient::new(config);
let geo = WindowGeometry {
x: 100,
y: 200,
width: 1280,
height: 720,
};
let id = client
.create_window("Test Penceresi", "test.app", geo, WindowType::Normal)
.unwrap();
assert!(client.get_window(id).is_some());
let record = client.get_window(id).unwrap();
assert_eq!(record.geometry.width, 1280);
assert_eq!(record.geometry.height, 720);
assert_eq!(record.title, "Test Penceresi");
client.destroy_window(id).unwrap();
assert!(client.get_window(id).is_none());
println!("✅ Window create and destroy working");
}
#[test]
fn test_set_and_get_geometry() {
let config = make_config();
let client = RawWindowClient::new(config);
let id = client
.create_window(
"Geo Test",
"geo.app",
WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
},
WindowType::Normal,
)
.unwrap();
let new_geo = WindowGeometry {
x: 50,
y: 75,
width: 1920,
height: 1080,
};
client.set_geometry(id, new_geo).unwrap();
let fetched = client.get_geometry(id).unwrap();
assert_eq!(fetched.width, 1920);
assert_eq!(fetched.height, 1080);
assert_eq!(fetched.x, 50);
assert_eq!(fetched.y, 75);
println!("✅ Geometry management working");
}
#[test]
fn test_window_state_transitions() {
let config = make_config();
let client = RawWindowClient::new(config);
let id = client
.create_window(
"State Test",
"state.app",
WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
},
WindowType::Normal,
)
.unwrap();
for state in [
WindowState::Minimized,
WindowState::Maximized,
WindowState::Fullscreen,
WindowState::Hidden,
WindowState::Normal,
] {
client.set_state(id, state.clone()).unwrap();
assert_eq!(client.get_state(id).unwrap(), state);
}
println!("✅ Window state transitions working");
}
#[test]
fn test_focus_management() {
let config = make_config();
let client = RawWindowClient::new(config);
let geo = WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
};
let id1 = client
.create_window("Win1", "app1", geo, WindowType::Normal)
.unwrap();
let id2 = client
.create_window("Win2", "app2", geo, WindowType::Normal)
.unwrap();
client.set_focus(id1).unwrap();
assert_eq!(client.get_focused_window(), Some(id1));
assert!(!client.get_window(id2).unwrap().focused);
client.set_focus(id2).unwrap();
assert_eq!(client.get_focused_window(), Some(id2));
assert!(!client.get_window(id1).unwrap().focused);
println!("✅ Focus management working");
}
#[test]
fn test_parent_child_relationship() {
let config = make_config();
let client = RawWindowClient::new(config);
let geo = WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
};
let parent_id = client
.create_window("Parent", "parent.app", geo, WindowType::Normal)
.unwrap();
let child_id = client
.create_window("Child", "child.app", geo, WindowType::Dialog)
.unwrap();
client.set_parent(child_id, parent_id).unwrap();
let parent = client.get_window(parent_id).unwrap();
assert!(parent.children.contains(&child_id));
let child = client.get_window(child_id).unwrap();
assert_eq!(child.parent_id, Some(parent_id));
client.destroy_window(parent_id).unwrap();
assert!(client.get_window(parent_id).is_none());
assert!(client.get_window(child_id).is_none());
println!("✅ Parent-child relationship working");
}
#[test]
fn test_geometry_codec() {
let geo = WindowGeometry {
x: -100,
y: 200,
width: 1920,
height: 1080,
};
let encoded = geometry_codec::encode(&geo);
let decoded = geometry_codec::decode(&encoded).unwrap();
assert_eq!(decoded.x, geo.x);
assert_eq!(decoded.y, geo.y);
assert_eq!(decoded.width, geo.width);
assert_eq!(decoded.height, geo.height);
println!("✅ Geometry codec working");
}
#[test]
fn test_state_codec() {
for state in [
WindowState::Normal,
WindowState::Minimized,
WindowState::Maximized,
WindowState::Fullscreen,
WindowState::Hidden,
] {
let encoded = state_codec::encode(&state);
let decoded = state_codec::decode(encoded);
assert_eq!(decoded, state);
}
println!("✅ State codec working");
}
#[test]
fn test_list_windows() {
let config = make_config();
let client = RawWindowClient::new(config);
let geo = WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
};
let _id1 = client
.create_window("W1", "a1", geo, WindowType::Normal)
.unwrap();
let _id2 = client
.create_window("W2", "a2", geo, WindowType::Normal)
.unwrap();
let _id3 = client
.create_window("W3", "a3", geo, WindowType::Utility)
.unwrap();
let windows = client.list_windows();
assert_eq!(windows.len(), 3);
assert!(windows[0].id < windows[1].id);
assert!(windows[1].id < windows[2].id);
println!("✅ Window listing working: {} windows", windows.len());
}
#[test]
fn test_uclient_engine_trait_object() {
let config = make_config();
let client: Box<dyn UClientEngine> = Box::new(RawWindowClient::new(config));
assert!(!client.is_active());
println!("✅ UClientEngine trait object (RawWindowClient) working");
}
#[test]
fn test_visibility() {
let config = make_config();
let client = RawWindowClient::new(config);
let geo = WindowGeometry {
x: 0,
y: 0,
width: 800,
height: 600,
};
let id = client
.create_window("Vis Test", "vis.app", geo, WindowType::Normal)
.unwrap();
assert!(client.get_window(id).unwrap().visible);
client.set_visible(id, false).unwrap();
assert!(!client.get_window(id).unwrap().visible);
client.set_visible(id, true).unwrap();
assert!(client.get_window(id).unwrap().visible);
println!("✅ Visibility management working");
}
}